java - 为什么 Java 编译器不能推断 Iterable从约束 Iterable和 () -> (Iterator)
问题描述
背景:我最近写了一个答案,我建议编写以下代码:
Files.write(Paths.get("PostgradStudent.csv"),
Arrays.stream(PGstudentArray).map(Object::toString).collect(Collectors.toList()),
StandardOpenOption.CREATE, StandardOpenOption.TRUNCATE_EXISTING);
想了想,我说:“我这里其实不需要列表,我只需要一个Iterable<? extends CharSequence>
”。
正如Stream<T>
有一个方法Iterator<T> iterator()
,然后我想,嗯,这很容易:
Iterable<? extends CharSequence> iterable = () -> Arrays.stream(arr).map(Object::toString).iterator();
(我将它提取到这个问题的局部变量中,我想在最后内联。)
不幸的是,如果没有额外的类型提示,这将无法编译:
error: incompatible types: bad return type in lambda expression
Iterable<? extends CharSequence> iterable = () -> Arrays.stream(arr).map(Object::toString).iterator();
^
Iterator<String> cannot be converted to Iterator<CharSequence>
当然,添加一些类型提示将使这项工作:
Iterable<? extends CharSequence> iterable2 = (Iterable<String>) () -> Arrays.stream(arr).map(Object::toString).iterator();
Iterable<? extends CharSequence> iterable3 = () -> Arrays.stream(arr).<CharSequence>map(Object::toString).iterator();
在我的理解中,Java 编译器做了以下事情:
- 它查看表达式的目标类型,即
Iterable<? extends CharSequence>
. - 然后它确定这个接口的函数类型,
() -> Iterator<? extends CharSequence>
在我的例子中。 - 然后它查看 lambda 并检查它是否兼容。
就我而言,lambda 的类型为() -> Iterator<String>
.
与步骤 2 中确定的函数类型兼容。
有趣的是,如果我将 lambda 的目标更改为Supplier
:
Supplier<Iterator<? extends CharSequence>> supplier = () -> Arrays.stream(arr)
.map(Object::toString)
.iterator();
它会编译得很好。
现在的问题是:为什么 javac 不能推断出这个 lambda 的正确类型?
解决方案
你可以在这里找到一些解释:
在检查兼容性之前,必须将通配符参数化的功能接口类型转换为函数类型(方法签名)......其工作原理如下:
Iterable<? extends CharSequence> becomes () -> Iterator<CharSequence>
因此,如果 lambda 表达式是隐式类型的,则 LHS 变为Iterator<CharSequence>
而 RHS 为Iterator<String>
. 因此,出现错误:
Iterator<String> cannot be converted to Iterator<CharSequence>
JLS §18.5.3中也解释了这种行为。
推荐阅读
- r - 如何在R中找到0到360经度范围内的特定经度
- angular - Angular6获取方法响应“_isScalar”:false,“source”
- axios - Axios 以数据二进制格式发送我的纯 JSON
- python - 如何在我的 Python 程序中获取短信验证码?
- electron - Electron dialog.showOpenDialog 如何获取快捷链接而不是目标?
- android - Listview 使用背景图像突出显示选定的行
- angular - Angular Jasmine 如何测试()是否返回;在一个函数中
- apache-kafka - kafka 如何在不同存储大小的 broker 之间共享磁盘空间?
- php - TCPDF 右边距不适用于右对齐
- php - 如何将管理员和经理条目添加到 cakePHP 2x ACL aros 和 acos 的数据库中