Java 8 Stream流API解析

拼搏现实的明天。 2022-10-07 12:54 297阅读 0赞

1. Stream流简介

Java 8 API添加了一个新的抽象称为流Stream,可以以一种声明的方式处理数据。

Stream流使用一种类似用 SQL 语句从数据库查询数据的直观方式来提供一种对 Java 集合运算和表达的高阶抽象。

Stream流特点:

  • 不是数据结构,不会保存数据,只是在原数据集上定义了一组操作
  • 惰性求值,流在中间处理过程中,只是对操作进行了记录,并不会立即执行,需要等到执行终止操作的时候才会进行实际的计算
  • Stream不保存数据,它会将操作后的数据保存到另外一个对象中

一般使用步骤:

  1. 获取数据源,创建流
  2. 中间操作(Intermediate):可以有多个,每次返回一个新的流,可进行链式操作
  3. 终端操作(Terminal):只能有一个,每次执行完,这个流也就用光光了,无法执行下一个操作

2. Stream流的创建方式

  1. package com.jbp.controller;
  2. import java.io.BufferedReader;
  3. import java.io.FileNotFoundException;
  4. import java.io.FileReader;
  5. import java.util.Arrays;
  6. import java.util.List;
  7. import java.util.Random;
  8. import java.util.regex.Pattern;
  9. import java.util.stream.Stream;
  10. /** * @ClassName: StreamAPI * @description: * @author: JiangBeiPing * @create: 2021-06-18 11:07 * @Version: 1.0 **/
  11. public class StreamAPI {
  12. public static void main(String[] args) throws FileNotFoundException {
  13. // 1.Stream创建
  14. // 数组 -----------------------------------------
  15. // 数组:Arrays.stream(T array)
  16. Integer[] array = { 1, 2, 3};
  17. Stream<Integer> integerStream1 = Arrays.stream(array);
  18. // 集合 Collection ------------------------------
  19. List<Integer> list = Arrays.asList(array);
  20. // 集合: Collection.stream()
  21. Stream<Integer> listStream1 = list.stream();
  22. // 集合: Collection.parallelStream() 默认使用的是 ForkJoinPool.commonPool()线程池
  23. Stream<Integer> listStream2 = list.parallelStream();
  24. // BufferedReader -------------------------------
  25. BufferedReader reader = new BufferedReader(new FileReader("xxx"));
  26. Stream<String> linesStream = reader.lines();
  27. // 字符串处理 String ------------------------------
  28. String str = "1,2,3";
  29. Pattern pattern = Pattern.compile(",");
  30. Stream<String> stringStream = pattern.splitAsStream(str);
  31. // Stream自带的静态方法 ----------------------------
  32. // Stream.of()
  33. Stream<Integer> integerStream = Stream.of(1, 2, 3);
  34. // Stream.iterate()
  35. Stream<Integer> integerStream2 = Stream.iterate(1, s -> (s + 2));
  36. // Stream.generate()
  37. Stream<Double> generate = Stream.generate(Math::random);
  38. }
  39. }

3. Stream流API分类






















































































































API 类型 返回类型 使用的类型/函数式接口 函数描述符
filter 中间操作(Intermediate) Stream < T > Predicate < T > T - > boolean
distinct 中间操作(Intermediate,有状态 - 无界) Stream < T >
skip 中间操作(Intermediate,有状态 - 有界) Stream < T > long
map 中间操作(Intermediate) Stream < T > Function < T,R > T - > R
flatMap 中间操作(Intermediate) Stream < T > Function < T,Stream < R > > T - > Stream < R >
sorted 中间操作(Intermediate,有状态 - 无界) Stream < T > Compartor < T > (T,T) - > int
anyMatch 终端操作(Terminal) boolean Predicate < T > T - > boolean
noneMatch 终端操作(Terminal) boolean Predicate < T > T - > boolean
allMatch 终端操作(Terminal) boolean Predicate < T > T - > boolean
findAny 终端操作(Terminal) Optional < T >
findFirst 终端操作(Terminal) Optional < T >
forEach 终端操作(Terminal) void Consumer < T > T - > void
collect 终端操作(Terminal) R Collector <T,A,R>
reduce 终端操作(Terminal,有状态 - 有界) Optional < T > BinaryOperator < T > (T,T) - > T
count 终端操作(Terminal) long
  • 有状态:指该操作只有拿到所有元素之后才能继续下去
  • 无状态:指元素的处理不受之前元素的影响

