lambda 表达式中的返回类型错误

2022-09-03 02:26:51

以下代码在 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

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

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

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

有关导致此问题的原因以及何时修复的任何详细信息?


答案 1

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

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

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

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

  Consumer<? super Boolean> consumer = (Object b)->{...}

但是,隐式地,应推断为 。这是有道理的,因为无论如何,消费者都应该只喂食。bBooleanBoolean

http://docs.oracle.com/javase/specs/jls/se8/html/jls-15.html#jls-15.27.3

如果 T 是通配符参数化函数接口类型,并且 lambda 表达式是隐式类型,则地面目标类型是 T 的非通配符参数化

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


答案 2

<? super E>包含 ,它不是 .即ObjectBoolean

MyPredicate<? super E>

可能是

MyPredicate<Object>

并且不能将 返回 为 .Objectboolean

尝试将 lambda 更改为:

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

它将编译和执行而不会出错,这与流的类型无关,但对于作为值的元素将返回。truetrueBoolean


推荐