Несовместимые типы при использовании подстановочного знака нижней границы

Я не могу понять, почему у меня есть ошибка компиляции для этого кода:

private static <T> Consumer<T> f3()
{
    return t -> {};
}

private static <T> Consumer<? super T> f4()
{
    return t -> {};
}


@Test
public void test()
{
    Consumer<Integer> action3 = f3();
    Consumer<Integer> action4 = f4(); // ERROR
}

ошибка от javac 1.8.0_161:

Ошибка: (84, 36) java: несовместимые типы: не существует экземпляра(ов) переменной(ов) типа T, так что java.util.function.Consumer<? super T> соответствует java.util.function.Consumer<java.lang.Void>

Кто-нибудь может объяснить эту ошибку? Спасибо.

EDIT Я попытался упростить свой пример, но сделал ошибку, сделав его слишком простым. Меня интересует объяснение этой ошибки, которая выводится IntelliJ:

private static <T> BiConsumer<T, ? super Throwable> f1(Consumer<? super Throwable> consumer)
{
    return null;
}

private static <T> BiConsumer<? super T, ? super Throwable> f2(Consumer<? super Throwable> consumer)
{
    return null;
}

@Test
public void test()
{
    BiConsumer<? super Integer, ? super Throwable> action1 = f1(throwable -> { });
    BiConsumer<? super Integer, ? super Throwable> action2 = f2(throwable -> { });  // ERROR HERE
}

IntelliJ считает это ошибкой, потому что «переменная вывода T имеет несовместимые границы: ограничения равенства: нижние границы T: целое число». Но при компиляции все нормально, ошибок нет. Действительно ли это действительный код Java и просто ошибка в IntelliJ? Спасибо.


person Florin M    schedule 16.03.2018    source источник
comment
@AndyTurner Я отредактировал, чтобы указать, где ошибка, извините за это.   -  person Florin M    schedule 16.03.2018


Ответы (3)


Consumer<? super Something> не является Consumer<Integer>.

Компилятор не знает, что в классе Consumer нет методов-производителей, поэтому он мешает вам потенциально использовать его в качестве производителя.

Что касается правил вывода типов, то, например, нет никакой разницы между Consumer и List. Таким образом, то же правило, которое мешает вам написать следующее, также останавливает вас и в том, что вы делаете:

List<? super Integer> c = Arrays.asList("");
List<Integer> d = c;        // Compiler error; let's pretend it works.
Integer i = d.get(0);       // ClassCastException!
person Andy Turner    schedule 16.03.2018

Ответ на ваше редактирование:

Я подозреваю, что это ошибка в intellij. Если я удалю объявление переменной, а затем выберу выражение и нажму Ctrl+Alt+V, чтобы извлечь переменную, она выберет следующий тип :

BiConsumer<? super Object, ? super Throwable> biConsumer = f2(throwable -> {});

который, несмотря на то, что он только что выбрал себя, выделяет лямбду как ошибку.

person Andy Turner    schedule 16.03.2018
comment
Я также думаю, что это ошибка: если я изменю тип возврата f2 с BiConsumer на Consumer, он сработает. Спасибо. - person Florin M; 19.03.2018
comment
@FlorinM JetBrains кажутся довольно быстрыми в исправлении ошибок! - person Andy Turner; 20.03.2018

Пожалуйста, попробуйте File->Invalidate Caches и перезапустите.

person Pushpendra Jaiswal    schedule 15.11.2018