1. 简介

在本篇教程中,我们将介绍使用 Java Stream API 对整数列表进行求和的各种方法。

虽然示例中我们以整型(Integer)为主,但同样的思路也适用于 LongDouble 类型的数据。

2. 使用 Stream.reduce()

Stream.reduce() 是一个终端操作,用于对流中的元素执行归约操作

它接收一个二元操作符(累加器),将流中每个元素依次与前一次的结果进行运算。第一个操作数是初始值或上一次的计算结果,第二个则是当前元素。

✅ 最基础的方式:Lambda 表达式

List<Integer> integers = Arrays.asList(1, 2, 3, 4, 5);
Integer sum = integers.stream()
  .reduce(0, (a, b) -> a + b);

✅ 更优雅的方式:使用内置方法引用

List<Integer> integers = Arrays.asList(1, 2, 3, 4, 5);
Integer sum = integers.stream()
  .reduce(0, Integer::sum);

✅ 自定义方法引用

我们也可以定义自己的加法函数:

public class ArithmeticUtils {

    public static int add(int a, int b) {
        return a + b;
    }
}

然后通过方法引用来调用:

List<Integer> integers = Arrays.asList(1, 2, 3, 4, 5);
Integer sum = integers.stream()
  .reduce(0, ArithmeticUtils::add);

⚠️ 小贴士:如果只是简单的加法,推荐直接使用 Integer::sum,没必要造轮子。

3. 使用 Stream.collect()

另一种常用的求和方式是结合 Collectors 工具类中的 summingInt() 方法:

List<Integer> integers = Arrays.asList(1, 2, 3, 4, 5);
Integer sum = integers.stream()
  .collect(Collectors.summingInt(Integer::intValue));

类似地,Collectors 还提供了 summingLong()summingDouble() 来处理长整型和浮点型数据。

4. 使用 IntStream.sum()

Stream API 提供了 mapToInt() 这个中间操作,可以将普通 Stream 转换为 IntStream,之后就可以直接调用 sum() 方法:

List<Integer> integers = Arrays.asList(1, 2, 3, 4, 5);
Integer sum = integers.stream()
  .mapToInt(Integer::intValue)
  .sum();

同理,还有 mapToLong()mapToDouble() 可供选择。

5. 处理 Map 中的值求和

假设我们有一个 Map<Object, Integer> 结构,要对其 value 求和,可以先获取 values 流,再进行求和操作:

Integer sum = map.values()
  .stream()
  .mapToInt(Integer::valueOf)
  .sum();

6. 对象字段求和

假设我们有如下对象:

public class Item {

    private int id;
    private Integer price;

    public Item(int id, Integer price) {
        this.id = id;
        this.price = price;
    }

    // Standard getters and setters
}

并创建了一个列表:

Item item1 = new Item(1, 10);
Item item2 = new Item(2, 15);
Item item3 = new Item(3, 25);
Item item4 = new Item(4, 40);

List<Item> items = Arrays.asList(item1, item2, item3, item4);

要计算所有 price 字段的总和,我们需要先使用 map() 提取出 price 值,再进行求和:

使用 reduce + 方法引用

Integer sum = items.stream()
  .map(x -> x.getPrice())
  .reduce(0, Integer::sum);

使用 reduce + Lambda

Integer sum = items.stream()
  .map(item -> item.getPrice())
  .reduce(0, (a, b) -> a + b);

使用 collect + Collectors.summingInt

Integer sum = items.stream()
  .map(x -> x.getPrice())
  .collect(Collectors.summingInt(Integer::intValue));

推荐方式:使用 mapToInt + sum()

Integer sum = items.stream()
  .mapToInt(x -> x.getPrice())
  .sum();

✅ 简单粗暴,性能也最优。

7. 字符串中提取数字求和

如果我们有一个字符串包含数字,比如:

String string = "Item1 10 Item2 25 Item3 30 Item4 45";

我们可以通过以下步骤完成求和:

  1. 分割字符串为数组;
  2. 过滤出纯数字字符串;
  3. 转换为整数;
  4. 求和;

代码如下:

Integer sum = Arrays.stream(string.split(" "))
    .filter((s) -> s.matches("\\d+"))
    .mapToInt(Integer::valueOf)
    .sum();

⚠️ 注意正则表达式 \d+ 匹配的是一个或多个数字字符。

8. 总结

在这篇文章中,我们探讨了多种使用 Java Stream API 对整数列表求和的方法,并将其扩展到以下场景:

  • 对象字段求和;
  • Map 值求和;
  • 字符串中数字提取并求和;

这些方法在实际开发中非常常见,掌握它们能让你写出更简洁高效的代码。

📌 完整代码示例可在 GitHub 获取:https://github.com/eugenp/tutorials/tree/master/core-java-modules/core-java-streams


原始标题:Summing Numbers with Java Streams