35

の数があるとしListます。の値はなどListの型Integerにすることができます。そのような を宣言する場合、ワイルドカード ( ) を使用して宣言することも、ワイルドカードを使用せずに宣言することもできます。DoubleList?

final List<Number> numberList = Arrays.asList(1, 2, 3D);
final List<? extends Number> wildcardList = Arrays.asList(1, 2, 3D);

だから、今私はを使いたいと思っていstreamます(明らかに、以下のコードは問題を説明するための単なる例です)。ストリーミングすることから始めましょう:ListcollectMapCollectors.toMapnumberList

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()
場所: java.lang.Object 型の変数番号

コンパイラ エラーから、ラムダ内の が としてではなくnumberとして扱われることは明らかです。ObjectNumber

だから、今私の質問に:

  • のワイルドカード バージョンを収集すると、ワイルドカードをList使用しないバージョンの のように機能しないのはなぜListですか?
  • ラムダの変数がではなくnumberと見なされるのはなぜですか?ObjectNumber
4

4 に答える 4

4

フォームの宣言は、 「またはそのサブクラスでList<? extends Number> wildcardListある不明なタイプのリスト」を意味します。興味深いことに、未知の型が名前で参照されている場合、未知の型を持つ同じ種類のリストが機能します。NumberNumber

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));

型推論に関する章は簡単に読めるものではありません。この点でワイルドカードと他のタイプに違いがあるかどうかはわかりませんが、あるべきではないと思います。したがって、コンパイラのバグまたは仕様による制限のいずれかですが、論理的は、ワイルドカードが機能しない理由はありません。

于 2015-01-12T12:05:14.267 に答える
2

これは型推論List<Number>によるものです。最初のケースではnumber -> Integer.valueOf(number.intValue())、変数の型numberjava.lang.Number

しかし、2番目のケースでは、宣言しfinal List<? extends Number> wildCardListたため、 EgCollectors.toMapのようなものに変換されますCollectors.<Object, ?, Map<Object, Number>toMap

    final List<? extends Number> wildCardList = Arrays.asList(1, 2, 3D);
    Collector<Object, ?, Map<Object, Object>> collector = Collectors.toMap(
            // Why is number treated as an Object and not a Number?
            number -> Integer.valueOf(number.intValue()),
            number -> number);
    wildCardList.stream().collect(collector);

その結果、表現に

number -> Integer.valueOf(number.intValue()

変数の型numberObjectintValue()であり、クラス Object にメソッドが定義されていません。したがって、コンパイルエラーが発生します。

必要なのは、コンパイラが intValue()エラーを解決するのに役立つコレクタ型引数を渡すことです。

    final List<? extends Number> wildCardList = Arrays.asList(1, 2, 3D);


    Collector<Number, ?, Map<Integer, Number>> collector = Collectors.<Number, Integer, Number>toMap(
            // Why is number treated as an Object and not a Number?
            Number::intValue,
            number -> number);
    wildCardList.stream().collect(collector);

Number::intValueさらに、代わりにメソッド参照を使用できますnumber -> Integer.valueOf(number.intValue())

Java 8 の型推論の詳細については、こちらを参照してください。

于 2015-01-11T18:18:08.553 に答える
-1

できるよ:

final List<Number> numberList = Arrays.asList(1, 2, 3D, 4D);

numberList.stream().collect(Collectors.toMap(Number::intValue, Function.identity()));
于 2018-05-18T08:58:31.613 に答える