51工具盒子

依楼听风雨
笑看云卷云舒,淡观潮起潮落

Java Stream 使用手册

在工作中时常会使用 Java Stream 对集合进行特殊操作,Stream 虽然能简化代码,但是书写以及阅读性不高。故在此记录常用的 Stream 案例以便在未来工作中查阅和使用(复制粘贴😅)

一、Stream 介绍 {#一、Stream-介绍}

Stream 是 Java8 中处理集合的关键抽象概念,它可以指定你希望对集合进行的操作,可以执行非常复杂的查找、过滤和映射数据等操作。

使用Stream API 对集合数据进行操作,就类似于使用 SQL 执行的数据库查询。也可以使用 Stream API 来并行执行操作。简而言之,Stream API 提供了一种高效且易于使用的处理数据的方式。

1.1 Stream 操作流程 {#1.1-Stream-操作流程}

  1. 创建 Stream:一个数据源(如:集合、数组),获取一个流。

  2. 中间操作:一个中间操作链,对数据源的数据进行处理。

  3. 终止操作:一个终止操作,执行中间操作链,并产生结果。

1.2 Stream 的创建 {#1.2-Stream-的创建}

通过 Collection 集合创建

|-----------------|-------------------------------------------------------------------------------------------------------------------------| | 1 2 3 4 | // 获取顺序流 Stream<String> stream = list.stream(); // 获取并行流 Stream<String> parallelStream = list.parallelStream(); |

通过 Arrays 创建

|-------------|---------------------------------------------------------------------------------------------| | 1 2 | String[] arr = {"hello","world","abc"}; Stream<String> stream = Arrays.stream(arr); |

通过 Stream 的静态方法创建

|-------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | 1 2 3 4 5 | Stream<String> stream1 = Stream.of("hello","world","abc"); // 获取无限流,迭代 Stream<Integer> stream2 = Stream.iterate(0,(x) -> x + 2); // 获取无限流,生成 Stream<Integer> stream3 = Stream.generate(() -> (int)(Math.random())); |

1.3 Stream 的中间操作 {#1.3-Stream-的中间操作}

多个中间操作可以连接起来形成一个流水线,除非流水线上触发终止操作,否则中间操作不会执行任何的处理,而在终止操作时一次性全部处理,称为 "惰性求值"。

筛选与切片

| 方法 | 说明 | |---------------------|---------------------------------------------------------| | filter(Predicate p) | 接收 Lambda , 从流中过滤出元素 | | distinct() | 筛选,通过流所生成元素的 hashCode() 和 equals() 去除重复元素 | | limit(long maxSize) | 截断流,使其元素不超过给定数量。 | | skip(long n) | 跳过元素,返回一个扔掉了前 n 个元素的流。若流中元素不足 n 个,则返回一个空流。与 limit(n) 互补 |

|------------------------------------------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | @Test public void test() { List<Person> list = Arrays.asList( new Person(1,"aaa",21), new Person(2,"bbb",22), new Person(3,"ccc",23), new Person(4,"ddd",24), new Person(5,"eee",25) ); // 中间操作 Stream<Person> stream = list.stream() .filter((p) -> p.getAge() > 22) // 过滤得到 id 为 3、4、5 的元素 .skip(1) // 跳过 1 个元素,得到 id 为 4、5 元素 .limit(1); // 指获取 1 个元素,得到 id 为 4 的元素 // 终止操作 stream.forEach(System.out::println); } |

映射

| 方法 | 说明 | |---------------------------------|-----------------------------------------------| | map(Function f) | 接收一个函数作为参数,该函数会被应用到每个元素上,并将其映射成一个新的元素。 | | mapToDouble(ToDoubleFunction f) | 接收一个函数作为参数,该函数会被应用到每个元素上,产生一个新的 DoubleStream。 | | mapToInt(ToIntFunction f) | 接收一个函数作为参数,该函数会被应用到每个元素上,产生一个新的 IntStream。 | | mapToLong(ToLongFunction f) | 接收一个函数作为参数,该函数会被应用到每个元素上,产生一个新的 LongStream。 | | flatMap(Function f) | 接收一个函数作为参数,将流中的每个值都换成另一个流,然后把所有流连接成一个流 |

|---------------------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | 1 2 3 4 5 6 7 8 9 10 11 | @Test public void test() { List<String> list = Arrays.asList("aaa","bbb","ccc"); // 中间操作 Stream<String> stream = list.stream() .map((str) -> str.toUpperCase()); // 将流中所有元素进行转大写操作 // 终止操作 stream.forEach(System.out::println); } |

排序

| 方法 | 说明 | |-------------------------|-------------------| | sorted() | 产生一个新流,其中按自然顺序排序 | | sorted(Comparator comp) | 产生一个新流,其中按比较器顺序排序 |

|------------------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | 1 2 3 4 5 6 7 8 9 10 | @Test public void test() { List<String> list = Arrays.asList("ccc","aaa","bbb"); // 中间操作 Stream<String> stream = list.stream().sorted(); // 自然排序 // 终止操作 stream.forEach(System.out::println); } |

1.4 Stream 的终止操作 {#1.4-Stream-的终止操作}

终止操作会从流的流水线生成结果。其结果可以是任何不是流的值,例如:List、Integer,甚至是 void 。

查找与匹配

| 方法 | 说明 | |------------------------|---------------------------------------------------------------------------| | allMatch(Predicate p) | 检查是否匹配所有元素。 | | anyMatch(Predicate p) | 检查是否至少匹配一个元素。 | | noneMatch(Predicate p) | 检查是否没有匹配所有元素。 | | findFirst() | 返回第一个元素。 | | findAny() | 返回当前流中的任意元素。 | | count() | 返回流中元素总数。 | | max(Comparator c) | 返回流中最大值。 | | min(Comparator c) | 返回流中最小值。 | | forEach(Consumer c) | 内部迭代(使用 Collection 接口需要用户去做迭代,称为外部迭代。相反,Stream API 使用内部迭代------它帮你把迭代做了)。 |

|---------------------------------------------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | @Test public void test() { List<Person> list = Arrays.asList( new Person(1,"aaa",21), new Person(2,"bbb",22), new Person(3,"ccc",23), new Person(4,"ddd",24), new Person(5,"eee",25) ); boolean result = list.stream() .allMatch((p) -> p.getAge() > 22); // 是否所有元素中年龄大于 22 System.out.println(result); Optional<Integer> op = list.stream() .map(Person::getAge) // 获取所有元素的年龄 .max(Integer::compare); // 获取最大年龄 System.out.println(op.get()); } |

归约

| 方法 | 说明 | |----------------------------------|-----------------------------------| | reduce(T iden, BinaryOperator b) | 可以将流中元素反复结合起来,得到一个值,返回 T。 | | reduce(BinaryOperator b) | 可以将流中元素反复结合起来,得到一个值,返回 Optional 。 |

|-------------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | 1 2 3 4 5 6 7 8 | @Test public void test() { List<Integer> list = Arrays.asList(1,2,3,4,5,6,7,8,9,10); Integer result = list.stream().reduce(0, (x,y) -> x + y); // 所有元素进行累加 System.out.println(result); } |

收集

| 方法 | 说明 | |----------------------|-----------------------------------------------------| | collect(Collector c) | 将流转换为其他形式。接收一个 Collector接口的实现,用于给 Stream 中元素做汇总的方法。 |

|------------------------------------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | @Test public void test() { List<Person> list = Arrays.asList( new Person(1,"aaa",21), new Person(2,"bbb",22), new Person(3,"ccc",23), new Person(4,"ddd",24), new Person(5,"eee",25) ); List<String> result = list.stream() .map(Person::getName) // 获取所有元素的名字 .collect(Collectors.toList()); // 将名字从流中放到新的集合中 System.out.println(result); } |

二、案例汇总 {#二、案例汇总}

准备测试数据

|------------------------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | 1 2 3 4 5 6 7 8 9 10 11 12 | List<User> userList = new ArrayList<>(); // id: id,name: 姓名,age: 年龄 User user1 = new User(1, "张三", 26); User user2 = new User(2, "张三", 28); User user3 = new User(3, "李四", 24); User user4 = new User(4, "王五", 30); User user5 = new User(4, "王五2", 31); userList.add(user1); userList.add(user2); userList.add(user3); userList.add(user4); userList.add(user5); |

2.1 获取 id 集合 {#2.1-获取-id-集合}

|-------------|-----------------------------------------------------------------------------------------------------------------------------------------| | 1 2 | List<Integer> idList = userList.stream().map(User::getId).collect(Collectors.toList()); System.out.println("idList:" + idList); |

结果:

|-----------|--------------------------------| | 1 | idList:[1, 2, 3, 4, 4] |

2.2 拼接所有用户姓名 {#2.2-拼接所有用户姓名}

|-------------|-------------------------------------------------------------------------------------------------------------------------------------| | 1 2 | String names = userList.stream().map(User::getName).collect(Collectors.joining(",")); System.out.println("names:" + names); |

结果:

|-----------|-------------------------------| | 1 | names:张三,张三,李四,王五,王五2 |

2.3 年龄递增排序 {#2.3-年龄递增排序}

|-------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------| | 1 2 | List<User> sortList = userList.stream().sorted(Comparator.comparing(User::getAge)).collect(Collectors.toList()); System.out.println("sortList:" + sortList); |

结果:

|-----------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | 1 | sortList:[User [id=3, name=李四, age=24], User [id=1, name=张三, age=26], User [id=2, name=张三, age=28], User [id=4, name=王五, age=30], User [id=4, name=王五2, age=31]] |

如要递减,编写 Comparator.comparing(User::getAge).reversed()

2.4 过滤出年龄大于 30 的用户 {#2.4-过滤出年龄大于-30-的用户}

|-------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------| | 1 2 | List<User> filterList = userList.stream().filter(i -> i.getAge() > 30).collect(Collectors.toList()); System.out.println("filterList:" + filterList); |

结果:

|-----------|----------------------------------------------------| | 1 | filterList:[User [id=4, name=王五2, age=31]] |

2.5 统计年龄小于 30 的用户数量 {#2.5-统计年龄小于-30-的用户数量}

|-------------|--------------------------------------------------------------------------------------------------------------------| | 1 2 | long count = userList.stream().filter(i -> i.getAge() < 30).count(); System.out.println("count:" + count); |

结果:

|-----------|-----------------| | 1 | count:3 |

2.6 获取年龄最大用户 {#2.6-获取年龄最大用户}

|-------------|-----------------------------------------------------------------------------------------------------------------------------------| | 1 2 | User maxUser = userList.stream().max(Comparator.comparing(User::getAge)).get(); System.out.println("maxUser:" + maxUser); |

结果:

|-----------|-----------------------------------------------| | 1 | maxUser:User [id=4, name=王五2, age=31] |

2.7 获取所有用户年龄总和 {#2.7-获取所有用户年龄总和}

|-------------|----------------------------------------------------------------------------------------------------------------------------------------| | 1 2 | Integer totalAge = userList.stream().collect(Collectors.summingInt(User::getAge)); System.out.println("totalAge:" + totalAge); |

结果:

|-----------|----------------------| | 1 | totalAge:139 |

2.8 获取所有用户年龄平均值 {#2.8-获取所有用户年龄平均值}

|-------------|--------------------------------------------------------------------------------------------------------------------------------------------------| | 1 2 | Double averageAge = userList.stream().collect(Collectors.averagingDouble(User::getAge)); System.out.println("averageAge:" + averageAge); |

结果:

|-----------|-------------------------| | 1 | averageAge:27.8 |

2.9 包含集合总数,年龄最大值, 年龄总和, 年龄平均值 {#2.9-包含集合总数,年龄最大值,-年龄总和,-年龄平均值}

|-------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | 1 2 | DoubleSummaryStatistics statistics = userList.stream().collect(Collectors.summarizingDouble(User::getAge)); System.out.println("count:" + statistics.getCount() + ", max:" + statistics.getMax() + ", sum:" + statistics.getSum() + ", average:" + statistics.getAverage()); |

结果:

|-----------|----------------------------------------------------| | 1 | count:5, max:31.0, sum:139.0, average:27.8 |

2.10 List 转成 Map {#2.10-List-转成-Map}

|---------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | 1 2 3 | Map<Integer, User> userMap = userList.stream() .collect(Collectors.toMap(User::getId, Function.identity(), (v1, v2) -> v2)); System.out.println("userMap:" + userMap); |

结果:

|-----------|---------------------------------------------------------------------------------------------------------------------------------------------------| | 1 | userMap:{1=User [id=1, name=张三, age=26], 2=User [id=2, name=张三, age=28], 3=User [id=3, name=李四, age=24], 4=User [id=4, name=王五2, age=31]} |

其中 (v1, v2) -> v2) 表示 v1,v2 相同时 取 v2

2.11 获取名字对应的的 id 集合 {#2.11-获取名字对应的的-id-集合}

同样是 List 转成 Map 。

|---------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | 1 2 3 4 5 6 | Map<String, List<Integer>> userMap = userList.stream() .collect(Collectors.groupingBy( User::getName, Collectors.mapping(User::getId, Collectors.toList())) ); System.out.println("userMap:" + userMap); |

结果:

|-----------|------------------------------------------------------| | 1 | userMap:{李四=[3], 王五2=[4], 张三=[1, 2], 王五=[4]} |

赞(0)
未经允许不得转载:工具盒子 » Java Stream 使用手册