jdk8新特性-4、Stream流式计算

一、概述:

java8的流式处理极大的简化了对于集合的操作,实际上不光是集合,包括数组、文件等,只要是可以转换成流,我们都可以借助流式处理,类似于我们写SQL语句一样对其进行操作。java8通过内部迭代来实现对流的处理,一个流式处理可以分为三个部分:转换成流、中间操作、终端操作。如下图:

jdk8新特性-4、Stream流式计算_第1张图片


/**
 * @Author zongx
 * @Date 2020/7/30 14:23
 * @Version 1.0
 */
public class StreamTest {
    List list;

    @Before
    public void init() {
        list = new ArrayList(){
            {
                add(new User(1l,"张三",10, "清华大学"));
                add(new User(2l,"李四",12, "清华大学"));
                add(new User(3l,"王五",15, "清华大学"));
                add(new User(4l,"赵六",12, "清华大学"));
                add(new User(5l,"田七",25, "北京大学"));
                add(new User(6l,"小明",16, "北京大学"));
                add(new User(7l,"小红",14, "北京大学"));
                add(new User(8l,"小华",14, "浙江大学"));
                add(new User(9l,"小丽",17, "浙江大学"));
                add(new User(10l,"小何",10, "浙江大学"));
            }
        };
    }
}

class User {
    public Long id;       //主键id
    public String name;   //姓名
    public Integer age;   //年龄
    public String school; //学校

    public User(Long id, String name, Integer age, String school) {
        this.id = id;
        this.name = name;
        this.age = age;
        this.school = school;
    }

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

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

    public Integer getAge() {
        return age;
    }

    public void setAge(Integer age) {
        this.age = age;
    }

    public String getSchool() {
        return school;
    }

    public void setSchool(String school) {
        this.school = school;
    }

    @Override
    public String toString() {
        return "User{" +
                "id=" + id +
                ", name='" + name + '\'' +
                ", age=" + age +
                ", school='" + school + '\'' +
                '}';
    }
}

二、中间操作

1. 过滤

1.1 filter

根据条件进行过滤

    @Test
    public void test4() {
        System.out.println("学校是清华大学的user");
        List userList1 = list.stream().filter(user -> "清华大学".equals(user.getSchool())).collect(Collectors.toList());
        userList1.forEach(user -> System.out.print(user.name + '、'));
    }

1.2 distinct

去重

    @Test
    public void test5() {
        System.out.println("所有user的年龄集合");
        List userAgeList = list.stream().map(User::getAge).distinct().collect(Collectors.toList());
        System.out.println("userAgeList = " + userAgeList);
    }

1.3 limit 

返回前n个元素的流,当集合的长度小于n时,则返回所有集合。

    @Test
    public void test6() {
        System.out.println("年龄是偶数的前两位user");
        List userList3 = list.stream().filter(user -> user.getAge() % 2 == 0).limit(2).collect(Collectors.toList());
        userList3.forEach(user -> System.out.print(user.name + '、'));
    }

1.4 sorted

排序

    @Test
    public void test7() {
        System.out.println("按年龄从大到小排序");
        List userList4 = list.stream().sorted((s1,s2) -> s2.age - s1.age).collect(Collectors.toList());
        userList4.forEach(user -> System.out.print(user.name + '、'));
    }

1.5 skip

跳过n个元素后再输出

    @Test
    public void test8() {
        System.out.println("跳过前面两个user的其他所有user");
        List userList5 = list.stream().skip(2).collect(Collectors.toList());
        userList5.forEach(user -> System.out.print(user.name + '、'));
    }

2 映射

2.1 map

集合会按照map后值进行精简

    @Test
    public void test9() {
        System.out.println("学校是清华大学的user的名字");
        List userList6 = list.stream().filter(user -> "清华大学".equals(user.school)).map(User::getName).collect(Collectors.toList());
        userList6.forEach(user -> System.out.print(user + '、'));
    }

jdk8新特性-4、Stream流式计算_第2张图片

2.2  mapToInt(ToIntFunction mapper)

类似的还有mapToDouble(ToDoubleFunction mapper),mapToInt(ToIntFunction mapper),这些映射分别返回对应类型的流。这些流设定了一些特殊的操作。

    @Test
    public void test10() {
        System.out.println("学校是清华大学的user的年龄总和");
        int userList7 = list.stream().filter(user -> "清华大学".equals(user.school)).mapToInt(User::getAge).sum();
        System.out.println( "学校是清华大学的user的年龄总和为: "+userList7);
    }

