30.Stream流

5.Stream流

5.1体验Stream流【理解】

  • 案例需求

    按照下面的要求完成集合的创建和遍历

    • 创建一个集合,存储多个字符串元素

    • 把集合中所有以"张"开头的元素存储到一个新的集合

    • 把"张"开头的集合中的长度为3的元素存储到一个新的集合

    • 遍历上一步得到的集合

  • 原始方式示例代码

package com.itheima.streamdemo;

import java.util.ArrayList;
import java.util.List;
import java.util.SortedMap;

/*
* 创建一个集合,存储多个字符串元素
"张三丰","张无忌","张翠山","王二麻子","张良","谢广坤"
把集合中所有以"张"开头的元素存储到一个新的集合

把"张"开头的集合中的长度为3的元素存储到一个新的集合

遍历上一步得到的集合
*
* */
public class MyStream1 {
    public static void main(String[] args) {
        ArrayList<String> list1=new ArrayList<>(List.of("张三丰","张无忌","张翠山","王二麻子","张良","谢广坤"));
        ArrayList<String> list2=new ArrayList<>();
        //遍历list1把张开头的元素添加到list2中。
        for (String s : list1) {
            if (s.startsWith("张")) {
                list2.add(s);
            }
        }
        //遍历list2集合,把其中长度为3的元素,再添加到list3中,
        ArrayList<String> list3=new ArrayList<>();
        for (String s : list2) {
            if (s.length() == 3) {
                list3.add(s);
            }
        }
        for (String s : list3) {
            System.out.println(s);
        }
        //Stream流
        list1.stream().filter(s -> s.startsWith("张"))
                .filter(s -> s.length()==3)
                .forEach(s -> System.out.println(s));
    }



}

Stream流的好处

  • 直接阅读代码的字面意思即可完美展示无关逻辑方式的语义:获取流、过滤姓张、过滤长度为3、逐一打印

  • Stream流把真正的函数式编程风格引入到Java中

  • 代码简洁

5.2Stream流的常见生成方式【应用】

  • Stream流的思想

 

 

 

  • Stream流的三类方法

    • 获取Stream流

      • 创建一条流水线,并把数据放到流水线上准备进行操作

    • 中间方法

      • 流水线上的操作

      • 一次操作完毕之后,还可以继续进行其他操作

    • 终结方法

      • 一个Stream流只能有一个终结方法

      • 是流水线上的最后一个操作

  • 生成Stream流的方式

    • Collection体系集合   单列集合

        使用默认方法stream()生成流, default Stream<E> stream()

    • Map体系集合   双列集合

        把Map转成Set集合,间接的生成流、  可以先通过keySet或者entrySet获取一个Set集合,在获取Stream流

    • 数组

        通过Arrays中的静态方法stream生成流

    • 同种数据类型的多个数据

        通过Stream接口的静态方法of(T... values)生成流     

    • 1,2,3,4,5.......
    • "aaa","bbb","ccc"......
    • 使用Stream.of(T...values)生成流
package com.itheima.streamdemo;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.stream.Stream;
/*
* Stream流的获取
* 单列集合:集合对象.Stream();
* 双列集合:不能直接获取,需要间接获取
*         集合对象.keySet().stream();
*         集合对象.entrySet.stream();
*数组:Arrays.stream(数组名);
* 同种数据类型的多个数据:Stream.of(数据1,数据2,数据3.。。。。)
*
* */
public class MyStream2 {
    public static void main(String[] args) {
        //单列集合
       //method1();

        //双列集合
        //method2();

        //数组
       //method3();

        //同种数据类型的多个数据
        method4();
    }

    public static void method4() {
        Stream.of(1,2,3,4,5,6,7,8).forEach(s-> System.out.println(s));
    }

    public static void method3() {
        int []arr={1,2,3,4,5};
        Arrays.stream(arr).forEach(s-> System.out.println(s));
    }

    public static void method2() {
        HashMap<String,Integer> hm=new HashMap<>();
        hm.put("zhangsan",23);
        hm.put("lisi",24);
        hm.put("wangwu",25);
        hm.put("zhaoliu",26);
        hm.put("qianqi",27);
        //双列集合不能直接获取Streatm流
        //KeySet
        //先获取到所有的键
        //再把这个Set集合中所有的键放到Stream流中
        hm.keySet().stream().forEach(s -> System.out.println(s));
        //entrySet
        //先获取到所有的键值对对象
        //再把这个Set集合中所有的键值对对象放到Stream流中
        hm.entrySet().stream().forEach(s-> System.out.println(s));
    }

