假设我们有一个 Iterator<Integer> iterator
.因为Iterable
是一个函数式接口(interface),我们可以这样写:
Iterable<Integer> iterable = () -> iterator;
我们当然可以使用 iterable
作为for循环的增强表达式:
for (Integer i : iterable) foo(i);
那是为什么
for (Integer i : () -> iterator) foo(i);
不允许? (它会导致以下编译器错误:)
error: lambda expression not expected here
for (Integer i : () -> iterator) foo(i);
^
明确目标类型
for (Integer i : (Iterable<Integer>) () -> iterator) foo(i);
显然有效,但是如果省略 λ 表达式,为什么编译器不能推断出它的目标类型?从 Expression 是 λ 表示法这一事实来看,编译器是否不清楚目标类型不能是 Array
,因此必须是 Iterable
?
这只是语言设计者的疏忽,还是我在这里遗漏了什么?
最佳答案
这不仅仅是关于 lambda 表达式;它是关于所有需要目标类型的多边形表达式。
可以肯定的是,这不是疏忽。该案被考虑并驳回。
引用早期规范:
http://cr.openjdk.java.net/~dlsmith/jsr335-0.9.3/D.html
Deciding what contexts are allowed to support poly expressions is driven in large part by the practical need for such features:
The expression in an enhanced for loop is not in a poly context because, as the construct is currently defined, it is as if the expression were a receiver:
exp.iterator()
(or, in the array case,exp[i]
). It is plausible that an Iterator could be wrapped as an Iterable in a for loop via a lambda expression (for (String s : () -> stringIterator)
), but this doesn't mesh very well with the semantics of Iterable.
我的看法是,每次调用 Iterable.iterator()
必须返回一个新的、独立的迭代器,位于开头。然而,示例(以及您的示例)中的 lambda 表达式返回 same 迭代器。这不符合 Iterable
的语义。 .
无论如何,在 for-each 循环中支持目标输入似乎是不必要的工作。如果你已经有了迭代器,你可以简单地做
iterator.forEachRemaining( element->{ ... } )
或者如果你更喜欢老派
while(iterator.hasNext()) {
Foo elment = iterator.next();
两者都太不好;使语言规范更加复杂是不值得的。 (如果我们确实希望 for-each 提供目标类型,请记住它也需要适用于其他 poly 表达式,例如 ?:
;那么在某些情况下 for-each 可能变得难以理解。一般来说,有两种可能的目标类型,Iterable<? extends X> | X[]
,这对于类型推断系统来说是非常困难的。)
for-each 构造可以被视为语法糖,因为 lambda 不可用。如果语言已经有 lambda 表达式,那么真的没有必要有一个特殊的语言结构来支持 for-each;它可以通过库 API 来完成。
关于java - 在 Java 中,为什么我不能使用 lambda 作为增强的 for 循环表达式?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32506732/