4. Stream流中间操作API

4.1 filter 过滤

将结果为false的元素过滤掉,为true会把当前元素会保留下来。

数值型过滤:

  1. Integer[] array = { 1, 2, 3};
  2. Stream<Integer> integerStream1 = Arrays.stream(array);
  3. Stream<Integer> filterStream = integerStream1.filter(i -> i == 2);
  4. System.out.println(Arrays.toString(filterStream.toArray())); // [2]

对象型过滤:

  1. User user1 = new User(1,"张三");
  2. User user2 = new User(2,"李四");
  3. User user3 = new User(3,"王五");
  4. ArrayList<User> users = new ArrayList<>();
  5. users.add(user1);
  6. users.add(user2);
  7. users.add(user3);
  8. Stream<User> userStream = users.stream().filter(user -> "王五".equals(user.getName()));
  9. System.out.println(Arrays.toString(userStream.toArray())); // [StreamAPI.User(id=3, name=王五)]

4.2 map 映射

接收一个函数作为参数,该函数会被应用到每个元素上,并将其映射成一个新的元素

数组类型映射:

  1. Integer[] array = { 1, 2, 3};
  2. Stream<Integer> integerStream1 = Arrays.stream(array);
  3. Stream<Integer> mapStream = integerStream1.map(i -> {
  4. i++;
  5. return i;
  6. });
  7. System.out.println(Arrays.toString(mapStream.toArray())); // [2, 3, 4]

对象类型映射:

  1. User user1 = new User(1,"张三");
  2. User user2 = new User(2,"李四");
  3. User user3 = new User(3,"王五");
  4. ArrayList<User> users = new ArrayList<>();
  5. users.add(user1);
  6. users.add(user2);
  7. users.add(user3);
  8. Stream<User> mapStream2 = users.stream().map(user -> {
  9. String name = user.getName();
  10. user.setName(name + "xx");
  11. return user;
  12. });
  13. System.out.println(Arrays.toString(mapStream2.toArray())); // [StreamAPI.User(id=1, name=张三xx), StreamAPI.User(id=2, name=李四xx), StreamAPI.User(id=3, name=王五xx)]

4.3 flatMap 映射

接收一个函数作为参数,将流中的每个值都换成另一个流,然后把所有流连接成一个流

数组类型映射:

  1. Integer[] array = { 1, 2, 3};
  2. Integer[] array2 = { 8, 9, 10};
  3. Stream<Integer> integerStream1 = Arrays.stream(array);
  4. // 每个元素 i 转换为一次新的stream流 并返回
  5. Stream<Integer> mapStream = integerStream1.flatMap(i -> {
  6. Stream<Integer> stream = Arrays.stream(array2);
  7. return stream;
  8. });
  9. System.out.println(Arrays.toString(mapStream.toArray())); // [8, 9, 10, 8, 9, 10, 8, 9, 10]

对象类型映射:

  1. User user1 = new User(1,"张三");
  2. User user2 = new User(2,"李四");
  3. User user3 = new User(3,"王五");
  4. ArrayList<User> users = new ArrayList<>();
  5. users.add(user1);
  6. users.add(user2);
  7. users.add(user3);
  8. Stream<String> stringStream = users.stream().flatMap(user -> {
  9. String name = user.getName();
  10. String[] split = name.split("");
  11. Stream<String> stream = Arrays.stream(split);
  12. return stream;
  13. });
  14. System.out.println(Arrays.toString(stringStream.toArray())); // [张, 三, 李, 四, 王, 五]

4.4 forEach 遍历

  1. Integer[] array = { 1, 2, 3};
  2. Stream<Integer> integerStream1 = Arrays.stream(array);
  3. // 遍历array数组 ---> 1,2,3
  4. integerStream1.forEach(i -> {
  5. System.out.println(i);
  6. });

