使用通配符类型减少流

我正在尝试使用Stream.reduce() ,并且遇到了类型系统的问题。 这是一个玩具示例:

 public static Number reduceNum1(List nums) { return nums.stream().reduce(0, (a, b) -> a); } 

这适用于任何List ,但如果我希望能够减少列表,该? extends Number ? extends Number ? 这不编译:

 public static Number reduceNum2(List nums) { return nums.stream().reduce((Number)0, (a, b) -> a); } 

有错误:

 ReduceTest.java:72: error: no suitable method found for reduce(Number,(a,b)->a) return nums.stream().reduce((Number)0, (a, b) -> a); ^ method Stream.reduce(CAP#1,BinaryOperator) is not applicable (argument mismatch; Number cannot be converted to CAP#1) method Stream.reduce(U,BiFunction,BinaryOperator) is not applicable (cannot infer type-variable(s) U (actual and formal argument lists differ in length)) where U,T are type-variables: U extends Object declared in method reduce(U,BiFunction,BinaryOperator) T extends Object declared in interface Stream where CAP#1 is a fresh type-variable: CAP#1 extends Number from capture of ? extends Number Note: Some messages have been simplified; recompile with -Xdiags:verbose to get full output 

从概念上讲,我得到了为什么会这样。 Stream.reduce()必须返回与源元素相同类型的东西,并且? extends Number ? extends NumberNumber 。 但我不确定如何处理这个案子。 如何减少(或收集)子类的集合(例如List )?


如果它有帮助,这是一个更实际的例子,同样无法编译:

 public static  Set reduceSet1(List<? extends Set> sets) { return sets.stream().reduce(ImmutableSet.of(), (a, b) -> Sets.union(a, b)); } 

问题实际上不是与? extends ? extends ,但使用identity参数reduce() 。 正如Sotirios Delimanolis所建议的那样,您可以指定有界类型N extends Number ,但仅限于标识值为null

 public static  N reduceNum3(List nums) { return nums.stream().reduce(null, (a, b) -> a); } 

这是因为通配符和有界方法都无法确定identity参数是否与列表元素的类型相同(除非它是null ,所有类型共享)。

解决方法是使用三参数reduce()方法,该方法允许您将结果视为不同的类型(即使它不是真的 )。

这是Number示例:

 public static Number reduceNum4(List nums) { return nums.stream().reduce((Number)0, (a, b) -> a, (a, b) -> a); } 

这是Set示例:

 public static  Set reduceSet2(List> sets) { return sets.stream().>reduce( ImmutableSet.of(), Sets::union, Sets::union); } 

有点烦人的是你必须复制还原function,因为accumulatorcombiner是不同的类型。 你可能会在一个变量中定义它一次并通过一个不安全的演员将它传递给两者,但我不确定这是一个改进。