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

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

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:

Error:(84, 36) java: incompatible types: no instance(s) of type variable(s) T exist so that java.util.function.Consumer<? super T> conforms to java.util.function.Consumer<java.lang.Void>

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

РЕДАКТИРОВАТЬ Я попытался упростить свой пример и сделал ошибку, сделав его слишком простым. Что меня интересует, так это объяснение этой ошибки, выводимой 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? Спасибо.

@AndyTurner Я отредактировал, чтобы указать, где ошибка, извините за это.

Florin M 16.03.2018 16:41
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
В компьютерном программировании биты играют важнейшую роль в представлении и манипулировании данными на двоичном уровне. Побитовые операции...
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Приходилось ли вам сталкиваться с требованиями, в которых вас могли попросить поднять тревогу или выдать ошибку, когда метод Java занимает больше...
Полный курс Java для разработчиков веб-сайтов и приложений
Полный курс Java для разработчиков веб-сайтов и приложений
Получите сертификат Java Web и Application Developer, используя наш курс.
2
1
606
3

Ответы 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!

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

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

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

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

Я тоже думаю, что это ошибка: если я изменю тип возвращаемого значения f2 с BiConsumer на Consumer, это сработает. Спасибо.

Florin M 19.03.2018 08:45

@FlorinM JetBrains действительно очень быстро исправляет ошибки!

Andy Turner 20.03.2018 08:14

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

Другие вопросы по теме