java流stream的一些简单用法

Posted 被杜撰的风

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了java流stream的一些简单用法相关的知识,希望对你有一定的参考价值。

@Data
@AllArgsConstructor
public class Student {
    private String name;
    private Integer score;
    private Integer age;
}
public class StreamTest {

    
    /**
     * flatMap 接收一个流的来源(比如list), 返回一个流
     * 将多个流,打平, 使其成为一个流
     */
    @Test
    public void Test3() {
        Stream<List<Integer>> stream = Stream.of(Arrays.asList(1), Arrays.asList(2,3), Arrays.asList(4,5,6));
        stream.flatMap(list -> list.stream()).map(x->x*x).forEach(System.out::println);

        List<String> list2 = Arrays.asList("hello world", "world hello", "hello world hello", "hello welcome");
        list2.stream().map(item -> item.split(" ")) // 拆成单词
                .flatMap(Arrays::stream) // 打平, 将每个数组处理成流
                .distinct() // 去重, 根据equals方法
                .forEach(System.out::println);
    }

    /**
     * flatMap的更深入使用, 核心就在于将多个stream打平成一个stream, 其入参就是stream类型的
     * 利用两个list交叉打招呼, 相当于两个list的求笛卡尔积
     */
    @Test
    public void Test31() {
        List<String> list1 = Arrays.asList("Hi", "Hello", "你好");
        List<String> list2 = Arrays.asList("zhangsan", "lisi", "wangwu", "zhaoliu");

        List<String> result = list1.stream()
                .flatMap(item -> list2.stream().map(item2 -> item + " " + item2))
                .collect(Collectors.toList());
        result.forEach(System.out::println);
    }

    @Test
    public void Test4() {
        // generate方法, 传入一个生产者
        Stream<String> stream = Stream.generate(UUID.randomUUID()::toString);
        // findFirst 返回一个 optional
        stream.findFirst().ifPresent(System.out::println);
    }

    /**
     * Stream.iterate()
     * 接收一个种子, 和一个行为
     * 这个行为会以种子为初始值, 不断的累加执行,返回一个无限的串行流
     * 所以在使用这个方法时, 一般会加一个limit()方法, 来限制长度
     */
    @Test
    public void Test5() {
        Stream.iterate(1, item -> item + 2)
                .limit(6)
                .forEach(System.out::println);
        System.out.println("-------------------------");
        IntSummaryStatistics collect = Stream.iterate(1, item -> item + 2)
                .limit(6)
                .filter(x -> x > 2) // 过滤
                .map(x -> x * 2) // 转换
                .skip(2)  // 忽略前两个元素
                .limit(2) // 只取前两个元素
                .collect(Collectors.summarizingInt(x -> x));// 求出结果集,集中包含很多操作
        System.out.println(collect.getSum());
    }

    /**
     * 串行流与并行流的排序时间对比
     * 串行流 : 9619
     */
    @Test
    public void Test6() {
        List<String> list = new ArrayList<>(5000000);
        for (int i = 0; i < 5000000; ++i) {
            list.add(UUID.randomUUID().toString());
        }
        System.out.println("开始排序");
        long startTime = System.nanoTime();
        list.stream().sorted().findFirst();
        long endTime = System.nanoTime();
        long millis = TimeUnit.NANOSECONDS.toMillis(endTime - startTime);
        System.out.println("排序耗时: " +millis);
    }

    /**
     * 串行流与并行流的排序时间对比
     * 并行流: 2235
     */
    @Test
    public void Test7() {
        List<String> list = new ArrayList<>(5000000);
        for (int i = 0; i < 5000000; ++i) {
            list.add(UUID.randomUUID().toString());
        }
        System.out.println("开始排序");
        long startTime = System.nanoTime();
        list.parallelStream().sorted().findFirst();
        long endTime = System.nanoTime();
        long millis = TimeUnit.NANOSECONDS.toMillis(endTime - startTime);
        System.out.println("排序耗时: " +millis);
    }

