关于Java:lambda表达式中的返回类型错误

bad return type in lambda expression

以下代码在IntelliJ和Eclipse中可以正常编译,但是JDK编译器1.8.0_25抱怨。 首先,代码。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
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的输出是:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
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

当我用E替换? super E时,JDK编译成功。

当我用filter(Predicate替换filter(MyPredicate时,JDK编译成功。

由于它可与JDK 1.8.0_60一起使用,因此我怀疑它是编译器错误。

关于什么原因以及何时修复的任何详细信息?


如果lambda表达式出现在带有通配符的目标类型中(在大多数情况下)

1
  Consumer<? super Boolean> consumer = b->{...}

问题出现了-lambda表达式的类型是什么?特别是b的类型。

当然,由于通配符,可能有很多选择;例如我们可以明确选择

1
  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

If T is a wildcard-parameterized functional interface type and the lambda expression is implicitly typed, then the ground target type is the non-wildcard parameterization of T

(这可能假设通配符在目标类型上正确地使用了方差;如果假设不成立,我们可能会发现一些有趣的例子)


包括Object,它不是Boolean。即

1
MyPredicate<? super E>

可能是

1
MyPredicate<Object>

并且您不能将Object作为Boolean返回。

尝试将lambda更改为:

1
MyStream.<Boolean> create().filter(b -> Boolean.TRUE.equals(b));

不管流的类型如何,它都会编译并执行而不会出错,但是对于true Boolean值的元素将返回true