为什么编译器无法推断出 Stream.of 的内联 lambda 参数的类型?

Gon*_*n I 4 java lambda java-stream

为什么Stream.of()需要强制转换才能采用内联 lambda 表达式或方法引用?

考虑一下:

 Function<String,String> f = String::toUpperCase; // works without cast
 Stream.of(f); // works without cast
 //Stream.of(String::toUpperCase); // Error - target type must be functional interface
 Stream.of((Function<String,String>) String::toUpperCase); //OK
Run Code Online (Sandbox Code Playgroud)

对变量 f 的赋值不需要强制转换,但当用作 Stream.of 的内联参数时,需要强制转换。为什么?

Mar*_*eel 10

lambda 或方法引用本身没有类型,它从上下文(例如它分配给的变量)派生其类型,或者换句话说,它是上下文类型的。当您Stream.of(...)在没有进一步上下文的情况下使用来推断类型(例如返回,因此类型由返回类型指定,或分配给变量或参数,或使用显式泛型参数)时,没有可用于构造 lambda 或方法参考。

原因是 Java 不知道您是否需要Function<String, String>、 、UnaryOperator<String>或其他具有兼容签名的函数接口。

你需要做类似的事情:

public Stream<Function<String, String>> example1() {
    return Stream.of(String::toUpperCase);
}

public void example2() {
    Stream<Function<String, String>> stream = Stream.of(String::toUpperCase);
}

public void example3() {
    Stream.<Function<String, String>>of(String::toUpperCase);
}

public void example4() {
    doSomething(Stream.of(String::toUpperCase));
}

private void doSomething(Stream<Function<String, String>> stream) {
    // ...
}
Run Code Online (Sandbox Code Playgroud)

另请参阅有关 lambda 的 Java 教程,特别是目标类型部分:

[...]这些方法期望的数据类型称为目标类型。为了确定 lambda 表达式的类型,Java 编译器使用找到 lambda 表达式的上下文或情况的目标类型。因此,您只能在 Java 编译器可以确定目标类型的情况下使用 lambda 表达式:

  • 变量声明
  • 作业
  • 退货声明
  • 数组初始值设定项
  • 方法或构造函数参数
  • Lambda 表达式体
  • 条件表达式,?:
  • 投射表情