3 回答
TA贡献1784条经验 获得超7个赞
编译器可以应用于(至少)三种可能的类型推断策略var o = null
:
挑选
Void
挑选
Object
寻找稍后的初始化并选择该类型
所有这些在技术上都是可行的,因此出现了一个问题,这对开发人员来说最有意义。
显然,这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为parent,因为determineParent()回报它,这将汇编。但是代码很脆弱,因为更改最后一行可能会导致在第一行中选择不同的类型,从而在第二行中编译错误。这不好!
我们已经习惯了这样的事实,即更改类型的声明可能会导致错误,但在此更改(第3行),其效果(第1行)和随之而来的错误(第2行)可能相距甚远,这使得对于开发人员来说,了解或更好地预测会发生什么事情要复杂得多。
通过保持简单的类型推断规则,开发人员可以更轻松地形成一个简单但正确的思维模式。
附录
令人怀疑的是,从以后的初始化中推断类型的选项3在技术上是否确实可行。我的看法是基于对JEP 286的理解,尤其是:
另一方面,我们可以将该功能扩展为包括“空白”末尾的局部等效项(即,不需要初始化程序,而是依赖于明确的赋值分析。)我们选择了“仅具有初始化程序的变量”的限制覆盖了很大一部分候选对象,同时保持了功能的简单性并减少了“远距离操作”错误。
同样,在推断类型时,我们也可以考虑所有分配,而不仅仅是初始化程序。虽然这将进一步增加可利用此功能的本地人的比例,但也会增加“远距离行动”错误的风险。
TA贡献1798条经验 获得超7个赞
我要问的是,在这种情况下,我们如何扩大范围。因此,例如,如果我想在条件块内初始化变量,但又想扩展范围,以便可以在块外使用相同的变量,那么在var情况下可以做什么。
答案是您可以使用:
var a = (RealType) null;
或(对此很明智)使用常规的类型声明:
RealType a = null;
的var形式仅仅是语法糖:一个方便,以避免不必编写特定的类型。当您使用初始化时,它根本不起作用null。推断Object的类型a是没有用的行为在绝大多数情况下。
例如,如果(假设)为avar分配了null:
var a = null;
if (something) {
a = someMethodReturningRealType();
}
a.someRealTypeMethod(); // Compilation error ... because the inferred
// type is java.lang.Object. Oops!!
这是编写代码的正确方法:
RealType a = null; // Just use a classic variable declaration
if (something) {
a = someMethodReturningRealType();
}
a.someRealTypeMethod();
我的示例只是分享我们可能需要将var声明为null的所有地方。似乎没有明确的方法可以做到这一点。
不。您不需要这样做。您想这样做...但是“想要”和“需要”不是同一回事。
而且,这是一个非常基本的问题,好像我们可以做到Object x = null;为什么我们不能做到var x = null;
因为JLS禁止这样做。就是这样。故事结局。
如果您不喜欢它,那很好。但这不是讨论论坛。无论如何,我们不是需要说服的人。
TA贡献1780条经验 获得超1个赞
从Oracle JDK 10页面:
您不能只使用var语法来声明没有值的变量,也不能将var变量初始化为null。实际上,尚不清楚类型应该是什么,因为它可能打算用于后期初始化。
因此,基本上,您必须具体确定所需的数据类型,编译器不能仅仅假定您想要的数据类型Object或任何其他类型。
因此,以下所有操作均会导致编译失败:
var x;
var x = null;
var x = () -> {}
添加回答
举报