web-dev-qa-db-ja.com

Optional.mapがこの割り当てを機能させるのはなぜですか?

Optional<ArrayList<String>> option = Optional.of(new ArrayList<>());

Optional<ArrayList<?>> doesntWork = option;

Optional<ArrayList<?>> works = option.map(list -> list);

最初に試行された割り当てはコンパイルされませんが、mapを使用した2番目の割り当てはコンパイルされます。 mapは実際には何も実行すべきではないようですが、何らかの理由でOptional<ArrayList<String>>Optional<ArrayList<?>>に変換します。進行中のある種の暗黙のキャストはありますか?

36
Carl Minden

mapのコードを調べて、すべてのメソッド呼び出しをたどると、option.map(list -> list)new Optional<>(option.get())を返すことになります。したがって、最後の割り当てを次のように置き換えることができます。

_Optional<ArrayList<?>> works = new Optional<>(option.get());
_

これにより、新しい_Optional<ArrayList<?>>_が作成され、valueインスタンス変数(タイプは_ArrayList<?>_)がmap.get()から返される_ArrayList<String>_で初期化されます。これは有効な割り当てです。

進行中のある種の暗黙のキャストはありますか?

いいえ、mapは新しいOptionalインスタンスを返します。呼び出された元のインスタンスはキャストされません。

次に、一連のメソッド呼び出しを示します。

_option.map(list -> list)
_

戻り値(optionは空ではないため)

_Optional.ofNullable(mapper.apply(value))
_

これはあなたの場合と同じです

_Optional.ofNullable(value)
_

戻り値(値がnullではないため):

_Optional.of(value)
_

戻る

_new Optional<>(value)
_
25
Eran

ジェネリックは不変なので、最初の方法は機能しません。ジェネリックスを共変にする唯一の方法は、たとえば次のように有界型を追加することです。

 Optional<? extends ArrayList<String>> doesntWork = option; 

コンパイルされます。

そして、あなたがmapステップが何も成し遂げるべきではないと言うとき、それは正しくありません。 Optional::mapの定義を見てください。

public <U> Optional<U> map(Function<? super T, ? extends U> mapper) {
    Objects.requireNonNull(mapper);
    if (!isPresent()) {
        return empty();
    } else {
        return Optional.ofNullable(mapper.apply(value));
    }
}

大まかに言えばdoesOptional<T>からOptional<U>...に変換.

10
Eugene

後者の場合、Optional.mapメソッドの戻り値の型は、works変数の型によって暗黙的に決定されます。それが違いがある理由です。

0
dpr

君の option.mapには署名があります

<ArrayList<?>> Optional<ArrayList<?>> Java.util.Optional.map(Function<? super ArrayList<String>, ? extends ArrayList<?>> mapper)

したがって、この

Optional<? extends ArrayList<?>> doesntWork = option;

コンパイルしません。

0
user11044402