【问题标题】:bad return type in lambda expressionlambda 表达式中的错误返回类型
【发布时间】:2015-10-12 15:45:33
【问题描述】:

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

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

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

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

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

【问题讨论】:

  • 是的,我也相信这是一个编译器错误。尝试解决方法filter((Boolean b)-&gt;b))

标签: java lambda java-8


【解决方案1】:

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

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

问题出现了——lambda 表达式的类型是什么?特别是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 是通配符参数化的函数式接口类型并且 lambda 表达式是隐式类型的,则地面目标类型是 T 的非通配符参数化

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

【讨论】:

    【解决方案2】:

    &lt;? super E&gt; 包括Object,它不是Boolean。即

    MyPredicate<? super E>
    

    可能是

    MyPredicate<Object>
    

    您不能将Object 作为boolean 返回。

    尝试将您的 lambda 更改为:

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

    无论流的类型如何,它都将编译和执行而不会出错,但将为 true Boolean 值的元素返回 true

    【讨论】:

    • no - 虽然目标类型是 Predicate&lt;? super Boolean&gt;,但 lambda 表达式的类型应该是 Predicate&lt;Boolean&gt;。 (jls#12.27.3)。因此b 的静态类型为Boolean
    猜你喜欢
    • 2021-11-01
    • 2018-10-09
    • 1970-01-01
    • 2014-08-06
    • 1970-01-01
    • 2019-10-11
    • 2019-05-24
    • 2021-01-31
    相关资源
    最近更新 更多