Ответ 1
В первом примере
consumerIntFunctionTest(data -> {
Arrays.sort(data);
}, int[]::new);
выражение лямбда имеет void
-собираемый блок, который может быть идентифицирован структурой выражения без необходимости разрешать фактические типы.
Напротив, в примере
consumerIntFunctionTest(Arrays::sort, int[]::new);
ссылка на метод должна быть решена, чтобы выяснить, соответствует ли она либо функции void
(Consumer
), либо функции возврата значения (Function
). То же самое относится к упрощенному лямбда-выражению
consumerIntFunctionTest(data -> Arrays.sort(data), int[]::new);
которые могут быть как void
- совместимыми, так и совместимыми по стоимости, в зависимости от разрешенного целевого метода.
Проблема заключается в том, что для решения метода требуется знание требуемой сигнатуры, которая должна определяться с помощью целевого ввода, но целевой тип неизвестен до тех пор, пока не будут известны параметры типа общего метода. В то время как теоретически оба могут быть определены сразу, процесс (все еще ужасно сложный) был упрощен в спецификации в этом методе, когда сначала выполняется перегрузка, и применяется процедура ввода вывода (см. JLS §15.12.2). Следовательно, информация, которую может предоставить вывод типа, не может использоваться для разрешения разрешения перегрузки.
Но обратите внимание, что первый шаг, описанный в 15.12.2.1. Определение потенциально применимых методов содержит:
Выражение потенциально совместимо с целевым типом в соответствии со следующими правилами:
Лямбда-выражение (§15.27) потенциально совместимо с функциональным интерфейсом типа (§9.8), если все верно:
Арность типа типа целевого типа такая же, как и арность выражения лямбда.
Если тип функции целевого типа имеет возврат void, то тело лямбда является выражением оператора (§14.8) или блоком, совместимым с void (§15.27.2).
Если тип функции целевого типа имеет (непустой) возвращаемый тип, то тело лямбда является либо выражением, либо совместимым по значению блоком (§15.27.2).
Ссылочное выражение метода (§15.13) потенциально совместимо с типом функционального интерфейса, если, когда тип типа типа arty равен n, существует по крайней мере один потенциально применимый метод для ссылочного выражения метода с arity n ( § 15.13.1), и одно из следующего верно:
Ссылочное выражение метода имеет форму ReferenceType:: [TypeArguments] Идентификатор и по крайней мере один потенциально применимый метод: i) статический и поддерживает arity n, или ii) не статический и поддерживает arity n-1.
В ссылочном выражении метода есть другая форма, и по крайней мере один потенциально применимый метод не является статическим.
...
Определение потенциальной применимости выходит за рамки базовой проверки достоверности, чтобы также учитывать наличие и "форму" целевых типов функционального интерфейса. В некоторых случаях, связанных с выводом аргумента типа, выражение лямбда, которое появляется как аргумент вызова метода, не может быть правильно напечатано до разрешения перегрузки.
Итак, в первом примере один из методов сортируется формой lambdas, а в случае ссылки на метод или лямбда-выражения, состоящего из выражения единственного вызова, оба потенциально применимых метода переносят этот первый процесс выбора и дают "неоднозначная" ошибка до того, как вывод типа может начать поиск целевого метода, чтобы определить, есть ли его метод void
или возвращающий значение.
Обратите внимание, что, как и при использовании x->{ foo(); }
, чтобы явно выразить лямбда-выражение void
-compatible, вы можете использовать x->( foo() )
, чтобы сделать лямбда-выражение явно совместимым с оценкой.
Вы, сумасшедший, далее читаете этот ответ, объясняя, что это ограничение суммированного вывода и разрешения перегрузки метода было преднамеренным (но не простым) решением.