Java将您看到的任何方法引用或lambda转换为实际类型:该类型必须是所谓的函数类型,这是任何接口,如果go 掉java.lang.Object
中的任何方法以及具有default
实现的任何方法,只留下一个方法.然后这是一个功能接口;,你可以将它标记为@FunctionalInterface
,但这仅仅是编译器判断的文档:该动作并不使其成为功能接口;该动作只是告诉编译器:如果我用它注释一个not是功能接口的东西,请生成编译器错误.
问题是,Iterable
,is是一个功能接口:它是一个定义了一个方法的接口,签名是:给定零个参数,产生一个迭代器.
结果,lines::iterator
also符合这个签名:这是一个不带参数的方法,返回一个迭代器.
请注意,无论lines
是什么,lines::iterator
都不会调用Iterator()方法.相反,它编码了这样做的 idea .值lines::iterator
是"在任何lines
上调用迭代器()方法的 idea ".无论给出什么代码,"这个概念"都可以 Select 实际执行该操作.然后再来一次.否则就永远不会go 做.或者把它保存下来,明天再做,在另一个帖子里.
也就是说,如果它能编译的话--那是一个方法引用,所以它must可以用在需要函数类型的上下文中;你不能只写Object o = lines::iterator;
.
考虑到演员阵容,现在有了一个背景.所以,那就好了.(Iterable<String>) lines::iterator
是有效的Java.
它甚至实现了Iterable
和Iterator
之间的关键语义差异:Iterable是可重复的:您可以"从头开始"--只需再次调用.iterator()
方法,即可获得一个从头开始的新迭代器.相比之下,Iterator
就不能倒退了.一旦你调用了next()
,你就继续前进了.没有prev()
、reset()
或goTo(0)
之类的东西.您可以在您多次创建的这Iterable<String>
上调用.iterator()
,编译器不会阻止您编写该代码.
除了,这实际上并不有用:So this is a hack,但相对无害的一个.Iterable
个实例应该是可重复的,但Stream
‘S iterator()
方法的文档非常清楚它是不可重复的--一旦你遍历了那个迭代器,你就不能再这样做了.如果您多次调用.iterator()
,编译器不会抱怨,但运行库会--第二次调用会导致异常.这是why,Stream
有一个iterator()
方法,但does not实现Iterable<T>
.即使它可以-编译器不会阻止Stream这样做(因为Iterable的所有实例都必须有一个方法:public Iterator<T> iterator()
,它..Stream<T>
个有!并不是API中的每个需求都可以被类型系统捕获,并且‘必须可以被多次调用,返回一个新的、功能正常的迭代器,该迭代器位于任何东西的开头,每次你把它称为’is‘这是Iterables应该做的事情,但是这个是does not,类型系统不能捕获它.
因此,这produces a broken Iterable.因此,让它作为公共API的一部分逃逸是一个非常非常糟糕的主意.然而,在这段代码中,它是立即使用的,所以想必代码可以"解决"它的缺陷(缺陷是:您不能对它多次调用iterator()
).代码确实应该有一个注释,解释这是一个半参数的迭代器,因此代码不能允许它转义,也不能对它多次调用iterator()
.