Stream 是 Java 8 API 中添加的一个新的语法糖,让开发者可以用一种申明式的骚操作来处理数据。

用起来的感觉,像是将你要处理的元素集合看作是水流, 水在管道中流动, 我们可以在管道的各节点上对元素流进行筛选, 排序,聚合等操作。

这些元素集合经过管道的中间操作处理,最后由终止操作得到最后的结果。

  • 无状态:元素的操作不依赖之前元素,不受之前元素的影响,这些操作没有内部状态,称为无状态操作

    • filter()
    • peek()
    • unordered()
    • map()/mapToXxx()
    • flatMap()/flatMapToXxx()
  • 有状态:只有拿到所有的元素之后才能继续操作,这些操作都需要利用到之前元素的内部状态,所以称为有状态操作

    • sort()
    • distinct()
    • limit()
    • skip()
  • 非短路操作:必须所有元素都处理完才能得到最终的结果

    • collect()
    • reduce()
    • max()/min()
    • count()
    • toArray()
    • foEach()/forEachOrdered()
  • 短路操作:一旦得到符合条件的元素就可以中断流得到最终的结果

    • anyMatch()/allMatch()/noneMatch()
    • findFirst()/findAny()
// 1.通过数组创建
String[] arr = {"不","高","兴","就","喝","水"};
Stream<String> stream1 = Arrays.stream(arr);
stream1.forEach(System.out::println);

// 2.通过集合创建
List<String> list = Arrays.asList("不","高","兴","就","喝","水");
// 2.1创建一个顺序流(串行执行)
Stream<String> stream2 = list.stream();
stream2.forEach(System.out::println);

//2.2创建并行流(以多线程方式对流进行操作,底层用的线程池)
// 通过parallel方法把顺序流转成并行流
Stream<String> parallelStream1 = list.stream().parallel();
parallelStream1.forEach(System.out::println);

// 通过集合创建一个并行流
Stream<String> parallelStream2 = list.parallelStream();
parallelStream2.forEach(System.out::println);

// 3.通过Stream的静态方法创建
// 3.1 iterate方法:
Stream<Integer> stream3 = Stream.iterate(1, (x) -> x + 1).limit(6);
stream3.forEach(System.out::println);

// 3.2 of方法:
Stream<String> stream4 = Stream.of("不","高","兴","就","喝","水");
stream4.forEach(System.out::println);

// 3.3 generate方法:
Stream<String> stream5 = Stream.generate(() ->"不高兴就喝水!").limit(3);
stream5.forEach(System.out::println);

// 4.通过数字Stream创建
IntStream intStream1 = IntStream.of(1, 2, 3);
intStream1.forEach(System.out::println);
IntStream intStream2 = IntStream.rangeClosed(1,3);
intStream2.forEach(System.out::println);

// 5.通过random创建无限流
IntStream randomStream = new Random().ints(1,3).limit(3);
randomStream.forEach(System.out::println);

String str = "bu gao xing jiu he shui";
// 转成list集合
// 输出:bu gao xing jiu he shui
Stream.of(str.split(" ")).collect(Collectors.toList())
        .forEach(System.out::println);
// 拿到长度大于2的单词
// 输出:gao xing jiu shui
Stream.of(str.split(" ")).filter(s -> s.length() > 2)
        .forEach(System.out::println);

// flatMap的使用,可以拿到str中的所有的字母
Stream.of(str.split(" ")).flatMap(s -> s.chars().boxed())
        .forEach(i -> System.out.println((char) i.intValue()));

// filter用来过滤符合条件的元素,peek可以输出流操作中的中间值,主要用来调试代码用
Stream.of(str.split(" ")).filter(e -> e.length() > 3)
        .peek(e -> System.out.println("过滤出来的元素: " + e))
        .map(String::toUpperCase)
        .peek(e -> System.out.println("映射过后的元素: " + e))
        .collect(Collectors.toList());


String str = "bu gao xing jiu he shui";

// 使用foreach得到乱序结果(因为用了并行流)
// 输出:n go xu sgbuhiaui  hiej
str.chars().parallel().forEach(i -> System.out.print((char) i));
// 使用forEachOrdered得到顺序结果
// 输出bu gao xing jiu he shui
str.chars().parallel().forEachOrdered(i -> System.out.print((char) i));

// 收集到list集合中
// 输出:[bu, gao, xing, jiu, he, shui]
List<String> list = Stream.of(str.split(" "))
        .collect(Collectors.toList());
System.out.println(list);

// 使用reduce对字符串进行拼接
// 输出bu_gao_xing_jiu_he_shui
Optional<String> stringOptional = Stream.of(str.split(" "))
        .reduce((s1, s2) -> s1 + "_" + s2);
System.out.println(stringOptional.get());

// 计算字符串总长度
// 输出:18
Integer length = Stream.of(str.split(" ")).map(s -> s.length())
        .reduce(0, (s1, s2) -> s1 + s2);
System.out.println(length);

// 取长度最大的单词
// 输出:xing
Optional<String> max = Stream.of(str.split(" "))
        .max((s1, s2) -> s1.length() - s2.length());
System.out.println(max.get());

// 使用findFirst取第一个元素,取到则中断操作
// 输出:bu
Optional<String> findFirst = list.stream().findFirst();
System.out.println(findFirst.get());


static class  Student {
    /**
    * id
    */
    private Integer id;
    /**
    * 学生姓名
    */
    private String name;
    /**
    * 性别
    */
    private String sex;
    /**
    * 年龄
    */
    private Integer age;
    /**
    * 分数
    */
    private Integer score;

    /**
    * 籍贯
    */
    private String area;

    public Student(Integer id, String name, String sex, Integer age, Integer score, String area) {
        this.id = id;
        this.name = name;
        this.sex = sex;
        this.age = age;
        this.score = score;
        this.area = area;
    }
}

