为什么Java中compose()需要显式类型转换而andThen()不需要?
核心原因是两个方法的泛型签名差异,结合String::toUpperCase的重载特性,导致Java类型推断能力不足以覆盖compose的场景
先给出Function<T, R>两个组合方法的标准签名:
// 先执行当前Function,再执行after <V> Function<T, V> andThen(Function<? super R, ? extends V> after) // 先执行before,再执行当前Function <V> Function<V, R> compose(Function<? super V, ? extends T> before)
你的示例中test是明确的Function<String, String>,也就是泛型参数T=String、R=String已经固定。
为什么andThen不需要显式转换
调用test.andThen()时,入参after的类型要求是Function<? super R, ? extends V>,这里R已经固定为String,所以after的入参类型必然是String。
此时传入String::toUpperCase,编译器可以直接匹配到无参重载版本String String.toUpperCase(),对应的函数描述符就是String->String,完全符合Function<String, String>的要求,类型推断可以直接完成,不需要额外强转。
为什么compose需要显式转换
调用test.compose()时,入参before的类型要求是Function<? super V, ? extends T>,这里T虽然固定为String(也就是before的返回类型必须是String),但类型变量V是未确定的——它是最终组合后函数的入参类型,编译器无法从调用上下文直接推断出V的具体值。
而String::toUpperCase存在两个重载版本:
- 无参版本:
String toUpperCase(),对应函数描述符String->String - 带参版本:
String toUpperCase(Locale),对应函数描述符(String, Locale)->String
在V未确定的情况下,编译器无法判断你要匹配哪个重载,甚至会尝试匹配带参版本,最终因为无法将默认推断的入参类型Object转换为Locale抛出你遇到的编译错误。
你显式添加(Function<String, String>)类型转换后,相当于明确告诉编译器V=String,且要匹配无参重载的String->String函数类型,类型推断才能正常完成。
内容的提问来源于stack exchange,提问作者Sharper

