Почему следующая кастинг с ссылкой метода не приводит к ошибке компиляции?
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