编译器可以应用于var o = null的(至少)三种可能的类型推断策略:
>挑选Void
>选择对象
>查找以后的初始化并选择该类型
所有这些都在技术上是可行的,因此问题出现了,哪一个对开发人员最有意义.
显然,Void是无用的,我认为Object也没有多大用处.虽然正确,但选择其中任何一种类型都不太可能帮助开发人员编写更好,更易读的代码.
var parent = null;
// imagine some recursion or loop structure, so this makes more sense
processNode(parent); // expects a parameter of type `Node`
parent = determineParent(); // returns a parameter of type `Node`
如果编译器推断Node为父,因为determineParent()返回它,这将编译.但是代码很脆弱,因为对最后一行的更改可能会导致在第一行中选择不同的类型,从而在第二行编译错误.这不好!
我们已经习惯了这样一个事实,即更改类型的声明可能导致错误,但这里的变化(第3行),其效果(第1行)和随之而来的错误(第2行)可能相差很远,这使得对于开发人员来说,理解或更好地预测会发生什么变得更加复杂.
通过简化类型推理规则,开发人员可以更容易地形成一个简单但正确的心理模型.
附录
有人怀疑选项3(从后来的初始化推断出类型)在技术上是否可行.我的观点(它是)基于我对JEP 286的理解,具体来说:
On the other hand, we could have expanded this feature to include the local equivalent of “blank” finals (i.e., not requiring an initializer, instead relying on definite assignment analysis.) We chose the restriction to “variables with initializers only” because it covers a significant fraction of the candidates while maintaining the simplicity of the feature and reducing “action at a distance” errors.
Similarly, we also could have taken all assignments into account when inferring the type, rather than just the initializer; while this would have further increased the percentage of locals that could exploit this feature, it would also increase the risk of “action at a distance” errors.