    public static void method1() {
        ArrayList<String> list=new ArrayList<>();
        list.add("aaa");
        list.add("bbb");
        list.add("ccc");
//        Stream<String> stream = list.stream();
//        stream.forEach(s -> System.out.println(s));
        list.stream().forEach(s -> System.out.println(s));
    }

}

 

5.3Stream流中间操作方法【应用】

  • 概念

    中间操作的意思是,执行完此方法之后,Stream流依然可以继续执行其他操作

  • 常见方法

    方法名说明
    Stream<T> filter(Predicate predicate) 用于对流中的数据进行过滤
    Stream<T> limit(long maxSize) 返回此流中的元素组成的流,截取前指定参数个数的数据
    Stream<T> skip(long n) 跳过指定参数个数的数据,返回由该流的剩余元素组成的流
    static <T> Stream<T> concat(Stream a, Stream b) 合并a和b两个流为一个流
    Stream<T> distinct() 返回由该流的不同元素(根据Object.equals(Object) )组成的流
  • filter代码演示

Stream<T> filter(Predicate predicate) 用于对流中的数据进行过滤

Predicate接口中的方法

boolean test(T t):对给定的参数进行判断,返回一个布尔值

package com.itheima.streamdemo;

import java.util.ArrayList;
import java.util.List;
import java.util.function.Predicate;

public class MyStream3 {
    public static void main(String[] args) {
        ArrayList<String> list = new ArrayList<>(List.of("张三丰", "张无忌", "张翠山", "王二麻子", "张良", "谢广坤"));
        //filter方法获取流中的每一个数据
        //而test方法中的s,就依次表示流中的每一个数据
        //我们只要在test方法中对s进行判断就可以了,
        //如果判断的结果为true,则当前的数据留下
        //如果判断的结果为false,则当前的数据就不要
//        list.stream().filter(
//                new Predicate<String>() {
//                    @Override
//                    public boolean test(String s) {
//                        boolean result = s.startsWith("张");
//                        return result;
//                    }
//                }
//        ).forEach(s -> System.out.println(s));
        //因为Predicate接口中只有一个抽象方法test
        //所以我们能使用lambda表达式来简化
//        list.stream().filter(
//                (String s) -> {
//                    boolean result = s.startsWith("张");
//                    return result;
//                }
//        ).forEach(s -> System.out.println(s));

        list.stream().filter(s -> s.startsWith("张")).forEach(s -> System.out.println(s));
    }
}

limit&skip&concat&distinct代码演示  

package com.itheima.streamdemo;

import javax.swing.*;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Stream;

public class MyStream4 {
    public static void main(String[] args) {
        ArrayList<String> list = new ArrayList<>(List.of("张三丰", "张无忌", "张翠山", "王二麻子", "张良", "谢广坤"));
        //Stream<T> limit(long maxSize)	返回此流中的元素组成的流,截取前指定参数个数的数据
        //list.stream().limit(2).forEach(s -> System.out.println(s));
        //Stream<T> skip(long n)	跳过指定参数个数的数据,返回由该流的剩余元素组成的流
        //list.stream().skip(2).forEach(s -> System.out.println(s));
        //static <T> Stream<T> concat(Stream a, Stream b)	合并a和b两个流为一个流
        ArrayList<String> list2 = new ArrayList<>(List.of("张三丰", "张无忌", "张翠山", "王二麻子", "张良", "谢广坤","谢广坤","谢广坤","谢广坤","谢广坤"));
//        Stream<String> stream1 = list.stream();
//        Stream<String> stream2 = list2.stream();
//        Stream<String> stream3 = Stream.concat(stream1, stream2);
//        stream3.forEach(s -> System.out.println(s));
        //Stream.concat(list.stream(),list2.stream()).forEach(s -> System.out.println(s));
        //Stream<T> distinct()	返回由该流的不同元素(根据Object.equals(Object) )组成的流,依赖(hashCode和equals方法)
        list.stream().distinct().forEach(s -> System.out.println(s));

    }
}

5.4Stream流终结操作方法【应用】

  • 概念

    终结操作的意思是,执行完此方法之后,Stream流将不能再执行其他操作

  • 常见方法

    方法名说明
    void forEach(Consumer action)

    对此流的每个元素执行操作

    long count() 返回此流中的元素数
  • 代码演示

