为什么Stream.of传入内联lambda或方法引用时需要强制类型转换?
为什么
Stream.of()接收内联lambda表达式或方法引用作为入参时需要强制类型转换? 先给出问题中的示例代码:
import java.util.function.Function; import java.util.stream.Stream; // 直接赋值给明确类型的变量,无需强制转换 Function<String,String> f = String::toUpperCase; // 传入变量,无需强制转换 Stream.of(f); // 直接传入内联方法引用,编译报错:目标类型必须是函数式接口 // Stream.of(String::toUpperCase); // 添加强制类型转换后编译正常 Stream.of((Function<String,String>) String::toUpperCase); // 也可以通过显式指定泛型参数实现同样效果,无需强制转换 // Stream.<Function<String,String>>of(String::toUpperCase);
底层原因
这个现象完全是由Java的类型推断规则和方法引用/lambda的语法特性决定的:
- 方法引用和lambda表达式属于多态表达式,本身没有固定的固有类型,它们的实际类型必须由上下文的目标类型推导得出,只要匹配函数式接口的抽象方法签名,就可以适配任意符合要求的函数式接口类型。
- 把方法引用赋值给显式声明类型的
Function<String,String> f变量时,左值已经明确给出了目标类型,编译器可以直接匹配String::toUpperCase的方法签名(入参String、返回值String)和Function接口的抽象方法签名,自动完成类型推断,不需要额外转换。 Stream.of()是泛型方法,签名为<T> Stream<T> of(T value),直接传入内联的String::toUpperCase时,没有足够的上下文信息告诉编译器泛型参数T应该匹配哪一种函数式接口:符合String->String签名的函数式接口不止Function一种,UnaryOperator<String>、自定义的同签名函数式接口都可以匹配,编译器无法自动确定你要使用的具体类型,因此会抛出目标类型不明确的编译错误。- 给内联方法引用加上强制类型转换
(Function<String,String>)后,相当于手动指定了表达式的目标类型,编译器就可以直接推导出Stream.of()的泛型参数T为Function<String,String>,编译就能正常通过。
内容的提问来源于stack exchange,提问作者Gonen I
相关产品推荐
相关产品推荐

