JEP 286 提议在 Java 局部变量中引入类型推断

  • Alex Blewitt
  • 任美芒

2016 年 3 月 16 日

话题:Java语言 & 开发

介绍JEP 286的提议已经发送到JEP 讨论平台(platform-jep-discuss)邮件列表中,如果能够实现,将在 Java 局部变量中引入类型推断。由于这只是一个初期阶段的提议,因此并没有计划在 Java 哪个版本中实现,甚至可能不会实现。

类型推断是指声明一个变量但无需指定其相关联的类型。类型推断在 Java 中已经存在一段时间;Java 5 中引入泛型时,便是利用类型推断处理泛型方法。Java 7 中增加了钻石(diamond)运算符 <>(Coin 项目中的一部分)允许 List 类型的变量被初始化而不需要 ArrayList<> 类型的约束。最近,Java 8 中增加了 lambdas 和 streams 功能,可以在方法链中推断类型以及 lambda 参数的形参类型。通常可以从上下文或初始化程序的表达式中推断出类型的信息。类似地如果表达式是无类型的 (如 0 或 null) 则不一定会得到正确的类型推断。类型推断相关内容甚至占据了Java 语言规范整个第 18 章

因为类型推断早已经被支持,并且可以有效地推断 final 局部变量,设想它被用于 Java 局部变量并不是一个大难题。它仅用于局部变量(这些变量通过方法或 lambda 函数体定义)而不是方法签名或字段签名。

提议中对于声明推断类型的变量提供了一个类关键字 var。在支持类型推断的语言中,通常把类型放在变量名的后面,这样一个变量或参数可以定义为 aNumber:Int 或者 aNumber,有效地将类型的定义(:Int)作为可选的后缀。但是,Java 是基于 C 语言,把类型放在第一位,而且这几乎是不可改变的。这样类关键字 var 被用来当作占位符代表“任何类型”,类似于其他语言中变量的定义方式。因此,它有可能写出这样的语句:

var proposal = "JEP-286";

这种情况下,变量的类型将被推断为字符串,表达式的实际类型在另一边。这也将简化泛型数据结构,例如:

var phonebook = new HashMap()

值得注意的是,这种类型会被推断为实际的类型;这种情况下,应该优先使用接口来代替。然而在大多数情况下鉴于它仅适用于局部变量,这种差别并不是特别有意义的。

也有人提出问题,是否其他类关键字结构也可能是有用的,例如为只读变量提供不同的结构。虽然 final var 可以拿来使用(对于 final 的有效推断已经比较成熟,也许没有必要使用其他类关键字结构),但是是否还有其他的可能性,这个灵感来自其他语言,如 const,val 或 let。对于变量的声明也会有其他的可能,例如 auto。JEP 提议者请求大家给予反馈。有一项调查来征求大家的意见,这样是很有用的。

建议方案的实施不是使 var(或 auto/let/def/val ...)成为一个新的关键字,这将会导致已经使用它们作为标识符的 Java 程序作废。相反,他们会保留这些类型名称,像 Object 或 String 一样有效。用 var 作为现有类型(class 或 interface)的应用程序将被中断,但这将打破现有的 java 命名规则。

通过原型实现和扫描现有 JDK 源代码,结果显示大多数情况下,局部变量切换为使用 var 是没有问题的。少数情况下不能成功地推断出结果,或者是因为没有初始化值,初始化为 null(当然可以是任何类型) 或者是因为推断出了比指定类型更严格的类型 (例如指定类型为 List,推断结果却是 ArrayList)。这确实表明,这个想法在实践中是可行的,在大多数情况下是有用的。

在 JDK 源代码下运行原型,结果如下:

  • 83.5% 推断出在源代码中存在的准确类型
  • 4% 推断出另一个可表示的类型(通常是更精准的类型)
  • 0% 由于推断的类型不可表示被拒绝
  • 8.5% 由于没有初始化被拒绝
  • 3% 由于初始化值为 null 被拒绝
  • 0.5% 由于需要一个目标类型被拒绝

如果我们排除由于没有初始化或初始化结果为 null 而被拒绝的案例,我们可以发现超过 99% 的局部变量可以被推断,95% 可以推断出正确的结果。

有效的 final 局部变量 (所有局部变量的 77%):

  • 86% 推断出在源代码中存在的准确类型
  • 4% 推断出另一个可表示的类型式(通常是更精准的类型)
  • 0% 由于推断的类型不可表示被拒绝
  • 8% 由于没有初始化被拒绝
  • 0.5% 由于初始化值为 null 被拒绝
  • 0.5% 由于需要一个目标类型被拒绝

提议中把这部分内容加入 Java 语言未来版本中,将会在JEP 286旗帜下进行讨论;如果有任何意见,请与 2016 年 3 月 16 日调查问卷关闭之前填写问卷信息反馈给 Java 团队。

查看英文原文:JEP 286 Proposes Extending Type Inference to Local Variables in Java


感谢张龙对本文的审校。

给 InfoQ 中文站投稿或者参与内容翻译工作,请邮件至editors@cn.infoq.com。也欢迎大家通过新浪微博(@InfoQ@丁晓昀),微信(微信号:InfoQChina)关注我们,并与我们的编辑和其他读者朋友交流(欢迎加入 InfoQ 读者交流群InfoQ 好读者(已满),InfoQ 读者交流群(#2)InfoQ 好读者)。

Java语言 & 开发