Подпись flatMap в опции Java 8

В oracle docs, это выглядит как

<U> Optional<U> flatMap(Function<? super T,Optional<U>> mapper)

Для mapper как Function он делает параметр контравариантным, но не делает возвращаемый тип ковариантным. Интересно, может ли mapper быть (должен) быть

Function<? super T,Optional<? extends U>>

или

Function<? super T, ? extends Optional<? extends U>>

?

Ответ 1

Прежде всего, IMO, поскольку U связывается с самим методом, но не с классом Optional, а также Optional является final, текущая подпись должна работать нормально.

Если оба указанных выше условия не выполняются, могут быть применены изменения. Спасибо за ссылку , предоставленную @MalteHartwig. Позвольте мне подытожить ответ на этот конкретный вопрос. Становится ясно, что если тип возврата должен быть ковариантным, последняя подпись (более длинная) необходима в Java 8. Это касается не только наследования. ? extends требуется Optional<? extends U>, чтобы объявить дисперсию пользовательского сайта Function, даже если Optional - final. Я сделал фрагмент кода, чтобы продемонстрировать его:

import java.util.function.Function;

class A {}
class B extends A {}

final public class Option<T> {
  private T value;
  public Option(T v) { value = v; }
  <U> Option<? extends U> flatMap1(Function<? super T, Option<? extends U>> mapper) {
    return mapper.apply(value);
  }

  <U> Option<? extends U> flatMap2(Function<? super T, ? extends Option<? extends U>> mapper) {
    return mapper.apply(value);
  }

  void test() {
    Option<A> oa = new Option<>(new A());
    Function<A,Option<A>> faa = (A a) -> new Option<>(new A());
    Function<A,Option<B>> fab = (A a) -> new Option<>(new B());
    //oa.flatMap1(faa);   DOES NOT COMPILE
    oa.flatMap2(fab);
  }
}

Похоже, что поскольку Java имеет только декларацию дисперсии пользовательского сайта, вам может понадобиться серия ? extends, которая будет распространять это декларацию вплоть до (2-го) внешнего уровня от переменной типа, для которой вы хотите объявить дисперсию.

Ответ 2

Скажите, что у вас есть class A и class B extends A; вам нужно помнить, что Object B является A Object; Вы унаследуете это.

Чтобы объект выполнил ограничение Optional<? extends U>, он должен был выполнить ограничение Optional<U>. Аналогично, для того, чтобы объект выполнил ограничение Optional<U>, он должен был выполнить Optional<? extends U>.

В этой ситуации они синонимы.

В то время как вопрос специфичен для определенного метода, вы можете легко проверить ответ. Написав аналогичную функцию, вы можете проверить, разрешит ли компилятор то, что вы хотите, и будет ли он работать, как ожидалось.

public static <U> void List(List<U> A, List<? extends U> B) {
    ...
}
...
MakeList(new ArrayList<Number>(), new ArrayList<Integer>());

Как и ожидалось, все в порядке.