跳到主要内容

JEP 101:广义目标类型推理

概括

平滑扩展方法类型推断的范围,以支持 (i) 方法上下文中的推断和 (ii) 链式调用中的推断。

目标

  • 添加对方法上下文中方法类型参数推断的支持
  • 添加对链式调用中方法类型参数推断的支持

非目标

  • 全局类型推断

成功指标

通过减少方法类型推断极端情况来提高泛型的可用性。通过减少泛型方法调用中的显式类型参数来提高代码的可读性。

动机

自 JDK 5 起,泛型方法调用中的类型参数由编译器自动推断。类型推断很重要,不仅因为显式类型参数有些尴尬和冗长,而且主要是因为许多程序员不熟悉它们,因此,无法应对类型参数推理无法给出正确答案的情况。因此,尽量减少方法类型推断失败的情况非常重要;我们相信,通过添加对以下功能的支持,可以极大地改进方法类型推断:(i) 参数位置推断和 (ii) 链式调用推断。

描述

在这里,我们提出了对现有类型参数推理支持的一些改进,这将显着减少泛型方法调用中对显式类型参数的需求。

我。论证位置的推论

考虑以下类声明:

class List<E> {
static <Z> List<Z> nil() { ... };
static <Z> List<Z> cons(Z head, List<Z> tail) { ... };
E head() { ... }
}

通用方法(例如 List.nil())的结果可以从赋值的右侧推断出来:

List<String> ls = List.nil();

编译器的类型推断机制发现 List.nil() 调用的类型参数确实是 String。当此类泛型方法调用的结果传递给另一个方法时,编译器应该能够推断出类型,这似乎是合理的,如下所示:

List.cons(42, List.nil()); //error: expected List<Integer>, found List<Object>

不幸的是,JDK 5/6/7 中不允许这样做——程序员唯一可用的选择是使用显式类型参数:

List.cons(42, List.<Integer>nil());

如果类型参数推断能够扩展以考虑方法调用中的形式参数类型(目标类型),那就太好了。

二.链式调用中的推理

另一个相当常见的问题是泛型方法调用链接在一起时,如下所示:

String s = List.nil().head(); //error: expected String, found Object

上述赋值中的右侧类型在类型参数推断期间未使用 - 因此,程序员的唯一选择是(再次)手动指定类型参数,如下所示:

String s = List.<String>nil().head();

同样,最好通过允许赋值的右侧类型(字符串)流经泛型方法调用链来消除显式类型参数的负担。

备择方案

手动指定类型参数(就像今天一样)。

测试

需要验证新的推理算法是否按预期运行。需要验证新的推理算法不会以意外的方式破坏向后兼容性(或者需要确保不保留向后兼容性的情况非常罕见)。

没有特殊的平台或硬件要求。

风险和假设

如上所述,此更改的主要风险是影响方法类型推断的任何更改都可能导致向后不兼容。由于本文档中描述的更改会影响 Java 语言/编译器(类型系统)的敏感区域,因此需要测试资源来检查提议的更改不会以意外的方式影响向后兼容性。如果需要,可以在相对较短的时间内(即在 Lambda 项目完成之前)提供支持所描述功能的原型。

依赖关系

这项工作依赖于 Lambda 项目 JEP——Lambda 项目需要一种新颖的类型推断方式,称为目标类型推断,用于从 lambda 表达式所在的上下文推断 lambda 表达式的形式类型。用过的。这项工作的一部分(方法上下文中的推理)只是 lambda 项目中使用的方法的概括。这项工作的另一部分(链式调用中的推理)是推理改进,这将有助于采用 Lambda 项目来开发类似 LinQ 的产品。

影响

  • 客户:更易读的代码(更少明确的类型参数)——更容易使用泛型方法/构造函数/钻石。
  • CCC:需要 CCC 来涵盖类型推断更改
  • 兼容性:新的推理方案可能会以微妙的方式改变可编译程序集——JCK 团队测试这些变化至关重要。
  • 医生:无
  • JCP:无
  • L10N:影响最小:可能会添加新的错误消息