介绍 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<string>()</string>
值得注意的是,这种类型会被推断为实际的类型;这种情况下,应该优先使用接口来代替。然而在大多数情况下鉴于它仅适用于局部变量,这种差别并不是特别有意义的。
也有人提出问题,是否其他类关键字结构也可能是有用的,例如为只读变量提供不同的结构。虽然 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 读者交流群(#2))。
评论