2.3 flatMap

flatMap与map的区别在于 flatMap是将一个流中的每个值都转成一个个流,然后再将这些流扁平化成为一个流 。

    @Test
    public void test11() {
        String[] strings = {"Hello", "World"};
        String s = "hello";
        String[] split = s.split("");
        List l1 = Arrays.stream(strings).map(str -> str.split("")).map(Arrays::stream).distinct().collect(Collectors.toList());
//        List l1 = Arrays.stream(split).distinct().collect(Collectors.toList());
        List l2 = Arrays.asList(strings).stream().map(str -> str.split("")).flatMap(Arrays::stream).distinct().collect(Collectors.toList());
        System.out.println(l1.toString());
        System.out.println(l2.toString());
    }

jdk8新特性-4、Stream流式计算_第3张图片

由上我们可以看到使用map并不能实现我们现在想要的结果,而flatMap是可以的。这是因为在执行map操作以后,我们得到是一个包含多个字符串(构成一个字符串的字符数组)的流,此时执行distinct操作是基于在这些字符串数组之间的对比,所以达不到我们希望的目的;flatMap将由map映射得到的Stream,转换成由各个字符串数组映射成的流Stream,再将这些小的流扁平化成为一个由所有字符串构成的大流Steam,从而能够达到我们的目的。

三、终端操作

1.查找

1.1 allMatch

用于检测是否全部都满足指定的参数行为,如果全部满足则返回true。

    @Test
    public void test12() {
        System.out.println("判断是否所有user的年龄都大于9岁");
        Boolean b = list.stream().allMatch(user -> user.age >9);
        System.out.println(b);
    }

1.2 anyMatch

anyMatch则是检测是否存在一个或多个满足指定的参数行为,如果满足则返回true。

    @Test
    public void test13() {
        System.out.println("判断是否有user的年龄是大于15岁");
        Boolean bo = list.stream().anyMatch(user -> user.age >15);
        System.out.println(bo);
    }

1.3 noneMatch 

noneMatch用于检测是否不存在满足指定行为的元素,如果不存在则返回true。

    @Test
    public void test14() {
        System.out.println("判断是否不存在年龄是15岁的user");
        Boolean boo = list.stream().noneMatch(user -> user.age == 15);
        System.out.println(boo);
    }

jdk8新特性-4、Stream流式计算_第4张图片

1.4 findFirst

findFirst用于返回满足条件的第一个元素

    @Test
    public void test15() {
        System.out.println("返回年龄大于12岁的user中的第一个");
        Optional first = list.stream().filter(u -> u.age > 10).findFirst();
        User user = first.get();
        System.out.println(user.toString());
    }

1.5 findAny

findAny相对于findFirst的区别在于,findAny不一定返回第一个,而是返回任意一个

    @Test
    public void test16() {
        System.out.println("返回年龄大于12岁的user中的任意一个");
        Optional anyOne = list.stream().filter(u -> u.age > 10).findAny();
        User user2 = anyOne.get();
        System.out.println(user2.toString());
    }

2. 归约

2.1 reduce

现在的目标不是返回一个新的集合,而是希望对经过参数化操作后的集合进行进一步的运算,那么我们可用对集合实施归约操作。java8的流式处理提供了reduce方法来达到这一目的。

    @Test
    public void test17() {
        Integer ages = list.stream().filter(student -> "清华大学".equals(student.school)).mapToInt(User::getAge).sum();
        System.out.println(ages);
        System.out.println("归约 - - 》 start ");
        Integer ages2 = list.stream().filter(student -> "清华大学".equals(student.school)).map(User::getAge).reduce(0,(a,c)->a+c);
        Integer ages3 = list.stream().filter(student -> "清华大学".equals(student.school)).map(User::getAge).reduce(0,Integer::sum);
//        Integer ages4 = list.stream().filter(student -> "清华大学".equals(student.school)).map(User::getAge).reduce(Integer::sum).get();
        Integer ages4 = list.stream().map(User::getAge).reduce(Integer::sum).get();
        System.out.println(ages2);
        System.out.println(ages3);
        System.out.println(ages4);
        System.out.println("归约 - - 》 end ");
    }

jdk8新特性-4、Stream流式计算_第5张图片

3. 收集

前面利用collect(Collectors.toList())是一个简单的收集操作,是对处理结果的封装,对应的还有toSet、toMap,以满足我们对于结果组织的需求。这些方法均来自于java.util.stream.Collectors,我们可以称之为收集器。

