Почему подстановочные знаки параметров типа поставщика или методов flatMap в Optional или? - PullRequest
0 голосов
/ 10 декабря 2018

Метод Optional.or был добавлен в Java 9. Это сигнатура метода

public Optional<T> or​(Supplier<? extends Optional<? extends T>> supplier)

Почему параметр типа Supplier принимает ? extends Optional, а непросто Optional, поскольку Optional является окончательным классом?

То же самое верно для метода Optional.flatMap.Это изменение по сравнению с Java 8.

В Java 8 это было Function<? super T, Optional<U>> mapper, тогда как в Java 9 оно было изменено на Function<? super T,​? extends Optional<? extends U>>.

Ответы [ 3 ]

0 голосов
/ 10 декабря 2018

FWIW, аналогичная проблема с ковариантными аргументами все еще существует в Stream.iterate и Stream.iterate в Java 11. Текущие сигнатуры методов

static <T> Stream<T> iterate(T seed, Predicate<? super T> hasNext, UnaryOperator<T> next)
static <T> Stream<T> iterate(T seed, UnaryOperator<T> f)

Эти подписи не допускают некоторые комбинации начальных значений и UnaryOperator s, которые являются звуковыми с точки зрения типа, например, следующее не компилируется:

UnaryOperator<String> op = s -> s; 
Stream<CharSequence> scs = iterate("", op); // error

Предлагаемое решениеэто изменить сигнатуры метода на

static <T, S extends T> Stream<T> iterate(S seed, Predicate<? super S> hasNext, UnaryOperator<S> next)
static <T, S extends T> Stream<T> iterate(S seed, UnaryOperator<S> f)

Так, в отличие от Optional.or и Optional.flatMap , это случай, когда «дополнительный тип-параметрический подход "реально работает.

0 голосов
/ 10 декабря 2018

Да ... говорят, что подстановочный знак с расширением-границей (верхняя граница) делает тип ковариантным , что означает, что, например, List<Apple> является фактическим подтипом List<? extends Fruit> (учитываячто Apple распространяется Fruit);это также называется ковариация .

Или в приведенных вами примерах это означает, что Optional<StringBuilder> является подтипом Optional<? extends Optional<? extends CharSequence>>, поэтому вы можете, например, сделать:

List<Optional<String>> left = new ArrayList<>();
List<? extends Optional<? extends CharSequence>> right = new ArrayList<>();

right = left; // will compile

или назначить Function к другому

0 голосов
/ 10 декабря 2018

Я нашел причину этого у самого Стюарта Маркса

http://mail.openjdk.java.net/pipermail/core-libs-dev/2016-October/044026.html

Это связано с вложенными генериками (Optional вложено в Function).Из почтовой ветки

 Function<..., Optional<StringBuilder>>

не является подтипом

 Function<..., Optional<? extends CharSequence>>

Чтобы обойти это, мы также должны добавить внешний подстановочный знак, так что

 Function<..., Optional<StringBuilder>>

является подтипом

 Function<..., ? extends Optional<? extends CharSequence>>
...