4.5 limit 截取

保留前n个元素

  1. Integer[] array = { 1, 2, 3};
  2. Stream<Integer> integerStream1 = Arrays.stream(array);
  3. Stream<Integer> integerStream = integerStream1.limit(2);
  4. System.out.println(Arrays.toString(integerStream.toArray())); // [1, 2]

4.6 skip 跳过

跳过前n个元素

  1. Integer[] array = { 1, 2, 3};
  2. Stream<Integer> integerStream1 = Arrays.stream(array);
  3. Stream<Integer> integerStream = integerStream1.skip(2);
  4. System.out.println(Arrays.toString(integerStream.toArray())); // [3]

4.7 distinct 去重

剔除重复元素

  1. Integer[] array = { 1, 2, 3,3};
  2. Stream<Integer> integerStream1 = Arrays.stream(array);
  3. Stream<Integer> integerStream = integerStream1.distinct();
  4. System.out.println(Arrays.toString(integerStream.toArray())); // [1, 2, 3]

4.8 sorted 排序

  • sorted():自然排序,流中元素需实现Comparable接口
  • sorted(Comparator com):定制排序,自定义Comparator排序器

    Integer[] array = { 1, 2, 3,8,5};
    Stream integerStream1 = Arrays.stream(array);
    Stream integerStream = integerStream1.sorted();
    System.out.println(Arrays.toString(integerStream.toArray())); // [1, 2, 3, 5, 8]

    Integer[] array = { 1, 2, 3,8,5};
    Stream integerStream1 = Arrays.stream(array);
    // 倒序排列
    Stream integerStream = integerStream1.sorted((i1,i2) -> {

    1. return i2 - i1;
    2. });

    System.out.println(Arrays.toString(integerStream.toArray())); // [8, 5, 3, 2, 1]

4.9 peek 消费

如同于map,能得到流中的每一个元素。但map接收的是一个Function表达式,有返回值;而peek接收的是Consumer表达式,没有返回值

  1. User user1 = new User(1,"张三");
  2. User user2 = new User(2,"李四");
  3. User user3 = new User(3,"王五");
  4. ArrayList<User> users = new ArrayList<>();
  5. users.add(user1);
  6. users.add(user2);
  7. users.add(user3);
  8. Stream<User> peek = users.stream().peek(user -> {
  9. String name = user.getName();
  10. user.setName(name + "v");
  11. });
  12. System.out.println(Arrays.toString(peek.toArray())); // [StreamAPI.User(id=1, name=张三v), StreamAPI.User(id=2, name=李四v), StreamAPI.User(id=3, name=王五v)]

5. Stream流终止操作API

5.1 匹配、聚合操作

匹配:

  • anyMatch(),只要有一个元素匹配传入的条件,就返回 true
  • allMatch(),只有有一个元素不匹配传入的条件,就返回 false;如果全部匹配,则返回true
  • noneMatch(),只要有一个元素匹配传入的条件,就返回 false;如果全部匹配,则返回 true

    Integer[] array = { 1, 2, 3,8,5};
    Stream integerStream1 = Arrays.stream(array);
    boolean anyMatch = integerStream1.anyMatch(i -> i > 6); // true
    System.out.println(anyMatch);
    boolean allMatch = integerStream1.allMatch(i -> i > 6); // false
    System.out.println(allMatch);
    boolean noneMatch = integerStream1.noneMatch(i -> i > 6); // false
    System.out.println(noneMatch);

聚合:

  • findFirst:返回流中第一个元素
  • findAny:返回流中的任意元素
  • count:返回流中元素的总个数
  • max:返回流中元素最大值
  • min:返回流中元素最小值

    Integer[] array = { 1, 2, 3,8,5};
    Stream integerStream1 = Arrays.stream(array);
    Optional first = integerStream1.findFirst();// 1
    Optional any = integerStream1.findAny();
    long count = integerStream1.count(); // 5
    Optional max = integerStream1.max(Integer::compareTo);// Optional[8]
    Optional min = integerStream1.min(Integer::compareTo);//Optional[1]

