news 2026/4/24 17:22:14

Java Lambda stream reduce

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Java Lambda stream reduce

引言

reduce是 Java Stream API 中的一个重要方法,用于将流中的元素反复结合起来,得到一个值。它常用于聚合、累加、拼接等操作。下面是详细说明:

1. 基本语法

有三种常用形式:

1.1 无初始值(返回 Optional)

Optional<T> reduce(BinaryOperator<T> accumulator)
  • 适用于流可能为空的情况,返回Optional<T>
  • accumulator是一个二元函数,接收两个流元素,返回一个合并后的结果。

示例:求最大值

List<Integer> list = Arrays.asList(1, 3, 2, 5, 4); Optional<Integer> max = list.stream().reduce(Integer::max); max.ifPresent(System.out::println); // 输出5

1.2 有初始值(返回 T)

T reduce(T identity, BinaryOperator<T> accumulator)
  • identity是初始值(如0、""等)。
  • 返回类型是 T,流为空时直接返回identity

示例:求和

List<Integer> list = Arrays.asList(1, 2, 3, 4, 5); int sum = list.stream().reduce(0, Integer::sum); System.out.println(sum); // 输出15

1.3 三参数(并行流用得多)

<U> U reduce(U identity, BiFunction<U, ? super T, U> accumulator, BinaryOperator<U> combiner)
  • 用于并行流,accumulator负责每个元素的归约,combiner负责合并各线程的结果。

示例:字符串拼接

List<String> list = Arrays.asList("a", "b", "c"); String result = list.stream().reduce( "", (s1, s2) -> s1 + s2, // accumulator (s1, s2) -> s1 + s2 // combiner ); System.out.println(result); // 输出abc

2. 典型用法

求积

int product = Arrays.asList(1, 2, 3, 4).stream().reduce(1, (a, b) -> a * b); System.out.println(product); // 输出24

拼接字符串

String concat = Arrays.asList("a", "b", "c").stream().reduce("", (a, b) -> a + b); System.out.println(concat); // 输出abc

找最小值

Optional<Integer> min = Arrays.asList(5, 2, 8, 1).stream().reduce(Integer::min); min.ifPresent(System.out::println); // 输出1

3. 注意事项

  • 如果流为空,无初始值reduce返回Optional.empty,要注意判空。
  • 有初始值时,结果类型与初始值类型一致,流为空时直接返回初始值。
  • 对于并行流,三参数形式效率更高。
  • reduce适合用于聚合操作,简单计数、求和可直接用countsummaxmin等方法。

4. 高级用法举例

4.1 统计对象属性之和

比如有一个对象列表,统计某个字段的总和:

class Person { String name; int age; // 构造方法和getter略 } List<Person> people = Arrays.asList( new Person("A", 20), new Person("B", 30), new Person("C", 25) ); int totalAge = people.stream() .map(Person::getAge) .reduce(0, Integer::sum); System.out.println(totalAge); // 输出75

4.2 归约为集合(不推荐,推荐用 collect)

虽然可以用 reduce 拼接集合,但推荐用collect。下面是用 reduce 实现:

List<Integer> list = Arrays.asList(1, 2, 3, 4); List<Integer> result = list.stream().reduce( new ArrayList<Integer>(), (acc, item) -> { acc.add(item); return acc; }, (acc1, acc2) -> { acc1.addAll(acc2); return acc1; } ); System.out.println(result); // 输出[1, 2, 3, 4]

注意:这种写法在并行流下可能有线程安全问题,推荐使用collect(Collectors.toList())

4.3 复杂对象归约

比如合并两个对象:

class Stat { int count; int sum; // 构造、getter、setter略 } List<Stat> stats = Arrays.asList( new Stat(1, 10), new Stat(2, 20), new Stat(3, 30) ); Stat total = stats.stream().reduce( new Stat(0, 0), (s1, s2) -> new Stat(s1.count + s2.count, s1.sum + s2.sum) ); System.out.println(total.count); // 输出6 System.out.println(total.sum); // 输出60

5. 常见误区

  1. reduce不是万能的聚合工具
    对于集合归约、分组等复杂操作,优先考虑collect,如Collectors.groupingByCollectors.toList等。

  2. 并行流下要注意可变对象
    如果 identity 是可变对象(如 ArrayList),并行流下可能导致线程安全问题。

  3. 初始值的选择很重要
    初始值应为归约运算的单位元(如加法用0,乘法用1,字符串拼接用"")。


6. 性能建议

  • 对于简单聚合(求和、求最大/最小),用sum()max()min()等内置方法更简洁高效。
  • 对于复杂归约,优先用collect,如Collectors.toList()Collectors.toMap()Collectors.groupingBy()

8. 总结一张表

reduce形式适用场景返回值类型是否可并行
reduce(BinaryOperator)流可能为空Optional
reduce(identity, BinaryOperator)简单聚合T
reduce(identity, accumulator, combiner)并行流复杂归约U

7. 总结

  • reduce可以实现各种聚合、归约操作。
  • 三种常用形式:无初始值、有初始值、三参数(并行流)。
  • 常见场景:求和、求积、拼接、最大/最小值等。
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!