我找到了以下代码:

try (Stream<String> lines = Files.lines(path, charset)) {
    for (String line : (Iterable<String>) lines::iterator) {
        //logic
    }
}

此代码已编译并按预期工作.但是,我看不懂这一段:(Iterable<String>) lines::iterator.一个for-each循环是for (Foo foo: Iterable<Foo> iterable) {}.但是方法引用如何转换为Iterable呢?有人能解释一下吗?

推荐答案

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.

它甚至实现了IterableIterator之间的关键语义差异: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().

Java相关问答推荐

在FML中删除关键帧动画

Java应用程序崩溃时试图读取联系人从电话

最小拓Flutter 排序的时间复杂度是多少?

为什么JAVA&S清洁器使用链表而不是并发HashSet?

如何创建一个2d自上而下的移动系统,其中移动,同时持有两个关键是可能的处理?

使用GridBagLayout正确渲染

与Spring Boot相关的实体未正确保存

如何使用带有谓词参数的方法,而不使用lambda表达式

与不同顺序的组进行匹配,不重复组但分开

SpringBoot:在条件{Variable}.isBlank/{Variable}.isEmpty不起作用的情况下进行路径变量验证

Java中不兼容的泛型类型

在不使用instanceof或强制转换的情况下从父类变量调用子类方法

使用MediaPlayer类在一段时间后停止播放音乐

在ECLIPSE上的M1 Pro上运行JavaFX的问题

在权限列表中找不到我的应用程序

如何在Java中的重写方法参数中强制(Enum)接口实现?

使用@ExceptionHandler的GlobalExceptionHandler还是来自服务器的REST应答的ResponseEntity?

org.springframework.web.HttpRequestMethodNotSupportedException:请求方法';帖子';不支持

在JPanel上使用GridBagLayout并将JButton放在里面时出现问题

找不到 jar 文件系统提供程序try 使用 jdeps 和 jlink 创建收缩 Java 映像来运行 Minecraft