List<Student> studentList = new ArrayList<Student>();
studentList.add(new Student(1,"小明", "男", 18, 100, "江西"));
studentList.add(new Student(2,"小花", "女", 17, 90, "安徽"));
studentList.add(new Student(3,"小虎", "男", 21, 80, "黑龙江"));
studentList.add(new Student(4,"小军", "男", 20, 85, "黑龙江"));

// 1.toList()/toSet()/toMap() (重组)
// 因为 Stream 流不储存数据,所以当流中的数据完成处理之后,需要将流中的数据重组到新的集合里

// 1.获取studentList中所有的籍贯
List<String> areaList1 = studentList.stream().map(Student :: getArea).collect(Collectors.toList());
System.out.println("areaList1:" + areaList1.toString());
// 2.获取studentList中所有的籍贯,并去重
Set<String> areaList2 = studentList.stream().map(Student :: getArea).collect(Collectors.toSet());
System.out.println("areaList2:" + areaList2.toString());
// 3.将studentList转成map
Map<Integer, Student> studentMap = studentList.stream().collect(Collectors.toMap(Student::getId, o -> o));
System.out.println("studentMap:" + studentMap);

// 2.filter()(过滤)
// 过滤出我们想要的数据

// 1.获取小明的信息
List<Student> xmStudent = studentList.stream().filter(o -> o.getName().equals("小明")).collect(Collectors.toList());
System.out.println("获取小明的信息:" + xmStudent.toString());
// 2.获取年龄大于18的学生名称
List<String> filterList = studentList.stream().filter(o -> o.getAge() > 18).map(Student::getName)
        .collect(Collectors.toList());
System.out.println("获取年龄大于18的学生名称:" + filterList);
3.groupingBy()(分组)和 partitioningBy()(分区)
// 1.按地区分组,得到学生id的Set集合
Map<String, Set<Integer>> areaIdSetMap = studentList.stream().collect(Collectors.groupingBy(Student::getArea, Collectors.mapping(Student::getId, Collectors.toSet())));
System.out.println("按地区分组,得到学生id的Set集合:" + areaIdSetMap);

// 2.按性别分组
Map<String, List<Student>> group1 = studentList.stream().collect(Collectors.groupingBy(Student::getSex));
System.out.println("按性别分组:" + group1);

// 3.将员工先按性别分组,再按籍贯分组
Map<String, Map<String, List<Student>>> group2 = studentList.stream().collect(Collectors.groupingBy(Student::getSex, Collectors.groupingBy(Student::getArea)));
System.out.println("将员工先按性别分组,再按籍贯分组:" + group2);

// 4.将学生按是否大于80分,分成两个map
Map<Boolean, List<Student>> partMap = studentList.stream().collect(Collectors.partitioningBy(x -> x.getScore() > 80));
System.out.println("将学生按是否大于80分,分成两个map:" + partMap);
4.count()/averagingXxx()/maxBy()(统计操作)
// 1.求学生集合总条数
Long count = studentList.stream().collect(Collectors.counting());
System.out.println("求学生集合总条数:" + count);
// 2.求学生的平均分数
Double averageScore = studentList.stream().collect(Collectors.averagingDouble(Student::getScore));
System.out.println("求学生的平均分数:" + averageScore);
// 3.求学生中的最高分
Optional<Integer> maxScore = studentList.stream().map(Student::getScore).collect(Collectors.maxBy(Integer::compare));
System.out.println("求学生中的最高分:" + maxScore.get());
// 4.一次性统计关于分数的所有信息
DoubleSummaryStatistics collect = studentList.stream().collect(Collectors.summarizingDouble(Student::getScore));
System.out.println("一次性统计关于分数的所有信息:" + collect);
// 5.统计总分前3的学生姓名并打印出来
Map<String, Integer> map = new HashMap();
studentList.stream().collect(Collectors.groupingBy(Student::getName))
        .forEach((k, v) -> map.put(k, v.stream().collect(Collectors.summingInt(Student::getScore))));
map.keySet().stream().sorted(Comparator.comparing(item->map.get(item)).reversed()).limit(3).collect(Collectors.toList()).forEach(item-> System.out.println(item));

// 5.join() (连接)和reduce() (浓缩)
// join():将元素用连接符连接起来 

// reduce():将流浓缩成一个值,用来求和、求最大值等操作

// 1.获取所有学生的姓名,用逗号分割
String joinNames = studentList.stream().map(o -> o.getName()).collect(Collectors.joining(","));
System.out.println("获取所有学生的姓名,用逗号分割:" + joinNames);

// 2.获取学生的年龄总和
Optional<Integer> sum = studentList.stream().map(Student::getAge).reduce(Integer::sum);
System.out.println("获取学生的年龄总和:" + sum.get());
6.sorted()(排序)
// 1.按分数升序排序
List<String> sortList1 = studentList.stream().sorted(Comparator.comparing(Student::getScore)).map(Student::getName)
        .collect(Collectors.toList());
System.out.println("按分数升序排序:" + sortList1);

// 2.按分数降序排序
List<String> sortList2 = studentList.stream().sorted(Comparator.comparing(Student::getScore).reversed())
        .map(Student::getName).collect(Collectors.toList());
System.out.println("按分数降序排序:" + sortList2);
// 3.先按分数再按年龄升序排序
List<String> sortList3 = studentList.stream()
        .sorted(Comparator.comparing(Student::getScore).thenComparing(Student::getAge)).map(Student::getName)
        .collect(Collectors.toList());
System.out.println("先按分数再按年龄升序排序:" + sortList3);

# To Be Continued!😎

Last Updated: 12/10/2021, 9:19:33 AM