为什么JAVA 10中的var无法初始化为null?

Ama*_*bra 3 java java-10

我正在玩JAVA 10中引入的新功能,在那里我发现了一个非常有趣的事实,你不能用null声明一个变量.

一旦你写下一段代码,

var a = null;
Run Code Online (Sandbox Code Playgroud)

它抛出一个错误:

变量初始值设定项为null

现在,我们都知道我们不能将基本类型声明为null,所以下面的语句没有任何意义.

int a  = null;
Run Code Online (Sandbox Code Playgroud)

这意味着,如果开发人员正在使用null初始化var,那么它肯定希望在其中放置一个Object,而不是文字val.如果是这样,我的问题是

为什么编译器不认为它是Object var而是抛出错误.

另一方面,如果你写下面的声明,它完全正常:

var a = (Object)null;
Run Code Online (Sandbox Code Playgroud)

声明var为null的原因是什么

考虑下面的情况,我想初始化var并希望在条件块之外使用它:

var a = null;
if(some condition) Initialize with some arguements
else Initialize with some other arguements
//Use a varialble here
Run Code Online (Sandbox Code Playgroud)

因此,在这种情况下,因为我们希望a的范围在条件块之外,所以我们要求初始化它将在block之外为null,这是使用var无法实现的.

Nic*_*lai 13

编译器可以应用(至少)三种可能的类型推断策略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`
Run Code Online (Sandbox Code Playgroud)

如果编译器推断Nodeparent因为determineParent()返回它,则会编译.但是代码很脆弱,因为对最后一行的更改可能会导致在第一行中选择不同的类型,从而在第二行编译错误.这不好!

我们已经习惯了这样一个事实,即更改类型的声明可能导致错误,但这里的变化(第3行),其效果(第1行)和随之而来的错误(第2行)可能相差很远,这使得对于开发人员来说,理解或更好地预测会发生什么变得更加复杂.

通过简化类型推理规则,开发人员可以更容易地形成一个简单但正确的心理模型.

附录

有人怀疑选项3是否在技术上可行,从后期初始化推断出类型.我的意见(它是)基于我对JEP 286的理解,具体来说:

另一方面,我们可以扩展此功能以包括本地等效的"空白"韵母(即,不需要初始化器,而是依赖于明确的分配分析.)我们选择限制为"仅使用初始化器的变量",因为它覆盖了很大一部分候选人,同时保持了功能的简单性并减少了"远距离行动"错误.

同样,我们也可以在推断类型时考虑所有赋值,而不仅仅是初始化器; 虽然这会进一步增加可能利用此功能的本地人的百分比,但也会增加"远距离行动"错误的风险.

  • @StephenC(新)附录解释了我是如何得出这个结论的. (5认同)
  • 对不起,这是不对的.或者至少它是推测性的...除非你能指出**存在证据**.您断言可以使用强子类型定义和实现类型推断.我(过去)试图在三个不同的场合做到这一点,并在这个问题上遇到了障碍.现在,诚然,我可能不够聪明.但是,在我相信它之前,我希望在真正的编程语言实现中看到这个实例. (2认同)

Ste*_*n C 6

我在问我们如何在这种情况下扩大范围.因此,例如,如果我想在条件块中初始化变量但是想要扩展范围以便可以在块外部使用相同的变量,那么在var的情况下可以做什么.

答案是你要么使用:

var a = (RealType) null;
Run Code Online (Sandbox Code Playgroud)

或者(对它是明智的)你使用传统的类型声明:

RealType a = null;
Run Code Online (Sandbox Code Playgroud)

var形式仅仅是语法糖:一个方便,以避免不必编写特定的类型.初始化时,它根本不起作用null.推断Object的类型a没有用的行为在绝大多数情况下.


例如,如果(假设)a var可以分配一个null:

    var a = null;            
    if (something) {
        a = someMethodReturningRealType();
    }
    a.someRealTypeMethod();  // Compilation error ... because the inferred
                             // type is java.lang.Object.  Oops!!
Run Code Online (Sandbox Code Playgroud)

这是编写代码的正确方法:

    RealType a = null;       // Just use a classic variable declaration
    if (something) {
        a = someMethodReturningRealType();
    }
    a.someRealTypeMethod();
Run Code Online (Sandbox Code Playgroud)

我的例子就是分享我们可能需要将var声明为null的地方.似乎没有明确的方法可以做到这一点.

不,你不需要这样做.你做到这一点......但"想要"和"需要"并不是一回事.

而且,这是一个非常基本的问题,好像我们可以做到Object x = null;为什么我们无法做到var x = null;

因为JLS禁止它.而已.故事结局.

如果你不喜欢它,那很好.但这不是一个讨论论坛.我们不是那些需要被说服的人.

  • @StephenC你(以及几乎所有谈论此功能的人)都错误地使用了术语"语法糖".计算类型所需的分析不仅仅是句法; 因此,这不是语法糖. (6认同)