为什么.forEach(val-> list.add())编译而.forEach(val-> true)不编译?

时间:2018-12-15 15:59:00

标签: java java-8 compiler-errors java-stream

最好在代码中表达这种行为:

List<Integer> list= new ArrayList<>();
Stream.of(1,2,3).forEach(i -> list.add(1));  // COMPILES

Stream.of(1,2,3).forEach(i -> true);  // DOES NOT COMPILE!

forEach(...)接受Consumer,但是如果List接口具有以下签名boolean add(E e),为什么第一个示例会编译?而第二个产量:

  

lambda表达式中的错误返回类型:布尔值不能转换为   无效

3 个答案:

答案 0 :(得分:11)

尽管您可能只是在寻找

Stream.of(1,2,3).forEach(list::add); // adding all to `list`
  

如果List接口具有以下内容,为什么第一个示例会编译   签名布尔值add(E e)

主要是因为方法的返回类型在第一次调用中被忽略。这就是它的扩展内容:

Stream.of(1,2,3).forEach(new Consumer<Integer>() {
    @Override
    public void accept(Integer i) {
        list.add(1); // ignored return type
    }
});  // COMPILES

另一方面,另一个lambda表示更像是Predicate(也是FunctionalInterface),表示总是从其true方法返回test。如果您甚至尝试将其表示为Consumer,它可能看起来就像

Stream.of(1,2,3).forEach(new Consumer<Integer>() {
    @Override
    public void accept(Integer i) {
        return true; // you can correlate easily now why this wouldn't compile 
    }
});  // DOES NOT COMPILE!

要添加到design basis via a comment from Brian

  

Java允许您调用方法并忽略返回值(方法调用表达式作为语句)。由于我们允许在   调用时,在使方法适应于   功能性接口,其参数兼容但功能性   界面返回了空白。

编辑:将其放在his own words中,与language spec接近:

  

更准确地说,list.add(x)是一个语句表达式,并且   因此是无效的。 true不是语句表达式,   因此不兼容void。 forEach(Consumer)需要一个    void兼容的lambda。

答案 1 :(得分:0)

forEach()作为Consumer作为唯一参数,因此您需要实现方法accept()的实现,该方法返回void,因此在第二个示例中,您重新实现具有给定关联static boolean method(int)的方法。

答案 2 :(得分:0)

Special Void-Compatibility Rule(JLS)说,返回空值的lambda可以接受返回非空值的语句。在这种情况下,退货将被丢弃。因此可以编译。

Stream.of(1,2,3).forEach(i -> list.add(1)); // return value of add is ignored

在Action book中引用Java-8可以使措辞有所不同:

  

如果lambda的主体为语句表达式,则表示兼容   带有返回void的函数描述符(提供了参数   列表也兼容)。例如,以下两行是   即使List的方法添加返回布尔值,但不合法   在使用者上下文中无效(T->无效):

// Predicate has a boolean return
 Predicate<String> p = s -> list.add(s); 
// Consumer has a void return 
Consumer<String> b = s -> list.add(s);

对于第二个示例,这是明确尝试返回不希望出现的布尔值

Stream.of(1,2,3).forEach(i -> true);  

换句话说:

Stream.of(1,2,3).forEach(i -> {return true;});

您已经知道forEach会使用一个Consumer,因此尝试“显式”返回一个boolean应该会产生编译错误。