List
の数字があると仮定します。 List
の値は、タイプInteger
、Double
などにすることができます。このようなList
を宣言する場合、ワイルドカード(?
)を使用して、または使用せずに宣言できますワイルドカード。
final List<Number> numberList = Arrays.asList(1, 2, 3D);
final List<? extends Number> wildcardList = Arrays.asList(1, 2, 3D);
それで、stream
をList
とcollect
を介してMap
にしたいのは、Collectors.toMap
を使用して(明らかに、以下のコードは問題を説明するための例にすぎません) 。 numberList
をストリーミングすることから始めましょう:
final List<Number> numberList = Arrays.asList(1, 2, 3D, 4D);
numberList.stream().collect(Collectors.toMap(
// Here I can invoke "number.intValue()" - the object ("number") is treated as a Number
number -> Integer.valueOf(number.intValue()),
number -> number));
しかし、私はwildcardList
で同じ操作を行うことはできません:
final List<? extends Number> wildCardList = Arrays.asList(1, 2, 3D);
wildCardList.stream().collect(Collectors.toMap(
// Why is "number" treated as an Object and not a Number?
number -> Integer.valueOf(number.intValue()),
number -> number));
コンパイラは、number.intValue()
の呼び出しに対して次のメッセージを表示して不平を言っています。
Test.Java:シンボルが見つかりません
symbol:メソッドintValue()
location:タイプJava.lang.Objectの可変数
コンパイラエラーから、ラムダのnumber
がObject
としてではなくNumber
として扱われていることは明らかです。
だから、今私の質問に:
List
を収集する場合、ワイルドカード以外のバージョンのList
のように機能しないのはなぜですか?number
変数がObject
ではなくNumber
であると見なされるのはなぜですか?それを正しくしないのは型推論です。 type引数を明示的に指定すると、期待どおりに機能します。
List<? extends Number> wildCardList = Arrays.asList(1, 2, 3D);
wildCardList.stream().collect(Collectors.<Number, Integer, Number>toMap(
number -> Integer.valueOf(number.intValue()),
number -> number));
これは既知のjavacバグです。 推論はキャプチャ変数を上限にマップすべきではありません 。マウリツィオシマダモアによると、ステータスは、
8で問題が発生したため修正が試みられてバックアウトされたため、9ですべてを実行しながら8でより保守的な修正を行った
どうやら、修正プログラムはまだプッシュされていません。 ( JoelBorggrén-Franck に感謝します。私を正しい方向に向けてくれました。)
List<? extends Number> wildcardList
形式の宣言は、「Number
またはNumber
のサブクラスである不明なタイプのリスト」を意味します。興味深いことに、未知のタイプが名前で参照されている場合、未知のタイプを持つ同じ種類のリストが機能します。
static <N extends Number> void doTheThingWithoutWildCards(List<N> numberList) {
numberList.stream().collect(Collectors.toMap(
// Here I can invoke "number.intValue()" - the object is treated as a Number
number -> number.intValue(),
number -> number));
}
ここでは、N
はまだ「Number
である不明な型またはNumber
のサブクラス」ですが、List<N>
を意図したとおりに処理できます。不明なタイプList<? extends Number>
に互換性があるという制約として、List<N>
をextends Number
に問題なく割り当てることができます。
final List<? extends Number> wildCardList = Arrays.asList(1, 2, 3D);
doTheThingWithoutWildCards(wildCardList); // or:
doTheThingWithoutWildCards(Arrays.asList(1, 2, 3D));
型推論に関する章 は読みにくいです。この点でワイルドカードと他のタイプに違いがあるかどうかはわかりませんが、あるべきだとは思いません。っていうことは どちらか コンパイラのバグ または仕様による制限ですが、論理的には、 ワイルドカードが機能しない理由はありません。