我想对一个整数列表求和。它的工作原理如下,但是语法感觉不太对。代码可以优化吗?
Map<String, Integer> integers; integers.values().stream().mapToInt(i -> i).sum();
从文档
< 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);
当然,这样的操作可以很容易地实现为简单的顺序循环,如:
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一起使用。
Collectors.summingInt()
summingLong()
mapToLong
第三个选择:Java 8引入了一个非常有效的LongAdder累加器,旨在加快并行流和多线程环境中的汇总速度。这里有一个例子:
LongAdder
LongAdder a = new LongAdder(); map.values().parallelStream().forEach(a::add); sum = a.intValue();
这将工作,但i -> i正在做一些自动开箱,这就是为什么它“感觉”;奇怪。mapToInt将流转换为原始int值元素的IntStream。下面的任何一个都可以工作,并且更好地解释编译器在你的原始语法下所做的事情:
i -> i
mapToInt
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()来对一个整数列表求和。
reduce()
int sum = integers.values().stream().reduce(0, Integer::sum);
这将是int类型数组的最短方法(对于long数组LongStream,对于double数组DoubleStream等等)。不过,并不是所有的基元整数或浮点类型都有Stream实现。
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
summarizingInt
int sum = numberList.stream().collect(Collectors.summarizingInt(Integer::intValue)).getSum();
使用reduce
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()的正常流。我猜他们是被迫这么做的因为泛型的工作方式。
List<Integer>#stream()
这些正常的流是泛型对象,所以没有像sum()等专门的方法,所以你必须使用奇怪的re-stream "看起来像一个no-op"默认转换到这些方法….mapToInt(i -> i)。
sum()
.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),并将其作为下一个流块的当前值,直到所有部分结果都被处理完毕。
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();