Вопрос:
Следующий код компилируется в IntelliJ и Eclipse, но компилятор JDK 1.8.0_25 жалуется. Во-первых, код.
import java.util.function.Predicate; public abstract class MyStream<E> { static <T> MyStream<T> create() { return null; } abstract MyStream<E> filter(MyPredicate<? super E> predicate); public interface MyPredicate<T> extends Predicate<T> { @Override boolean test(T t); } public void demo() { MyStream.<Boolean> create().filter(b -> b); MyStream.<String> create().filter(s -> s != null); } }
Выход из javac 1.8.0_25:
MyStream.java:18: error: incompatible types: incompatible parameter types in lambda expression MyStream.<Boolean> create().filter(b -> b); ^ MyStream.java:18: error: incompatible types: bad return type in lambda expression MyStream.<Boolean> create().filter(b -> b); ^ ? super Boolean cannot be converted to boolean MyStream.java:19: error: bad operand types for binary operator ‘!=’ MyStream.<String> create().filter(s -> s != null); ^ first type: ? super String second type: <null> MyStream.java:19: error: incompatible types: incompatible parameter types in lambda expression MyStream.<String> create().filter(s -> s != null); ^ Note: Some messages have been simplified; recompile with -Xdiags:verbose to get full output 4 errors
Когда я заменяю ? super E просто E, JDK успешно компилируется.
Когда я заменяю filter(MyPredicate на filter(Predicate, JDK успешно компилируется.
Поскольку он работает с JDK 1.8.0_60, я подозреваю, что это ошибка компилятора.
Любые сведения о том, что вызвало это и когда оно было исправлено?
Лучший ответ:
Если выражение лямбда появляется в целевом типе с помощью подстановочных знаков (как в большинстве случаев)
Consumer<? super Boolean> consumer = b->{…}
возникает вопрос – какой тип лямбда-выражения; в частности, тип b.
Конечно, может быть много вариантов из-за подстановочных знаков; например мы могли бы явно выбрать
Consumer<? super Boolean> consumer = (Object b)->{…}
Однако, неявно, b следует вывести как Boolean. Это имеет смысл, так как потребителю следует подавать только Boolean.
http://docs.oracle.com/javase/specs/jls/se8/html/jls-15.html#jls-15.27.3
Если T – тип функционального интерфейса с параметром подстановочной подстановки и выражение лямбда неявно напечатано, то целевой целевой тип – это несимметричная параметризация T
(Вероятно, предполагается, что подстановочные знаки корректно используются для целевого типа, поэтому мы можем найти несколько веселых примеров, если предположение не выполняется)
Ответ №1
<? super E> включает Object, который не является Boolean. т.е.
MyPredicate<? super E>
Может быть
MyPredicate<Object>
и вы не можете вернуть Object как Boolean.
Попробуйте изменить lambda на:
MyStream.<Boolean> create().filter(b -> Boolean.TRUE.equals(b));
который будет компилироваться и выполняться без ошибки, не имеет значения типа потока, но вернет true для элементов, которые являются значениями true Boolean.