Почему следующая кастинг с ссылкой метода не приводит к ошибке компиляции?

public class SomeClass{

    public static int someFunction(int a) {
        return a;
    }

    public static void main(String[] args) {    
        Consumer<Integer> c = SomeClass::someFunction; 
    }
}

Я не понимаю почему: Consumer<Integer> c = SomeClass::someFunction; не создает ошибку компиляции, так как функция someFunction - это метод с возвращаемым значением, а Consumer представляет методы без возвращаемого значения

Ответ 1

Из спецификации:

Если тело лямбда является выражением оператора (то есть выражением, которое можно было бы оставить в силе как оператор), оно совместимо с типом функции, производящей пустоты; любой результат просто отбрасывается.

То же самое верно для ссылок на методы.

Это более гибко. Предположим, что ошибка компилятора не использовать возвращаемое значение, когда вы вызывали метод нормально - это было бы невероятно раздражающим. В конечном итоге вам придется использовать поддельные переменные, которые вам не нужны в некоторых случаях.

public class SomeClass
{
    public static int someFunction(int a) {
        return a;
    }

    public static void main(String[] args) {    
        someFunction(3); // "error" - ignoring return type
        int unused = someFunction(3); // "success"
    }
}

Если вы хотите получить полное формальное определение того, что приемлемо, см. 15.13.2. Тип справочника метода.

Ответ 2

Это называется специальным void compatibility rule. Например, сколько раз вы действительно заботились о List#add return type? Даже если он возвращает true/false.

Здесь почти то же самое, вы можете вызвать метод, но проигнорировать его результат. Если вы переписываете своего потребителя как выражение лямбда, это имеет смысл:

Consumer<Integer> c = x -> {
   SomeClass.someFunction(x);
   return;     
}

Если я правильно помню из JLS, для этого разрешены только некоторые типы.

 increment/decrement operations
 method invocation
 assignment 
 instance creation