收集器也提供了相应的归约操作,但是与reduce在内部实现上是有区别的,收集器更加适用于可变容器上的归约操作,这些收集器广义上均基于Collectors.reducing()实现。

下面都是结果收集,是对java.util.stream.Collectors的操作。

3.1 counting

 计算个数

    @Test
    public void test18() {
        System.out.println("user的总人数");
        long COUNT = list.stream().count();//简化版本
        long COUNT2 = list.stream().filter( user -> user.age > 10).collect(Collectors.counting());//原始版本
        System.out.println(COUNT);
        System.out.println(COUNT2);
    }

3.2 maxBy、minBy

通过comparetor计算最大值和最小值

    @Test
    public void test19() {
        System.out.println("user的年龄最大值和最小值");
        Integer maxAge =list.stream().collect(Collectors.maxBy((s1, s2) -> s1.getAge() - s2.getAge())).get().age;
        Integer maxAge2 = list.stream().collect(Collectors.maxBy(Comparator.comparing(User::getAge))).get().age;
        Integer minAge = list.stream().collect(Collectors.minBy((S1,S2) -> S1.getAge()- S2.getAge())).get().age;
        Integer minAge2 = list.stream().collect(Collectors.minBy(Comparator.comparing(User::getAge))).get().age;
        System.out.println("maxAge = " + maxAge);
        System.out.println("maxAge2 = " + maxAge2);
        System.out.println("minAge = " + minAge);
        System.out.println("minAge2 = " + minAge2);
    }

jdk8新特性-4、Stream流式计算_第6张图片

3.3 summingInt、summingLong、summingDouble

总和

    @Test
    public void test20() {
        System.out.println("user的年龄总和");
        Integer sumAge =list.stream().collect(Collectors.summingInt(User::getAge));
        System.out.println("sumAge = " + sumAge);
    }

jdk8新特性-4、Stream流式计算_第7张图片

3.4 averageInt、averageLong、averageDouble

求平均

    @Test
    public void test21() {
        System.out.println("user的年龄平均值");
        double averageAge = list.stream().collect(Collectors.averagingDouble(User::getAge));
        System.out.println("averageAge = " + averageAge);
    }

jdk8新特性-4、Stream流式计算_第8张图片

3.5 summarizingInt、summarizingLong、summarizingDouble

一次性查询元素个数、总和、最大值、最小值和平均值

    @Test
    public void test22() {
        System.out.println("一次性得到元素个数、总和、均值、最大值、最小值");
        long l1 = System.currentTimeMillis();
        IntSummaryStatistics summaryStatistics = list.stream().collect(Collectors.summarizingInt(User::getAge));
        long l111 = System.currentTimeMillis();
        System.out.println("计算这10个值消耗时间为" + (l111-l1));
        System.out.println("summaryStatistics = " + summaryStatistics);
    }

3.6 joining

拼接

    @Test
    public void test23() {
        System.out.println("字符串拼接");
        String names = list.stream().map(User::getName).collect(Collectors.joining(","));
        System.out.println("names = " + names);
    }

3.7 groupingBy

分组

    @Test
    public void test24() {
        System.out.println("分组");
        Map> collect1 = list.stream().collect(Collectors.groupingBy(User::getSchool));
        Map> collect2 = list.stream().collect(Collectors.groupingBy(User::getSchool, Collectors.groupingBy(User::getAge, Collectors.counting())));
        Map collect3 = list.stream().collect(Collectors.groupingBy(User::getSchool, Collectors.counting()));
        Map>> collect4 = list.stream().collect(Collectors.groupingBy(User::getSchool, Collectors.groupingBy(User::getAge, Collectors.groupingBy(User::getName,Collectors.counting()))));
        System.out.println("collect1 = " + collect1);
        System.out.println("collect2 = " + collect2);
        System.out.println("collect3 = " + collect3);
        System.out.println("collect4 = " + collect4);
    }

3.8 partitioningBy  

分区,分区可以看做是分组的一种特殊情况,在分区中key只有两种情况:true或false,目的是将待分区集合按照条件一分为二。

    @Test
    public void test25() {
        System.out.println("分区");
        Map> collect5 = list.stream().collect(Collectors.partitioningBy(user1 -> "清华大学".equals(user1.school)));
        System.out.println("collect5 = " + collect5);
    }

 

 

你可能感兴趣的:(jdk8新特性)