如何和一个列表的整数与java流?

我想对一个整数列表求和。它的工作原理如下,但是语法感觉不太对。代码可以优化吗?

Map<String, Integer> integers;
integers.values().stream().mapToInt(i -> i).sum();
505960 次浏览

文档

< p >还原操作 约简操作(也称为折叠)获取输入元素序列,并通过重复应用组合操作将它们组合成单个汇总结果,例如找到一组数字的和或最大值,或将元素累加到列表中。streams类有多种形式的一般约简操作,称为reduce()和collect(),以及多种特殊的约简形式,如sum()、max()或count()

当然,这样的操作可以很容易地实现为简单的顺序循环,如:

int sum = 0;
for (int x : numbers) {
sum += x;
}

然而,有很好的理由选择减少操作而不是像上面那样的突变累积。约简不仅“更抽象”——它对整个流而不是单个元素进行操作——而且只要用于处理元素的函数是关联的和无状态的,正确构造的约简操作本质上是可并行的。例如,给定一串数字,我们想求它的和,我们可以这样写:

int sum = numbers.stream().reduce(0, (x,y) -> x+y);

或者:

int sum = numbers.stream().reduce(0, Integer::sum);

这些约简操作可以并行安全地运行,几乎不需要修改:

int sum = numbers.parallelStream().reduce(0, Integer::sum);

所以,对于一个地图,你会使用:

integers.values().stream().mapToInt(i -> i).reduce(0, (x,y) -> x+y);

或者:

integers.values().stream().reduce(0, Integer::sum);

我建议另外两种选择:

integers.values().stream().mapToInt(Integer::intValue).sum();
integers.values().stream().collect(Collectors.summingInt(Integer::intValue));

第二个使用Collectors.summingInt()收集器,还有一个summingLong()收集器,你可以与mapToLong一起使用。


第三个选择:Java 8引入了一个非常有效的LongAdder累加器,旨在加快并行流和多线程环境中的汇总速度。这里有一个例子:

LongAdder a = new LongAdder();
map.values().parallelStream().forEach(a::add);
sum = a.intValue();

这将工作,但i -> i正在做一些自动开箱,这就是为什么它“感觉”;奇怪。mapToInt将流转换为原始int值元素的IntStream。下面的任何一个都可以工作,并且更好地解释编译器在你的原始语法下所做的事情:

integers.values().stream().mapToInt(i -> i.intValue()).sum();
integers.values().stream().mapToInt(Integer::intValue).sum();

你可以使用reduce方法:

long sum = result.stream().map(e -> e.getCreditAmount()).reduce(0L, (x, y) -> x + y);

long sum = result.stream().map(e -> e.getCreditAmount()).reduce(0L, Integer::sum);

可以使用collect方法添加整数列表。

List<Integer> list = Arrays.asList(2, 4, 5, 6);
int sum = list.stream().collect(Collectors.summingInt(Integer::intValue));

你可以使用reduce()来对一个整数列表求和。

int sum = integers.values().stream().reduce(0, Integer::sum);

这将是int类型数组的最短方法(对于long数组LongStream,对于double数组DoubleStream等等)。不过,并不是所有的基元整数或浮点类型都有Stream实现。

IntStream.of(integers).sum();

我已经声明了一个整数列表。

ArrayList<Integer> numberList = new ArrayList<Integer>(Arrays.asList(1, 2, 3, 4, 5));

你可以试试下面这些不同的方法。

使用mapToInt

int sum = numberList.stream().mapToInt(Integer::intValue).sum();

使用summarizingInt

int sum = numberList.stream().collect(Collectors.summarizingInt(Integer::intValue)).getSum();

使用reduce

int sum = numberList.stream().reduce(Integer::sum).get().intValue();

希望这能帮助那些在清单上有物品的人。

如果您有一个对象列表,并且想要对该对象的特定字段求和,请使用下面的方法。

List<ResultSom> somList = MyUtil.getResultSom();
BigDecimal result= somList.stream().map(ResultSom::getNetto).reduce(
BigDecimal.ZERO, BigDecimal::add);

不幸的是,流API看起来只返回来自List<Integer>#stream()的正常流。我猜他们是被迫这么做的因为泛型的工作方式。

这些正常的流是泛型对象,所以没有像sum()等专门的方法,所以你必须使用奇怪的re-stream "看起来像一个no-op"默认转换到这些方法….mapToInt(i -> i)

另一种选择是使用“Eclipse集合"就像一个扩展的java流API

IntLists.immutable.ofAll(integers.values()).sum();

List < Integer > listOfIntegers = List.of(1, 2, 10, 3, 4, 8, 5, 9, 6, 7);


Optional < Integer > maxValue = listOfIntegers
.stream().reduce((partialResult, currentValue) -> Math.max(partialResult, currentValue));


System.out.println("Maximum value : " + maxValue);

输出:最大值:可选[10]

这里还有一个没有考虑到的选项,它反映了多核环境的使用。如果你想利用它的优势,那么应该使用下面的代码,而不是其他提到的解决方案:

int sum = integers.values().parallelStream().mapToInt(Integer::intValue)
.reduce(0, Integer::sum, Integer::sum);

这个解决方案与其他解决方案相似,但请注意reduce中的第三个参数。它告诉编译器如何处理由不同线程在流的不同块中计算的部分摘要。同样,使用parallelStream()代替stream()。在这种情况下,它只是总结。作为第三个参数的另一个选项是(i, j) -> i + j,这意味着它会将流块的值(j)添加到当前值(i),并将其作为下一个流块的当前值,直到所有部分结果都被处理完毕。

即使在使用普通的stream()时,告诉reduce如何处理流块的摘要也是有用的,以防将来有人(或你)想要并行化它。最初的开发是最好的时间,因为之后你需要记住这应该是什么,需要花一些时间来再次理解代码的目的。

当然,除了方法引用运算符,你可以用不同的方言。我更喜欢这种方式,因为它更紧凑,而且仍然易于阅读。

还要记住,这也可以用于更复杂的计算,但始终要注意,不能保证流元素到线程的顺序和部署。

IntStream.of(1, 2, 23).sum();
IntStream.of(1, 2, 23,1, 2, 23,1, 2, 23).max().getAsInt();