簡體   English   中英

使用通配符類型減少流

[英]Stream reduction with wildcard types

我正在試驗Stream.reduce() ,並且遇到了類型系統的障礙。 這是一個玩具示例:

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

這適用於任何List<Number> ,但如果我想能夠減少一個列表? extends Number ? extends Number 這不編譯:

public static Number reduceNum2(List<? extends Number> 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<CAP#1>) is not applicable
      (argument mismatch; Number cannot be converted to CAP#1)
    method Stream.<U>reduce(U,BiFunction<U,? super CAP#1,U>,BinaryOperator<U>) 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 <U>reduce(U,BiFunction<U,? super T,U>,BinaryOperator<U>)
    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<Integer> )的集合?


如果有幫助,這里有一個更實際的例子,同樣無法編譯:

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

問題實際上不在於? extends ? extends ,但使用identity參數reduce() 正如 Sotirios Delimanolis 建議的那樣,您可以指定有界類型N extends Number ,但前提是標識值為null

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

這是因為通配符和有界方法都無法確定標識參數是否與列表元素的類型相同(除非它是所有類型共享的null )。

解決方法是使用三參數的reduce()方法,它允許您將結果視為不同的類型(即使它不是真正的)。

這是Number示例:

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

這是Set示例:

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

由於accumulatorcombiner是不同的類型,因此您必須復制歸約函數,這有點煩人。 您大概可以在變量中定義一次,然后通過不安全的強制轉換將其傳遞給兩者,但我不確定這是否是一種改進。 無論如何,使用方法引用可能是正確的方法。

我有一個類似的問題,並設法解決如下

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

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM