JEP 101: Generalized Target-Type Inference | 广义目标类型推断
摘要
平滑地扩展方法类型推断的范围,以支持(i)方法上下文中的推断和(ii)链式调用中的推断。
目标
- 支持方法上下文中的方法类型参数推断
- 支持链式调用中的方法类型参数推断
非目标
- 全局类型推断
成功指标
通过减少方法类型推断的边缘情况,改善泛型的可用性。通过减少泛型方法调用中的显式类型参数,提高代码的可读性。
动机
自 JDK 5 以来,在泛型方法调用中,编译器自动推断泛型方法调用中的类型参数。类型推断不仅重要,因为显式类型参数有些笨拙和冗长,而且主要是因为许多程序员对它们不熟悉,结果无法处理类型参数推断未能给出正确答案的情况。因此,重要的是最小化方法类型推断失败的情况;我们认为通过添加以下功能的支持(i)参数位置推断和(ii)链式调用中的推断,可以大大改进方法类型推断。
描述
在此,我们提出了对现有类型参数推断支持的一些改进,这将显着减少泛型方法调用中显式类型参数的需求。
参数位置推断
考虑以下类声明:
javaclass List<E> { static <Z> List<Z> nil() { ... }; static <Z> List<Z> cons(Z head, List<Z> tail) { ... }; E head() { ... } }
泛型方法的结果,例如
List.nil()
,可以从赋值的右侧推断出来:javaList<String> ls = List.nil();
编译器的类型推断机制会推断出
List.nil()
调用的类型参数确实是String
。当将这样的泛型方法调用的结果传递给另一个方法时,编译器应该能够推断出类型,如下所示:javaList.cons(42, List.nil()); //error: expected List<Integer>, found List<Object>
不幸的是,在 JDK 5/6/7 中,程序员唯一可用的选项是使用显式类型参数:
javaList.cons(42, List.<Integer>nil());
如果类型参数推断可以扩展到考虑方法调用中的形式参数类型(目标类型推断),则这似乎是合理的。
链式调用中的推断
另一个相当常见的问题是泛型方法调用在链式调用中连接在一起,如下所示:
javaString s = List.nil().head(); //error: expected String, found Object
在上面的赋值中,右侧类型在类型参数推断中未使用,因此程序员的唯一选择是(再次)手动指定类型参数,如下所示:
javaString s = List.<String>nil().head();
再次,通过允许赋值的右侧类型(
String
)在一系列泛型方法调用中流动,可以消除显式类型参数的负担。
替代方案
手动指定类型参数(与今天一样)。
测试
需要验证新的推断算法的行为是否符合预期。需要验证新的推断算法是否以意外的方式破坏了向后兼容性(或需要确保不保留向后兼容性的情况足够少)。
此工作没有特殊的平台或硬件要求。
风险和假设
如上所述,此更改的主要风险是任何影响方法类型推断的更改都可能具有向后不兼容的潜力。由于本文所述的更改涉及 Java 语言/编译器的敏感领域(类型系统),因此需要测试资源来检查所提议的更改不会以意外的方式影响向后兼容性。如果需要,在 Project Lambda 完成之前可以提供支持所述功能的原型(即将使用目标类型推断推断 Lambda 表达式的形式参数的新型类型推断方法)。
依赖
此工作取决于 Project Lambda JEP -- Project Lambda 需要一种新的类型推断方法,称为目标类型推断,用于从使用 Lambda 表达式的上下文中推断 Lambda 表达式的形式参数的类型。本工作的一部分(方法上下文中的推断)只是利用了 Project Lambda 中使用的方法。本工作的另一部分(链式调用中的推断)是一种推断改进,将帮助采用 Project Lambda 开发类似于 LinQ 的技术。
影响
- 客户:更可读的代码(较少的显式类型参数)--更容易使用泛型方法/构造函数/钻石。
- CCC:需要对类型推断更改进行 CCC 覆盖。
- 兼容性:新的推断方案可能以微妙的方式更改可编译程序的集合--需要 JCK 团队测试更改。
- 文档:无
- JCP:无
- L10N:最小影响:可能会添加新的错误消息。