在具体的介绍之前,先总结一波常用的写法,有基础的可以直接拿来用,没有基础的可以先跳过,看完下面的基础再回来看

java 流式编程原理 java流式编程的优缺点_List

java 流式编程原理 java流式编程的优缺点_List_02

List<User> userList = new ArrayList<>();
    userList.addAll(Arrays.asList(
        new User(1, 11, "张三"),
        new User(1, 11, "张三"),
        new User(2, 22, "李四"),
        new User(1, 33, "王五"),
        new User(2, 44, "赵六"),
        new User(2, 44, "赵六")));
    //----------------------------------------------中间操作----------------------------------------------
    //【filter】从列表中筛选出性别为女的数据
    List<User> filterUsage = userList.stream().filter(s->s.getSex() == 2).collect(Collectors.toList());
    //结果:[User(sex=2, age=22, name=李四), User(sex=2, age=44, name=赵六), User(sex=2, age=44, name=赵六)]
    System.out.println(filterUsage);
    //【distinct】从列表中去重
    List<User> distinctUsage = userList.stream().distinct().collect(Collectors.toList());
    //结果:[User(sex=1, age=11, name=张三), User(sex=2, age=22, name=李四), User(sex=1, age=33, name=王五), User(sex=2, age=44, name=赵六)]
    System.out.println(distinctUsage);
    //【sorted】按照年龄字段从大到小重新排序 (从小到大就是s1.getAge()-s2.getAge())
    List<User> sortedUsage = userList.stream().sorted((s1,s2)->s2.getAge()-s1.getAge()).collect(Collectors.toList());
    //结果:[User(sex=2, age=44, name=赵六), User(sex=2, age=44, name=赵六), User(sex=1, age=33, name=王五), User(sex=2, age=22, name=李四), User(sex=1, age=11, name=张三), User(sex=1, age=11, name=张三)]
    System.out.println(sortedUsage);
    //【limit】获取前两条数据
    List<User> limitUsage = userList.stream().limit(2).collect(Collectors.toList());
    //结果:[User(sex=1, age=11, name=张三), User(sex=1, age=11, name=张三)]
    System.out.println(limitUsage);
    //【skip】跳过前两条,之后获取前三条数据
    List<User> skipUsage = userList.stream().skip(2).limit(3).collect(Collectors.toList());
    //结果:[User(sex=2, age=22, name=李四), User(sex=1, age=33, name=王五), User(sex=2, age=44, name=赵六)]
    System.out.println(skipUsage);
    //【map】获取所有人的姓名
    List<String> mapUsage = userList.stream().map(User::getName).collect(Collectors.toList());
    //结果:[张三, 张三, 李四, 王五, 赵六, 赵六]
    System.out.println(mapUsage);
    //【flatMap】

    //【Collectors工具类一些常用方法】
    //【groupingBy】分组
    // 将集合中的数据按照姓名分组
    Map<String, List<User>> groupingByUsage = userList.stream().collect(Collectors.groupingBy(s -> s.getName()));
    //结果:{李四=[User(sex=2, age=22, name=李四)], 张三=[User(sex=1, age=11, name=张三), User(sex=1, age=11, name=张三)],
    //      王五=[User(sex=1, age=33, name=王五)], 赵六=[User(sex=2, age=44, name=赵六), User(sex=2, age=44, name=赵六)]}
    System.out.println(groupingByUsage);
    // 将集合中的数据按照姓名+性别分组
    Map<String, List<User>> groupingByUsage2 = userList.stream().collect(Collectors.groupingBy(s -> s.getName() + "#" + s.getSex()));
    //结果:{张三#1=[User(sex=1, age=11, name=张三), User(sex=1, age=11, name=张三)], 李四#2=[User(sex=2, age=22, name=李四)],
    //      赵六#2=[User(sex=2, age=44, name=赵六), User(sex=2, age=44, name=赵六)], 王五#1=[User(sex=1, age=33, name=王五)]}
    System.out.println(groupingByUsage2);
    //【maxBy】获取集合中年龄最大的对象信息
    User maxByUsage = userList.stream().collect(Collectors.maxBy((s1, s2) -> s1.getAge() - s2.getAge())).get();
    //结果:User(sex=2, age=44, name=赵六)
    System.out.println(maxByUsage);
    //【minBy】获取集合中年龄最小的对象信息
    User minByUsage = userList.stream().collect(Collectors.minBy((s1, s2) -> s1.getAge() - s2.getAge())).get();
    //结果:User(sex=1, age=11, name=张三)
    System.out.println(minByUsage);
    //【joining】拼接集合中所有的用户名称---直接拼接
    String joiningUsage = userList.stream().map(User::getName).collect(Collectors.joining());
    //结果:张三张三李四王五赵六赵六
    System.out.println(joiningUsage);
    //拼接中间加上逗号
    String joiningUsage2 = userList.stream().map(User::getName).collect(Collectors.joining(","));
    //结果:张三,张三,李四,王五,赵六,赵六
    System.out.println(joiningUsage2);
    //拼接中间加上逗号,两边加上前后缀
    String joiningUsage3 = userList.stream().map(User::getName).collect(Collectors.joining(",","[","]"));
    //结果:[张三,张三,李四,王五,赵六,赵六]
    System.out.println(joiningUsage3);
    //【counting】获取集合中对象的数量
    Long countingUsage = userList.stream().collect(Collectors.counting());
    //结果:6
    System.out.println(countingUsage);
    //【summingInt】获取集合中所有对象年龄的和
    int summingIntUsage = userList.stream().collect(Collectors.summingInt(User::getAge));
    //结果:165
    System.out.println(summingIntUsage);
    //【averagingInt】获取集合中所有对象年龄的平均值
    Double averagingIntUsage = userList.stream().collect(Collectors.averagingInt(User::getAge));
    //结果:27.5
    System.out.println(averagingIntUsage);
    //【summarizingInt】获取集合中所有对象的数量/和/最大值/最小值/平均值等信息
    IntSummaryStatistics summarizingIntUsage = userList.stream().collect(Collectors.summarizingInt(User::getAge));
    //结果:IntSummaryStatistics{count=6, sum=165, min=11, average=27.500000, max=44}
    System.out.println(summarizingIntUsage);

    //----------------------------------------------最终操作----------------------------------------------

    //【collect】
    //这里不做演示,上面的所有例子中都有用到
    //【reduce】将集合中的所有性别字段的值按照相加的规则求乘积
    Integer reduceUsage = userList.stream().map(User::getSex).reduce((s1, s2) -> s1 * s2).get();
    //结果:8
    System.out.println(reduceUsage);
    //【count】求集合中对象的数量
    long countUsage = userList.stream().count();
    //结果:6
    System.out.println(countUsage);
    //【forEach】遍历出所有的对象的名称
    Consumer<String> action = System.out::println;
    //结果:张三 张三 李四 王五 赵六 赵六
    userList.stream().map(User::getName).forEach(action);
    //【max&min】获取集合中所有对象中年龄的最大值和最小值
    Integer maxUsage = userList.stream().map(User::getAge).max(Integer::compareTo).get();
    //结果:44
    System.out.println(maxUsage);
    Integer minUsage = userList.stream().map(User::getAge).min(Integer::compareTo).get();
    //结果:11
    System.out.println(minUsage);
    //【Matching -> allMatch、anyMatch、noneMatch】
    //allMatch:只有当流中所有的元素,都匹配指定的规则,才会返回true
    boolean allMatchUsage = userList.stream().map(User::getAge).allMatch(e -> e >= 44);
    //结果:false
    System.out.println(allMatchUsage);
    //anyMatch:只要流中有任意的数据,满足指定的规则,都会返回true
    boolean anyMatchUsage = userList.stream().map(User::getAge).anyMatch(e -> e <= 11);
    //结果:true
    System.out.println(anyMatchUsage);
    //noneMatch:只有当流中所有的元素,都不满足指定的规则,才会返回true
    boolean noneMatchUsage = userList.stream().map(User::getAge).noneMatch(e -> e < 11);
    //结果:true
    System.out.println(noneMatchUsage);
    //【find--> findFirst、findAny】【parallelStream并行流、stream串行流】
    //findFirst:从流中获取开头第一个元素
    User user = userList.stream().findFirst().get();
    //结果:User(sex=1, age=11, name=张三)
    System.out.println(user);
    User user2 = userList.parallelStream().findFirst().get();
    //结果:User(sex=1, age=11, name=张三)
    System.out.println(user2);
    //findAny:单线程是获取第一个元素,多线程可能不一样
    User user3 = userList.stream().findAny().get();
    //结果:User(sex=1, age=11, name=张三)
    System.out.println(user3);
    User user4 = userList.parallelStream().findAny().get();
    //结果:User(sex=1, age=33, name=王五)
    System.out.println(user4);
    //【IntStream+summaryStatistics】获取int数组中的最大值
    //1.准备一个int数组作为数据源
    int[] array = new int[]{0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
    //2.读取数据到流中,获取IntStream对象
    IntStream intStream = Arrays.stream(array);
    //两种方法:(不能一起用,因为是中间操作)
    //1. 直接通过IntStream来获取
    //System.out.println(intStream.max().getAsInt());
    //2. 通过IntSummaryStatistics,里面包括最大/最小/平均/数量等方法
    IntSummaryStatistics intSummaryStatistics = intStream.summaryStatistics();
    //结果:9
    System.out.println(intSummaryStatistics.getMax());

    //----------------------------------------------其它操作----------------------------------------------
    //【list转数组1】
    Integer[] ints = userList.stream().map(User::getAge).toArray(Integer[]::new);
    //【list转数组2】
    List<String> list = new ArrayList();
    list.add("1");
    list.add("2");
    list.add("3");
    String[] strings = list.toArray(new String[list.size()]);
    //【数组转list】
    String[] arrays = {"1", "2", "3"};
    List<String> listStrings = Stream.of(arrays).collect(Collectors.toList());
    //结果:[1, 2, 3]
    System.out.println(listStrings);
    //【修改集合中的对象属性的值】
    //原值:[User(sex=1, age=11, name=张三), User(sex=1, age=11, name=张三), User(sex=2, age=22, name=李四), 
    //      User(sex=1, age=33, name=王五), User(sex=2, age=44, name=赵六), User(sex=2, age=44, name=赵六)]
    System.out.println(userList);
    userList.forEach(s->{
        s.setAge(100);
        s.setSex(100);
    });
    //新值:[User(sex=100, age=100, name=张三), User(sex=100, age=100, name=张三),User(sex=100, age=100, name=李四), 
    // User(sex=100, age=100, name=王五), User(sex=100, age=100, name=赵六), User(sex=100, age=100, name=赵六)]
    System.out.println(userList);

View Code

、集合流的简介

1. 集合的流式编程的简介

Stream是JDK1.8之后出现的新特性,也是JDK1.8新特性中最值得学习的两种新特性之一(另一个是lambda表达式)Stream是对集合操作的增强,流不是集合的元素,不是一种数据结构,不负责数据的存储的。流更像是一个迭代器,可以单向的遍历一个集合中的每一个元素,并且不可循环。

2. 为什么要使用集合的流式编程

有些时候,对集合中的元素进行操作的时候,需要使用到其他操作的结果。在这个过程中,集合的流式编程可以大幅度的简化代码的数量。将数据源中的数据,读取到一个流中,可以对这个流中的数据进行操作(删除、过滤、映射...)。每次的操作结果也是一个流对象,可以对这个流再进行其它的操作。

3. 使用流式编程的步骤

通常情况下,对集合中的数据使用流式编程,需要经过以下三步:

 (1)获取数据源,将数据源中的数据读取到流中
 (2)对流中的数据进行各种各样的处理
 (3)对流中的数据进行整合处理

在上述三个过程:

 (1)过程2中,有若干方法,可以对流中的数据进行各种各样的操作,并且返回流对象本身,这样的操作,被称为中间操作
 (2)过程3中,有若干方法,可以对流中的数据进行各种处理,并关闭流,这样的操作,被称为最终操作

在中间操作和最终操作中,基本上所有的方法参数都是函数式接口,可以使用lambda表达式来实现。使用集合的流式编程,来简化代码量。

二、数据源的获取

1. 数据源的简介

数据源,顾名思义,就是流中的数据的来源,是集合的流式编程的第一步,将数据源中的数据读取到流中,进行处理。注意:将数据读取到流中进行处理的时候,与数据源中的数据没有关系。也就是说,中间操作对流中的数据进行处理、过滤、映射、排序...是不会影响到数据源中的数据的。

2. 数据源的获取

这个过程,其实是将一个容器中的数据,读取到一个流中,因此无论什么容器作为数据源,读取到流中的方法返回值一定是一个Stream。

public static void main(String[] args) throws Exception{
    //将集合作为数据源,读取集合中的数据到一个流中
    collectionDataSource();
    //将数组作为数据源,读取数组中的数据到一个流中(使用引用数据类型)
    arrayDataSource();
    //将数组作为数据源,读取数组中的数据到一个流中(使用基本数据类型)
}

//将集合作为数据源,读取集合中的数据到一个流中
public static void collectionDataSource(){
    //1.实例化一个集合
    List<Integer> list = new ArrayList<>();
    //2.填充元素
    Collections.addAll(list,0,1,2,3,4,5,6,7,8,9);
    //3.读取集合中的数据,将其读取到流中
    //Stream<Integer> stream = list.stream();//同步流
    Stream<Integer> integerStream = list.parallelStream();//并发流
    //4.输出stream
    System.out.println(integerStream);//java.util.stream.ReferencePipeline$Head@4554617c
}

//将数组作为数据源,读取数组中的数据到一个流中
public static void arrayDataSource(){
    //1.实例化一个数组
    Integer[] array = new Integer[]{0,1,2,3,4,5,6,7,8,9};
    //2.读取数组中的数据到流中,得到一个流对象
    Stream<Integer> stream = Arrays.stream(array);
    //3.输出Stream
    System.out.println(stream);
}

//将数组作为数据源,读取数组中的数据到一个流中
//集合中只能存引用数据类型,但是数组中不用
public static void arrayDataSource2(){
    //1.实例化一个数组
    int[] array = new int[]{0,1,2,3,4,5,6,7,8,9};
    //2.读取数组中的数据到流中,得到一个流对象
    IntStream stream = Arrays.stream(array);
    //3.输出Stream
    System.out.println(stream);
}

三、最终操作

将流中的数据整合到一起,可以存入一个集合,也可以直接对流中的数据进行遍历,数据统计...通过最终操作,需要掌握如何从流中提取出来我们想要的信息。

注意事项:最终操作,在执行结束之后,会关闭这个流,流中的所有数据都会被销毁,如果使用一个已经关闭了的流,会出现异常。

最终操作包括:collect、reduce、count、forEach、max&min、Matching、find、IntStream等。

1. collect

将流中的数据收集到一起,对这些数据进行一些处理。最常见的处理,就是将流中的数据存入一个集合。collect方法的参数,是一个collector接口,而且这个接口并不是一个函数式接口,实现这个接口,可以自定义收集的规则。但是,绝大部分情况下,不需要自定义。
直接使用Collectors工具类提供的方法即可。

java 流式编程原理 java流式编程的优缺点_List

java 流式编程原理 java流式编程的优缺点_List_02

public class FinalOperation {
    public static void main(String[] args) {
        collectUsage();
    }

    //最终操作:collect将流中的数据整合起来,最常见的处理是:读取流中的数据,整合到一个容器中,得到一个集合。
    public static void collectUsage(){
        //1.读取数据源
        Stream<Integer> dataSource = getDataSource();
        //2.流中的数据的聚合
        //List<Integer> list = dataSource.collect(Collectors.toList());
        //System.out.println(list);//[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
        //Set<Integer> set = dataSource.collect(Collectors.toSet());
        //System.out.println(set);//[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
        //Map<String, Integer> map = dataSource.collect(Collectors.toMap(i -> i.toString(), i -> i));//i.toString作为键 i作为值
        Map<String, Integer> map = dataSource.collect(Collectors.toMap(Object::toString, i -> i));//i.toString作为键 i作为值
        System.out.println(map);//{0=0, 1=1, 2=2, 3=3, 4=4, 5=5, 6=6, 7=7, 8=8, 9=9}
    }

    //数据源的获取,从一个容器中获取数据源中的数据(得到一个Stream对象)
    public static Stream<Integer> getDataSource(){
        //1.准备一个容器
        List<Integer> dataSource = new ArrayList<>();
        //2.向数据源中添加数据
        Collections.addAll(dataSource, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9);
        //3.读取数据源中的数据,得到Stream对象
        return dataSource.stream();
    }
}

View Code

2. reduce

将流中的数据按照一定的规则聚合起来。将流的元素,逐一带入这个方法中,进行运算。最终的运算结果,得到的其实是一个Optional类型,需要使用get()获取到里面的数据

java 流式编程原理 java流式编程的优缺点_List

java 流式编程原理 java流式编程的优缺点_List_02

public class FinalOperation {
    public static void main(String[] args) {
        reduceUsage();
    }

    public static void reduceUsage(){
        //1.读取数据源,得到流对象
        Stream<Integer> dataSource = getDataSource();
        //2.最终操作 (这里有两个参数,实现了从0到9的和的求值 即p1=0 p2=1 和的结果为1作为p1 再跟p2=2相加,以此类推)
        Integer num = dataSource.reduce((p1, p2) -> p1 + p2).get();
        //Integer num = dataSource.reduce(Integer::sum).get();
        //3.输出
        System.out.println(num);//45
    }

    //数据源的获取,从一个容器中获取数据源中的数据(得到一个Stream对象)
    public static Stream<Integer> getDataSource(){
        //1.准备一个容器
        List<Integer> dataSource = new ArrayList<>();
        //2.向数据源中添加数据
        Collections.addAll(dataSource, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9);
        //3.读取数据源中的数据,得到Stream对象
        return dataSource.stream();
    }
}

View Code

3. count

统计流中的元素数量

java 流式编程原理 java流式编程的优缺点_List

java 流式编程原理 java流式编程的优缺点_List_02

public class FinalOperation {
    public static void main(String[] args) {
        countUsage();
    }

    public static void countUsage(){
        //1.读取数据源,得到流对象
        Stream<Integer> dataSource = getDataSource();
        //2.最终操作 获取元素数量
        Long num = dataSource.count();
        //3.输出
        System.out.println(num);//10
    }

    //数据源的获取,从一个容器中获取数据源中的数据(得到一个Stream对象)
    public static Stream<Integer> getDataSource(){
        //1.准备一个容器
        List<Integer> dataSource = new ArrayList<>();
        //2.向数据源中添加数据
        Collections.addAll(dataSource, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9);
        //3.读取数据源中的数据,得到Stream对象
        return dataSource.stream();
    }
}

View Code

4. forEach

迭代、遍历流中的数据

java 流式编程原理 java流式编程的优缺点_List

java 流式编程原理 java流式编程的优缺点_List_02

public class FinalOperation {
    public static void main(String[] args) {
        forEachUsage();
    }

    public static void forEachUsage(){
        //1.读取数据源,得到流对象
        Stream<Integer> dataSource = getDataSource();
        //2.最终操作 遍历流中的数据 输出
        dataSource.forEach(System.out::print);//0123456789
    }

    //数据源的获取,从一个容器中获取数据源中的数据(得到一个Stream对象)
    public static Stream<Integer> getDataSource(){
        //1.准备一个容器
        List<Integer> dataSource = new ArrayList<>();
        //2.向数据源中添加数据
        Collections.addAll(dataSource, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9);
        //3.读取数据源中的数据,得到Stream对象
        return dataSource.stream();
    }
}

View Code

5. max&min

获取流中的最大/最小元素

java 流式编程原理 java流式编程的优缺点_List

java 流式编程原理 java流式编程的优缺点_List_02

public class FinalOperation {
    public static void main(String[] args) {
        maxAndMinUsage();
    }

    //按照执行的对象比较的规则去进行大小的比较,然后得出流中最大、最小的数据
    public static void maxAndMinUsage(){
        //1.读取数据源,得到流对象
        Stream<Integer> dataSource = getDataSource();
        //2.最终操作 获取流中的最大、最小值
        //Integer max = dataSource.max(Integer::compareTo).get();
        //System.out.println(max);//9
        Integer min = dataSource.min(Integer::compareTo).get();
        System.out.println(min);//0
    }

    //数据源的获取,从一个容器中获取数据源中的数据(得到一个Stream对象)
    public static Stream<Integer> getDataSource(){
        //1.准备一个容器
        List<Integer> dataSource = new ArrayList<>();
        //2.向数据源中添加数据
        Collections.addAll(dataSource, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9);
        //3.读取数据源中的数据,得到Stream对象
        return dataSource.stream();
    }
}

View Code

6. Matching

allMatch:只有当流中所有的元素,都匹配指定的规则,才会返回true
anyMatch:只要流中有任意的数据,满足指定的规则,都会返回true
noneMatch:只有当流中所有的元素,都不满足指定的规则,才会返回true

java 流式编程原理 java流式编程的优缺点_List

java 流式编程原理 java流式编程的优缺点_List_02

public static void main(String[] args) {
    matchingUsage();
}

public static void matchingUsage(){
    //1.读取数据源,获取Stream对象
    Stream<Integer> dataSource = getDataSource();
    //2.匹配的操作
    //boolean b = dataSource.allMatch(e -> e>0);
    //System.out.println(b);//false 因为不是集合中所有的元素都大于0 还有一个等于0
    //boolean b = dataSource.anyMatch(e -> e >= 9);
    //System.out.println(b);//true
    boolean b = dataSource.noneMatch(e -> e > 9);
    System.out.println(b);//true
}

//数据源的获取,从一个容器中获取数据源中的数据(得到一个Stream对象)
public static Stream<Integer> getDataSource(){
    //1.准备一个容器
    List<Integer> dataSource = new ArrayList<>();
    //2.向数据源中添加数据
    Collections.addAll(dataSource, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9);
    //3.读取数据源中的数据,得到Stream对象
    return dataSource.stream();
}

View Code

7. find

findFirst:从流中获取一个元素(是获取的开头元素)
findAny:从流中获取一个元素(一般情况下,是获取的开头的元素)
这两个方法,绝大部分情况下,是完全相同的,但是在多线程环境下,返回结果可能不一样

java 流式编程原理 java流式编程的优缺点_List

java 流式编程原理 java流式编程的优缺点_List_02

public static void main(String[] args) {
    findUsage();
}

public static void findUsage(){
    //1.实例化一个集合
    ArrayList<Integer> dataSource = new ArrayList<>();
    Collections.addAll(dataSource, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9);
    //2.findFirst演示
    //Integer integer = dataSource.stream().findFirst().get();//串行流
    //Integer integer = dataSource.parallelStream().findFirst().get();//并行流
    //System.out.println(integer);//串行流或者是并行流结果都是0
    //3.findAny演示
    //Integer integer = dataSource.stream().findAny().get();//串行流
    Integer integer = dataSource.parallelStream().findAny().get();//并行流
    System.out.println(integer);//串行流是0、并行流结果为6  即不一定是0
}

View Code

8. IntStream

主要可以实现获取流中int类型数据的最大值、最小值、平均值、和、数量
还可以获取到一个对流中数据的分析结果(即一次获取所有类型的值)

java 流式编程原理 java流式编程的优缺点_List

java 流式编程原理 java流式编程的优缺点_List_02

public static void main(String[] args) {
    intStreamUsage();
}

public static void intStreamUsage(){
    //1.准备一个int数组作为数据源
    int[] array = new int[]{0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
    //2.读取数据到流中,获取IntStream对象
    IntStream stream = Arrays.stream(array);
    //3.输出
    //System.out.println(stream.max().getAsInt());//获取最大值     9
    //System.out.println(stream.min().getAsInt());//获取最小值     0
    //System.out.println(stream.sum());//获取和      45
    //System.out.println(stream.count());//获取流中数据个数   10
    //System.out.println(stream.average().getAsDouble());//获取流中数据的平均值   4.5
    //4.获取到一个对流中数据的分析结果(即一次获取所有类型的值)
    IntSummaryStatistics intSummaryStatistics = stream.summaryStatistics();
    System.out.println("最大值:"+intSummaryStatistics.getMax()+" 最小值:"+intSummaryStatistics.getMin());//最大值:9 最小值:0
    System.out.println("平均值:"+intSummaryStatistics.getAverage()+" 和:"+intSummaryStatistics.getSum());//平均值:4.5 和:45
    System.out.println("数量:"+intSummaryStatistics.getCount());//数量:10
}

View Code

四、中间操作

将数据从数据源中读取到流中,就是对流中的数据进行各种各样的操作、处理。中间操作可以连续操作,每一个操作的返回值都是一个Stream对象,可以继续进行其他的操作,直到最终操作。

中间操作主要分为:filter、distinct、sorted、limit&skip、map&flatMap、Collections工具类

1. filter

条件过滤,仅保留流中满足指定条件的数据,其他不满足的数据都会被删除。

java 流式编程原理 java流式编程的优缺点_List

java 流式编程原理 java流式编程的优缺点_List_02

//学生类:存储于集合中的数据类型
private static class Student{
    private String name;
    private int age;
    private int score;

    public Student(String name, int age, int score) {
        this.name = name;
        this.age = age;
        this.score = score;
    }
    //这里省略getter、setter、toString方法
}

public static void main(String[] args) {
    filterUsage();
}

public static void filterUsage(){
    //1. 获取数据源
    Stream<Student> dataSource = getDataSource();
    //2. 过滤掉集合中成绩不合格的学生信息
    dataSource.filter(s -> s.getScore()>=60).forEach(System.out::println);
    //Student{name='xiaoming', age=18, score=100}
    //Student{name='xiaoming', age=19, score=90}
    //Student{name='xiaoming', age=20, score=80}
    //Student{name='xiaoming', age=21, score=70}
    //Student{name='xiaoming', age=22, score=60}
}

//读取数据源,将集合中存储的数据,读取到数据源中
public static Stream<Student> getDataSource(){
    //1.实例化一个集合,存Student对象
    ArrayList<Student> arrayList = new ArrayList<>();
    //2.添加若干数据
    Collections.addAll(arrayList,
                       new Student("xiaoming",18,100),
                       new Student("xiaoming",19,90),
                       new Student("xiaoming",20,80),
                       new Student("xiaoming",21,70),
                       new Student("xiaoming",22,60),
                       new Student("xiaoming",23,50),
                       new Student("xiaoming",24,40)
                      );
    //3.读取数据源,得到Stream对象
    return arrayList.stream();
}

View Code

2. distinct

去除集合中重复的元素,这个方法没有参数,去重的规则与HashSet相同。
 (1)比较两个对象的hashcode
 (2)使用equals再来对比一下
这里要注意:实体类中需要重写hashcode和equals方法,否则去重可能不会生效

java 流式编程原理 java流式编程的优缺点_List

java 流式编程原理 java流式编程的优缺点_List_02

//学生类:存储于集合中的数据类型
private static class Student{
    private String name;
    private int age;
    private int score;

    public Student(String name, int age, int score) {
        this.name = name;
        this.age = age;
        this.score = score;
    }
    //这里省略getter、setter、toString、hashcode、equals方法
}

public static void main(String[] args) {
    distinctUsage();
}


public static void distinctUsage(){
    //1. 获取数据源
    Stream<Student> dataSource = getDataSource();
    //2. 去重 要注意实体类Student中需要重写equals和hashCode方法,否则去重不会生效
    dataSource.distinct().forEach(System.out::println);
    //Student{name='xiaoming1', age=18, score=100}
    //Student{name='xiaoming2', age=20, score=80}
    //Student{name='xiaoming3', age=21, score=70}
    //Student{name='xiaoming4', age=22, score=60}
    //Student{name='xiaoming5', age=23, score=50}
    //Student{name='xiaoming6', age=24, score=40}

}

//读取数据源,将集合中存储的数据,读取到数据源中
public static Stream<Student> getDataSource(){
    //1.实例化一个集合,存Student对象
    ArrayList<Student> arrayList = new ArrayList<>();
    //2.添加若干数据
    Collections.addAll(arrayList,
                       new Student("xiaoming1",18,100),
                       new Student("xiaoming1",18,100),
                       new Student("xiaoming2",20,80),
                       new Student("xiaoming3",21,70),
                       new Student("xiaoming4",22,60),
                       new Student("xiaoming5",23,50),
                       new Student("xiaoming6",24,40)
                      );
    //3.读取数据源,得到Stream对象
    return arrayList.stream();
}

View Code

3. sorted

对流中的数据进行排序
 (1)无参:sorted():将流中的数据,按照其对应的类实现的Comparable接口提供的比较规则进行排序
 (2)有参:sorted(Comparator<T> comparator):将流中的数据,按照参数接口提供的比较规则进行排序

java 流式编程原理 java流式编程的优缺点_List

java 流式编程原理 java流式编程的优缺点_List_02

private static class Student implements Comparable<Student>{
    private String name;
    private int age;
    private int score;

    public Student(String name, int age, int score) {
        this.name = name;
        this.age = age;
        this.score = score;
    }

    @Override
    public int compareTo(Student o) {
        return score-o.score;
    }
    //这里省略getter、setter、toString、hashcode、equals方法
}

public static void main(String[] args) {
    sortedUsage();
}


public static void sortedUsage(){
    //1. 获取数据源
    Stream<Student> dataSource = getDataSource();
    //2. 将流中的数据进行排序 (注意实体类要注意实现Comparable接口并重写compareTo方法,否则会报错)
    //dataSource.sorted().forEach(System.out::println);
    //Student{name='xiaoming6', age=24, score=40}
    //Student{name='xiaoming5', age=23, score=50}
    //Student{name='xiaoming4', age=22, score=60}
    //Student{name='xiaoming3', age=21, score=70}
    //Student{name='xiaoming2', age=20, score=80}
    //Student{name='xiaoming1', age=18, score=100}
    //Student{name='xiaoming1', age=18, score=100}
    //3. 对流中的数据按照自定义的规则进行排序 (按照年龄升序排列)
    dataSource.sorted((s1,s2)->s1.getAge()-s2.getAge()).forEach(System.out::println);
    //Student{name='xiaoming1', age=18, score=100}
    //Student{name='xiaoming1', age=18, score=100}
    //Student{name='xiaoming2', age=20, score=80}
    //Student{name='xiaoming3', age=21, score=70}
    //Student{name='xiaoming4', age=22, score=60}
    //Student{name='xiaoming5', age=23, score=50}
    //Student{name='xiaoming6', age=24, score=40}
}

//读取数据源,将集合中存储的数据,读取到数据源中
public static Stream<Student> getDataSource(){
    //1.实例化一个集合,存Student对象
    ArrayList<Student> arrayList = new ArrayList<>();
    //2.添加若干数据
    Collections.addAll(arrayList,
                       new Student("xiaoming1",18,100),
                       new Student("xiaoming1",18,100),
                       new Student("xiaoming2",20,80),
                       new Student("xiaoming3",21,70),
                       new Student("xiaoming4",22,60),
                       new Student("xiaoming5",23,50),
                       new Student("xiaoming6",24,40)
                      );
    //3.读取数据源,得到Stream对象
    return arrayList.stream();
}

View Code

4. limit&skip

limit:限制,截取流中指定数量的元素   skip:跳过流中的指定数量的元素 经常放在一起用

java 流式编程原理 java流式编程的优缺点_List

java 流式编程原理 java流式编程的优缺点_List_02

//实体类省略,参考上面即可

public static void main(String[] args) {
     limitAndSkipUsage();
 }


public static void limitAndSkipUsage(){
    //1. 获取数据源
    Stream<Student> dataSource = getDataSource();
    //2. 获取成绩的前5名
    //        dataSource.distinct()
    //                .sorted((s1,s2)->s2.getScore()-s1.getScore())
    //                .limit(5)
    //                .forEach(System.out::println);
    //3. 获取成绩为3-5名的
    dataSource.distinct()
        .sorted((s1,s2)->s2.getScore()-s1.getScore())
        .limit(5)
        .skip(2)
        .forEach(System.out::println);
}

//读取数据源,将集合中存储的数据,读取到数据源中
public static Stream<Student> getDataSource(){
    //1.实例化一个集合,存Student对象
    ArrayList<Student> arrayList = new ArrayList<>();
    //2.添加若干数据
    Collections.addAll(arrayList,
                       new Student("xiaoming1",18,100),
                       new Student("xiaoming1",18,100),
                       new Student("xiaoming2",20,80),
                       new Student("xiaoming3",21,70),
                       new Student("xiaoming4",22,60),
                       new Student("xiaoming5",23,50),
                       new Student("xiaoming6",24,40)
                      );
    //3.读取数据源,得到Stream对象
    return arrayList.stream();
}

View Code

5. map&flatMap

对流中的数据进行映射,用新的数据替换旧的数据

map最主要,就是来做元素的替换,其实map是一个元素的映射(将流中每一个元素替换成指定的元素)

flatMap也是元素的映射,flatMap是扁平化映射

扁平化映射:一般用在map映射完成后,流中的数据是一个容器,而我们需要对容器中的数据进行处理 此时使用扁平化映射,可以将流中的容器中的数据,直接读取到流中

案例1:

java 流式编程原理 java流式编程的优缺点_List

java 流式编程原理 java流式编程的优缺点_List_02

public static void main(String[] args) {
    mapUsage();
}


public static void mapUsage(){
    //1. 获取数据源
    Stream<Student> dataSource = getDataSource();
    //2. 实际需求:获取所有学生的名字
    //dataSource.map(Student::getName).forEach(System.out::println);
    //dataSource.map(s->s.getName()).forEach(System.out::println);
    //3. 实际需求:获取所有学生的成绩 注意:泛型中不能是基本数据类型,只能是包装类 即下面的返回值应该为Stream<Integer>
    //dataSource.map(Student::getScore).forEach(System.out::println);
    //4. 实际需求:获取所有学生的成绩
    IntSummaryStatistics intSummaryStatistics = dataSource.mapToInt(Student::getScore).summaryStatistics();
    System.out.println(intSummaryStatistics.getMax());
}

//读取数据源,将集合中存储的数据,读取到数据源中
public static Stream<Student> getDataSource(){
    //1.实例化一个集合,存Student对象
    ArrayList<Student> arrayList = new ArrayList<>();
    //2.添加若干数据
    Collections.addAll(arrayList,
                       new Student("xiaoming1",18,100),
                       new Student("xiaoming1",18,100),
                       new Student("xiaoming2",20,80),
                       new Student("xiaoming3",21,70),
                       new Student("xiaoming4",22,60),
                       new Student("xiaoming5",23,50),
                       new Student("xiaoming6",24,40)
                      );
    //3.读取数据源,得到Stream对象
    return arrayList.stream();
}

View Code

案例2:

java 流式编程原理 java流式编程的优缺点_List

java 流式编程原理 java流式编程的优缺点_List_02

public static void main(String[] args) {
    mapUsage();
}

public static void mapUsage(){
    //1.实例化一个字符串数组
    String[] array = {"hello","world"};
    //2.将字符串数组中的数据读取到流中
    Stream<String> stream = Arrays.stream(array);
    //3.需求:统计字符串数组中所有出现的字符
    //stream.map(String::toCharArray).forEach(e->System.out.println(Arrays.toString(e)));
    //结果为 [h, e, l, l, o]  [w, o, r, l, d] 两个数组 不符合我们的要求
    stream.map(s->s.split(""))
        .flatMap(Arrays::stream)
        .distinct()
        .forEach(System.out::println);
    //结果为h e l o w r d
}

View Code

6. Collections工具类

Collectors是一个工具类,里面封装了很多方法,可以很方便的获取到一个Collector接口的实现类对象,从而可以使用collect()方法,对流中的数据,进行各种各样的处理、整合。
常用方法:
 Collectors.toList()  将流中的数据,聚合到一个List集合中
 Collectors.toSet()  将流中的数据,聚合到一个Set集合中
 Collectors.toMap()  将流中的数据,聚合到一个Map集合中
 maxBy()     按照指定的规则,找到流中最大的元素,等同于max
 minBy()     按照指定的规则,找到流中最小的元素,等同于min
 joining()     将流中的数据拼接成一个字符串,注意:只能操作流中是String的数据
 summingInt()    将流中的数据,映射成int类型的数据,并求和
 averagingInt()   将流中的数据,映射成int类型的数据,并求平均值
 summarizingInt()   将流中的数据,映射成int类型的数据,并获取描述信息

java 流式编程原理 java流式编程的优缺点_List

java 流式编程原理 java流式编程的优缺点_List_02

public static void main(String[] args) {
    //1. 准备一个字符串数组,作为数据源
    String[] dataSource = {"nihao","wo","shi","xxx"};
    //2. 读取数据源中的数据
    Stream<String> stream = Arrays.stream(dataSource);
    //3. joining方法,只适用于 Stream<String> 这种流
    //String collect = stream.collect(Collectors.joining());//拼接
    //System.out.println(collect);//nihaowoshixxx
    //String collect = stream.collect(Collectors.joining(","));//拼接 按照逗号分隔
    //System.out.println(collect);//nihao,wo,shi,xxx
    //tring collect = stream.collect(Collectors.joining(",","[","]"));//拼接 带前缀、后缀
    //System.out.println(collect);//[nihao,wo,shi,xxx]

    //4. summingInt
    Integer collect = stream.collect(Collectors.summingInt(String::length));
    System.out.println(collect);//13
}

View Code