void forEach(Consumer action)

对此流的每个元素执行操作

Consumer接口中的方法              void accept(T t):对给定的参数执行此操作  

package com.itheima.streamdemo;

import java.util.ArrayList;
import java.util.List;
import java.util.function.Consumer;

public class MyStream5 {
    public static void main(String[] args) {
        ArrayList<String> list = new ArrayList<>(List.of("张三丰", "张无忌", "张翠山", "王二麻子", "张良", "谢广坤"));
        //void forEach(Consumer action)对此流的每个元素执行操作
        //Consumer接口中的方法         void accept(T t):对给定的参数执行此操作  
        //method1(list);
        // long count()返回此流中的元素数
        long count = list.stream().count();
        System.out.println(count);
    }

    public static void method1(ArrayList<String> list) {
        //在forEach方法的底层 ,会循环获取到流中的每一个数据
        //并循环调用accept方法,并把每一个数据传递给accept方法
        //s就依次表示了流中的每一个数据
        //所以,我们只要在accept方法中,写上处理的业务逻辑就可以了
        list.stream().forEach(
                new Consumer<String>() {
                    @Override
                    public void accept(String s) {
                        System.out.println(s);
                    }
                }
        );
        //lambda表达式的简化格式
        //是因为Consumer接口中,只有一个accept方法
        list.stream().forEach(s -> System.out.println(s));
    }
}

 

需求:过滤元素并遍历集合

定义一个集合,并添加一些整数1,2,3,4,5,6,7,8,9,10

将集合中的奇数删除,只保留偶数

遍历集合得到2,4,6,8,10

package com.itheima.streamdemo;

import java.util.ArrayList;
import java.util.List;

/*
*需求:过滤元素并遍历集合

定义一个集合,并添加一些整数1,2,3,4,5,6,7,8,9,10

将集合中的奇数删除,只保留偶数

遍历集合得到2,4,6,8,10
*
*
* */
public class MyStream6 {
    public static void main(String[] args) {
        ArrayList<Integer> list = new ArrayList<>();
        for (int i = 1; i <= 10; i++) {
            list.add(i);
        }
        list.stream().filter(number -> number%2==0).forEach(number-> System.out.println(number));
        System.out.println("==============");
        for (Integer integer : list) {
            System.out.println(integer);
        }
    }
}

  结论:在Stream流中无法直接修改集合,数组等数据源中的数据

5.5Stream流的收集操作【应用】

使用Stream流的方式操作完毕之后,我想把流中的数据保存起来,该怎么办

  • 概念

    对数据使用Stream流的方式操作完毕后,可以把流中的数据收集到集合中

  • 常用方法

    方法名说明
    R collect(Collector collector) 把结果收集到集合中
  • 工具类Collectors提供了具体的收集方式

    方法名说明
    public static <T> Collector toList() 把元素收集到List集合中
    public static <T> Collector toSet() 把元素收集到Set集合中
    public static Collector toMap(Function keyMapper,Function valueMapper) 把元素收集到Map集合中
  • 代码演示

  • 收集到list和set单列集合中
package com.itheima.streamdemo;

import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;

/*
*需求:过滤元素并遍历集合

定义一个集合,并添加一些整数1,2,3,4,5,6,7,8,9,10

将集合中的奇数删除,只保留偶数

遍历集合得到2,4,6,8,10
*
*
* */
public class MyStream7 {
    public static void main(String[] args) {
        ArrayList<Integer> list = new ArrayList<>();
        for (int i = 1; i <= 10; i++) {
            list.add(i);
        }
        list.add(10);
        list.add(10);
        list.add(10);
        list.add(10);
        list.add(10);
        //filter负责过滤数据的
        //collect负责收集数据,
            //获取流中剩余数据,但是他不负责创建容器,也不负责把数据添加到容器中
        //Collectors.toList():在底层创建一个List集合,并把所有数据添加到List集合中
        List<Integer> list1 = list.stream().filter(number -> number % 2 == 0)
                .collect(Collectors.toList());
        System.out.println(list1);


        Set<Integer> set = list.stream().filter(number -> number % 2 == 0)
                .collect(Collectors.toSet());
        System.out.println(set);
    }
}

  收集到双列集合中

练习:

