给出一个整数列表:
List<Integer> numbers = Arrays.asList(1,2,3);
我为什么不能像numbers.stream().sum();
那样概括它们?
相反,我必须这样做:numbers.stream().mapToInt(e -> e).sum();
我知道mapToInt
会产生IntStream
(原始专业化)。但是我还是不明白。为什么不能对整数求和?我知道此列表具有Integers,并且编译器应该能够执行相同操作。毕竟,它现在可以推断lambda表达式中的类型参数。
好的,一个Integer可以为null,并且求和将失败。但是我可以对此负责并过滤掉null:
numbers.stream().filter(Objects::nonNull).sum();
为什么我不能对整数流求和?
答案 0 :(得分:14)
在stream()
上调用List
将为您提供通用的Stream
,它可以处理任何引用类型,而不仅仅是数字类型。在sum
上包含Stream
方法是没有意义的,因为将URL
,Class
,Thread
之和相加是没有意义的s或任何其他非数字引用类型。
您可以通过调用reduce
对元素求和:
numbers.stream().reduce(0, (a, b) -> a + b)
但这将涉及大量拆箱和装箱。最好对它们进行求和,方法是将其转换为IntStream
上运行的int
,然后调用sum()
(或summaryStatistics()
,其中包括计数,平均值,最大值和最小值以及总数)。
您甚至可以使用IntStream.of
并避免将值装箱一次。
IntStream.of(1, 2, 3).sum()
答案 1 :(得分:3)
Stream<Interger>
和IntStream
实际上是不同的。当numbers.stream()
返回类型为Stream
的对象时,Stream
接口没有像sum
这样的方法。另一面numbers.stream().mapToInt(e -> e)
返回具有IntStream
方法的sum
。
答案 2 :(得分:3)
您不能这样做:
numbers.stream().sum();
因为Stream<T>
是泛型类型,就其而言,它正在处理任何类型的对象。例如可能是Stream<Person>
,Stream<Apple>
等,因此没有必要包含sum
方法。
答案 3 :(得分:2)
我认为您的要求根本无法完成,即使从理论上讲也是如此。
我的意思是stream()
在List
接口上声明,并且返回Stream<E>
。 您知道E
实际上是Integer
,编译器必须推断,这不像编译器可以在以下情况下更改返回类型它可以推断出类型,您仍将获得通用的Stream<E>
。
但是,如果我考虑得更多,那就更糟了,在这种情况下,必须返回BaseStream
和Stream<String>
都将延伸的IntStream
,而{{ 1}}对于sum
没有任何意义。以后的Stream<String>
类型将必须在运行时保留,这样您就知道要返回什么专业化,这显然是不可能的(当然,如果没有无用的见证人,也是不可能的)
如果有一个E
会返回理论上的IntsList
,这确实是可能的,但是在这种情况下会变得一团糟。