Вы можете вызвать Try.of()
с явным универсальным типом, возвращаемым для удовлетворения проверок компилятора.Что-то вроде:
Try.<Seq<? extends Number>of(() -> List.of(1,2,3))
Try.of()
возвращает тип Try<T>
, где T
- это тип, возвращаемый поставщиком.А поскольку List.of(T t...)
возвращает List<T>
, то последний тип, видимый компилятором, равен Try<List<Integer>
, что не является тем, что метод возвращает тип, определенный.Обобщения Java с определенным типом являются инвариантными и не поддерживают ковариантные или контравариантные замены, поэтому List<Integer> != List<Number>
.
Рабочий пример:
import io.vavr.collection.List;
import io.vavr.collection.Seq;
import io.vavr.control.Try;
interface Lol {
default Try<Seq<? extends Number>> lol() {
return Try.of(List::empty);
}
}
class LolImpl implements Lol {
@Override
public Try<Seq<? extends Number>> lol() {
return Try
.<Seq<? extends Number>>of(() -> List.of(1, 2, 3))
.onFailure(t -> System.out.println(t.getMessage()));
}
public static void main(String[] args) {
System.out.println(new LolImpl().lol());
}
}
Вывод:
Success(List(1, 2, 3))
Типовая проблема вывода типа
Дальнейшие исследования показали, что это, скорее всего, общая проблема компилятора.Взгляните на следующий простой пример Java:
import java.util.Arrays;
import java.util.List;
import java.util.function.Supplier;
interface Some<T> {
static <T> Some<T> of(Supplier<T> supplier) {
return new SomeImpl<>(supplier.get());
}
default Some<T> shout() {
System.out.println(this);
return this;
}
class SomeImpl<T> implements Some<T> {
private final T value;
public SomeImpl(T value) {
this.value = value;
}
}
static void main(String[] args) {
final Some<List<CharSequence>> strings = Some.of(() -> Arrays.asList("a", "b", "c"));
}
}
Этот код компилируется без проблем, и компилятор выводит тип, возвращаемый Arrays.asList()
из ожидаемого типа с левой стороны:
![enter image description here](https://i.stack.imgur.com/bdnUT.png)
Теперь, если я вызову этот метод Some<T>.shout()
, который ничего не делает и возвращает Some<T>
, компилятор выводит тип не из ожидаемого типа переменной, а из последнего возвращенного типа:
![enter image description here](https://i.stack.imgur.com/jJ8eA.png)
Конечно Arrays.asList("a","b","c")
возвращает List<String>
и this is the type
shout () `метод выводит и возвращает:
![enter image description here](https://i.stack.imgur.com/PM8b7.png)
Указание явного типа Some<T>.of()
решает проблему, как в примере Try.of()
:
![enter image description here](https://i.stack.imgur.com/nxA2r.png)
Я искал документацию Oracle по выводу типа, и есть такое объяснение:
Компилятор Java использует преимущества типизации цели, чтобы вывести параметры типа при вызове универсального метода.Целевой тип выражения - это тип данных, который ожидает компилятор Java в зависимости от того, где находится выражение.
Источник: https://docs.oracle.com/javase/tutorial/java/generics/genTypeInference.html#target_types
Это выглядит так "в зависимости от того, где появляется выражение" в этом случае означает предполагаемый тип из ранеевернул точный тип.Это объясняет, почему при пропуске метода shout()
компилятор осознает, что мы ожидаем Some<List<CharSequence>>
, а когда мы добавляем метод shout()
, он начинает возвращать Some<List<String>>
, потому что именно этот метод shout()
видит из возвращенного типа Some.of()
метод.Надеюсь, это поможет.