创建一个ArrayList集合,并添加以下字符串,字符串中前面是姓名,后面是年龄

”zhangsan“,23

”lisi“,24

”wangwu“,25  

保留年龄大于等于24岁的人,并将结果收集到Map集合中,姓名为键,年龄为值

  

public static Collector toMap(Function keyMap,Function valueMapper):把元素收集到Map集合中  

package com.itheima.streamdemo;

import java.util.ArrayList;
import java.util.Map;
import java.util.stream.Collectors;

/*
* 创建一个ArrayList集合,并添加以下字符串,字符串中前面是姓名,后面是年龄

”zhangsan“,23
”lisi“,24
”wangwu“,25  
保留年龄大于等于24岁的人,并将结果收集到Map集合中,姓名为键,年龄为值
*
* */
public class MyStream8 {
    public static void main(String[] args) {
        ArrayList<String> list = new ArrayList<>();
        list.add("zhangsan,23");
        list.add("lisi,24");
        list.add("wangwu,25");

        Map<String, Integer> map = list.stream().filter(
                s -> {
                    String[] split = s.split(",");
                    int age = Integer.parseInt(split[1]);
                    return age >= 24;
                }
                //collection方法只能获取到流中剩余的每一个数据
                //在底层不能创建容器,也不能把数据添加到容器当中

                //Collectors.toMap 创建一个集合,并将数据添加到集合当中

                //s依次表示流中的每一个数据

                //第一个lambda表达式就是如何获取到map中的键
                //第二个lambda表达式就是如何获取到map中的值
        ).collect(Collectors.toMap(
                s -> s.split(",")[0],
                s -> Integer.parseInt(s.split(",")[1])));
        System.out.println(map);
    }
}

5.6Stream流综合练习【应用】

  • 案例需求

    现在有两个ArrayList集合,分别存储6名男演员名称和6名女演员名称,要求完成如下的操作

    • 男演员只要名字为3个字的前两人

    • 女演员只要姓杨的,并且不要第一个

    • 把过滤后的男演员姓名和女演员姓名合并到一起

    • 把上一步操作后的元素作为构造方法的参数创建演员对象,遍历数据

    演员类Actor已经提供,里面有一个成员变量,一个带参构造方法,以及成员变量对应的get/set方法

  • 代码实现

    演员类

package com.itheima.streamdemo;

public class Actor {
    private String name;

    public Actor() {
    }

    public Actor(String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    @Override
    public String toString() {
        return "Actor{" +
                "name='" + name + '\'' +
                '}';
    }
}

测试类  

package com.itheima.streamdemo;

import javax.xml.namespace.QName;
import java.util.ArrayList;
import java.util.stream.Stream;

/**
 * 现在有两个ArrayList集合,分别存储6名男演员名称和6名女演员名称,要求完成如下的操作
 * 1.男演员只要名字为3个字的前两人
 * 2.女演员只要姓杨的,并且不要第一个
 * 3.把过滤后的男演员姓名和女演员姓名合并到一起
 * 4.把上一步操作后的元素作为构造方法的参数创建演员对象,遍历数据
 * 演员类Actor,里面有一个成员变量,一个带参构造方法,以及成员变量对应的get/set方法
 */
public class MyStream9 {
    public static void main(String[] args) {
        ArrayList<String> manList = new ArrayList<>();
        manList.add("张国立");
        manList.add("张晋");
        manList.add("刘烨");
        manList.add("郑伊健");
        manList.add("徐峥");
        manList.add("王宝强");

        ArrayList<String>  womanList = new ArrayList<>();
        womanList.add("郑爽");
        womanList.add("杨紫");
        womanList.add("关晓彤");
        womanList.add("张天爱");
        womanList.add("杨幂");
        womanList.add("赵丽颖");
        //男演员只要名字为3个字的前两个人
        Stream<String> stream1=manList.stream().filter(name -> name.length() == 3).limit(2);
        //女演员只要姓杨的,并且不要第一个
        Stream<String> stream2=womanList.stream().filter(name-> name.startsWith("杨")).skip(1);

        Stream.concat(stream1,stream2).forEach(name->{
            Actor actor = new Actor(name);
            System.out.println(actor);
        });
    }

}

  

  

 

 

 

 

 

 

  

 

posted @ 2020-11-17 22:36  星梦泪痕  阅读(81)  评论(0编辑  收藏  举报