最好在代码中表达这种行为:
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表达式中的错误返回类型:布尔值不能转换为 无效
答案 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
应该会产生编译错误。