数値のがあるとします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: シンボルが見つかりません。
シンボル: メソッド intValue()
場所: java.lang.Object 型の変数番号
number
コンパイラ エラーから、ラムダ内の がObject
ではなくとして扱われていることは明らかですNumber
。
さて、私の質問は次の通りです。
- のワイルドカード バージョンを収集するときに
List
、 の非ワイルドカード バージョンのように動作しないのはなぜですかList
? number
ラムダ内の変数がObject
ではなく とみなされるのはなぜですかNumber
?
ベストアンサー1
型推論が正しく行われないのです。型引数を明示的に指定すると、期待どおりに動作します。
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 でケースが壊れていたため取り消されたため、8 ではより保守的な修正を行い、9 では完全な修正を行うことにしました。
どうやら修正はまだプッシュされていないようです。(ジョエル・ボルグレン・フランク正しい方向を指し示してくれてありがとう。