为什么Java编译器不能从约束Iterable <推断出Iterable <String>?扩展CharSequence>和()->(Iterator <String>)

Joh*_*uhn 6 java lambda type-inference jls

背景:最近我写了一个答案,建议我编写以下代码:

Files.write(Paths.get("PostgradStudent.csv"),
        Arrays.stream(PGstudentArray).map(Object::toString).collect(Collectors.toList()),
        StandardOpenOption.CREATE, StandardOpenOption.TRUNCATE_EXISTING);
Run Code Online (Sandbox Code Playgroud)

经过一番思考,我说:“我实际上不需要这里的列表,我只需要一个Iterable<? extends CharSequence>”。
就像Stream<T>一种方法一样Iterator<T> iterator(),然后我想到了,这很容易:

Iterable<? extends CharSequence> iterable = () -> Arrays.stream(arr).map(Object::toString).iterator();
Run Code Online (Sandbox Code Playgroud)

(针对这个问题,我将其提取到一个局部变量中,我想最后进行内联。)
不幸的是,如果没有其他类型提示,则无法编译该代码:

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>
Run Code Online (Sandbox Code Playgroud)

当然添加一些类型提示将使这项工作:

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();
Run Code Online (Sandbox Code Playgroud)

以我的理解,Java编译器执行以下操作:

  1. 它查看表达式的目标类型,即Iterable<? extends CharSequence>
  2. 然后,它确定此接口的功能类型,() -> Iterator<? extends CharSequence>在我的情况下。
  3. 然后,它查看lambda并检查其是否兼容。
    就我而言,lambda的类型为() -> Iterator<String>
    与步骤2中确定的功能类型兼容。

有趣的是,如果我将lambda的目标更改为Supplier

Supplier<Iterator<? extends CharSequence>> supplier = () -> Arrays.stream(arr)
    .map(Object::toString)
    .iterator();
Run Code Online (Sandbox Code Playgroud)

它将编译正常。

现在的问题是:为什么javac不能为此lambda推断正确的类型?

Ole*_*hov 3

您可以在这里找到一些解释:

\n\n
\n

在检查兼容性之前,通配符参数化的函数接口类型必须转换为函数类型(方法签名)......其工作原理如下:

\n
\n\n
Iterable<? extends CharSequence> becomes () -> Iterator<CharSequence>\n
Run Code Online (Sandbox Code Playgroud)\n\n

因此,如果 lambda 表达式是隐式类型的,则 LHS 变为 ,Iterator<CharSequence>而 RHS 为Iterator<String>。因此,出现错误:

\n\n
Iterator<String> cannot be converted to Iterator<CharSequence>\n
Run Code Online (Sandbox Code Playgroud)\n\n

JLS \xc2\xa718.5.3中也解释了此行为。

\n