5.2 归并

合并流的元素并产生单个值

  • Optional reduce(BinaryOperator accumulator)
  • T reduce(T identity, BinaryOperator accumulator)
  • < U > U reduce(U identity,BiFunction accumulator,BinaryOperator combiner)

identity = 默认值或初始值

BinaryOperator = 函数式接口,取两个值并产生一个新值。(注: java Function 函数中的 BinaryOperator 接口用于执行 lambda 表达式并返回一个 T 类型的返回值)

  1. Integer[] array = { 1, 2, 3,8,5};
  2. int sum = 0;
  3. for (Integer i : array) {
  4. sum += i;
  5. }
  6. System.out.println(sum); // 19
  7. Stream<Integer> integerStream1 = Arrays.stream(array);
  8. Integer reduce = integerStream1.reduce(0, (a, b) -> a + b);
  9. System.out.println(reduce);// 19

6. Stream流收集器collect

集合、聚合收集:

  1. User user1 = new User(1,"张三");
  2. User user2 = new User(2,"李四");
  3. User user3 = new User(3,"王五");
  4. ArrayList<User> users = new ArrayList<>();
  5. users.add(user1);
  6. users.add(user2);
  7. users.add(user3);
  8. // list
  9. List<Integer> list = integerStream1.collect(Collectors.toList());
  10. // set
  11. Set<Integer> set = integerStream1.collect(Collectors.toSet());
  12. // map key不能相同
  13. Map<Integer, String> map = users.stream().collect(Collectors.toMap(User::getId, User::getName));
  14. // 获取users元素个数
  15. Long count = users.stream().collect(Collectors.counting());
  16. // 获取users集合id最大值
  17. Optional<Integer> max = users.stream().map(User::getId).collect(Collectors.maxBy(Integer::compare));
  18. // 获取users集合id最小值
  19. Optional<Integer> min = users.stream().map(User::getId).collect(Collectors.minBy(Integer::compare));
  20. // 获取users集合所有id的和
  21. Integer id = users.stream().collect(Collectors.summingInt(User::getId));
  22. // 获取users集合所有id的平均值
  23. Double average = users.stream().collect(Collectors.averagingDouble(User::getId));

字符串拼接:

  1. String s = users.stream().map(User::getName).collect(Collectors.joining(",", "{", "}"));// {张三,李四,王五}

分组、分区和归并:

  1. User user1 = new User(1,"张三");
  2. User user2 = new User(2,"李四");
  3. User user3 = new User(2,"王五");
  4. ArrayList<User> users = new ArrayList<>();
  5. users.add(user1);
  6. users.add(user2);
  7. users.add(user3);
  8. // 按照id分组
  9. Map<Integer, List<User>> group = users.stream().collect(Collectors.groupingBy(User::getId));// {1=[StreamAPI.User(id=1, name=张三)], 2=[StreamAPI.User(id=2, name=李四), StreamAPI.User(id=2, name=王五)]}
  10. // 多重分组:先按照名字分,再按照id分
  11. Map<String, Map<Integer, List<User>>> map = users.stream().collect(Collectors.groupingBy(User::getName, Collectors.groupingBy(User::getId)));//{李四={2=[StreamAPI.User(id=2, name=李四)]}, 张三={1=[StreamAPI.User(id=1, name=张三)]}, 王五={2=[StreamAPI.User(id=2, name=王五)]}}
  12. // 按照id分区:大于1为一部分,小于等于1为一部分
  13. Map<Boolean, List<User>> collect = users.stream().collect(Collectors.partitioningBy(user -> user.getId() > 1));//{false=[StreamAPI.User(id=1, name=张三)], true=[StreamAPI.User(id=2, name=李四), StreamAPI.User(id=2, name=王五)]}
  14. // 归并:计算users集合的id之和
  15. Optional<Integer> sum = users.stream().map(User::getId).collect(Collectors.reducing(Integer::sum));//Optional[5]

发表评论

表情:
评论列表 (有 0 条评论,297人围观)

还没有评论,来说两句吧...

相关阅读