    /**
     * stream还提供了和sql一样的分组功能, 分组结果一般是返回map
     * 根据谁分组, 谁就是key
     */
    @Test
    public void Test8() {
        Student s1 = new Student("zhangsan", 100, 20);
        Student s2 = new Student("lisi", 90, 20);
        Student s3 = new Student("wangwu", 90, 30);
        Student s4 = new Student("zhangsan", 80, 40);

        List<Student> students = Arrays.asList(s1, s2, s3, s4);
        // 按名字对学生分组
        /* 传统做法: 
        结果: Map<String, List<Student>>
        * 1. 循环列表
        * 2. 取出学生名字
        * 3. 检查map中是否存在该名字, 不存在直接添加到该map,
        * 存在则将map中的List对象取出来,然后添加到list中
        * 4. 返回map对象
        * */
        // stream做法:
        Map<String, List<Student>> map = students.stream().collect(Collectors.groupingBy(Student::getName));
        map.forEach((key, value) -> System.out.println("key: " + key + "
value: " + value));
        System.out.println("-----------------------------------------");

        // 根据分数来分组
        Map<Integer, List<Student>> map2 = students.stream().collect(Collectors.groupingBy(Student::getScore));
        map2.forEach((key, value) -> System.out.println("key: " + key + "
value: " + value));
        System.out.println("-----------------------------------------");

        // 分组后,返回数量
        Map<String, Long> m3 = students.stream().collect(Collectors.groupingBy(Student::getName, Collectors.counting()));
        m3.forEach((key, value) -> System.out.println("key: " + key + "
value: " + value));
        System.out.println("-----------------------------------------");

        // 分组后,返回分数平均值
        Map<String, Double> m4 = students.stream().collect(Collectors.groupingBy(Student::getName, Collectors.averagingDouble(Student::getScore)));
        m4.forEach((key, value) -> System.out.println("key: " + key + "
value: " + value));

    }

    /**
     * stream分区, 分区是分组的一种特例, 只把数据分为两组
     * 返回一个map, key是bool类型, 表明是否符合分区条件
     */
    @Test
    public void Test9() {
        Student s1 = new Student("zhangsan", 100, 20);
        Student s2 = new Student("lisi", 90, 20);
        Student s3 = new Student("wangwu", 90, 30);
        Student s4 = new Student("zhangsan", 80, 40);

        List<Student> students = Arrays.asList(s1, s2, s3, s4);
        Map<Boolean, List<Student>> map = students.stream()
                .collect(Collectors.partitioningBy(student -> student.getScore() >= 90));
        map.forEach((key, value) -> System.out.println("key: " + key + "
value: " + value));

    }

    @Test
    public void Test() {
        Student s1 = new Student("zhangsan", 80);
        Student s2 = new Student("lisi", 90);
        Student s3 = new Student("wangwu", 100);
        Student s4 = new Student("zhaoliu", 90);
        Student s5 = new Student("zhangsan", 70);
        Student s6 = new Student("wangwu", 50);
        List<Student> students = Arrays.asList(s1, s2, s3, s4, s5, s6);

        // 在分组的基础上,再次分组, 先根据分数分组, 再根据名字分组
        Map<Integer, Map<String, List<Student>>> map = students.stream().collect(Collectors.groupingBy(Student::getScore, Collectors.groupingBy(Student::getName)));
        System.out.println(map);
        System.out.println("-------------------------");
        // 两次分区
        Map<Boolean, Map<Boolean, List<Student>>> map2 = students.stream().collect(Collectors.partitioningBy(s -> s.getScore() > 80, Collectors.partitioningBy(s -> s.getScore() > 90)));
        System.out.println(map2);
        System.out.println("-------------------------");
        // 先分区, 再求出分区中学生数量
        Map<Boolean, Long> map3 = students.stream().collect(Collectors.partitioningBy(s -> s.getScore() > 80, Collectors.counting()));
        System.out.println(map3);
        System.out.println("-----------------------------");
        // 先根据名字进行分组, 再收集组中分数最小的学生
        Map<String, Optional<Student>> map4 = students.stream().collect(Collectors.groupingBy(Student::getName, Collectors.minBy(Comparator.comparingInt(Student::getScore))));
        System.out.println(map4);
        System.out.println("---------------------------------");
        // 对map4 的优化,先根据名字进行分组, 再收集组中分数最小的学生, 由于先分组了,
        // 所以后面比较的时候一定有元素,可以直接get到值,少一次Optional操作
        Map<String, Student> map5 = students.stream()
                .collect(Collectors.groupingBy(Student::getName,
                        Collectors.collectingAndThen(
                                Collectors.minBy(Comparator.comparingInt(Student::getScore)),
                                Optional::get)
                        )
                );
        System.out.println(map5);
        System.out.println("---------------------------------");
    } 
}

以上是关于java流stream的一些简单用法的主要内容,如果未能解决你的问题,请参考以下文章

Java8用了这么久了,Stream 流用法及语法你都知道吗?

全面吃透JAVA Stream流操作,让代码更加的优雅

Java8 Stream流

Java基础 | Stream流原理与用法总结

Java8 Stream用法详解

java8里面lambda的stream()用法讲解