Java中的Var和val?

2,238 阅读4分钟

局部变量类型推理应该被添加到Java中吗?这就是Java语言团队现在正在思考的问题。

局部变量类型推理

JEP-286建议使用一个新的伪关键词(被视为 "保留的类型名称")来增加局部变量的推理。

我们试图通过减少与编写Java代码相关的仪式来改善开发者的体验,同时保持Java对静态类型安全的承诺,允许开发者省略通常不必要的局部变量类型的清单声明。

有人提出了一些可能的关键字。

  • var- 用于可变的局部变量
  • val--用于最终的(不可变的)局部变量
  • let- 用于最终的(不可变的)局部变量
  • auto--好吧,让我们忽略它吧......

考虑到实现策略,目前的final 关键字似乎仍将被接受在所有的选项前面,因此所有这些都将是最终(不可变)变量。

  • final var- 将可变的局部变量变为最终变量
  • final val--多余的附加修饰符
  • finallet--多余的附加修饰符

因此,选择似乎是在Java中加入这些组合之一。

  • varfinal var
  • varval- 但final varfinal val也有效
  • varlet--但final varfinal let也有效。

从广义上讲,我对这个功能不感兴趣,也不相信它真的能让Java变得更好。虽然IDE可以减轻编码时类型信息的损失,但我预计一些代码审查会明显困难(因为它们是在IDE之外完成的)。还应注意的是,C#的编码标准警告不要过度使用这一特性。

当类型从赋值的右边看不出来时,不要使用var。
不要依靠变量名称来指定变量的类型。它可能不正确。

说了以上这些,我怀疑停止这个功能的可能性很小。这篇博文的其余部分主要讨论为Java选择正确的选项

Java的最佳选择

当这个功能公布后,Scala和Kotlin的爱好者自然开始争论varval的问题。然而,虽然在其他语言中的优先权很好考察,但不一定适用,它是Java的最佳选择。

Java的最佳选择可能不同的主要原因是历史。Scala和Kotlin从一开始就有这个功能,而Java却没有。我想说明为什么我认为vallet对Java来说是错误的,因为这个历史。

考虑一下下面的代码。

 public double parSpread(SwapLeg leg) {
   

本地变量的类型推理会很好地适用于它。但是,让我们说,有一行的类型不清楚,所以我们选择保留它以增加清晰度(根据C#的指导方针)。

 public double parSpread(SwapLeg leg) {
   

好吧,你可能会说。但是,如果这段代码是在一个坚持把每个局部变量都标记为final的团队中写的呢。

 public double parSpread(

突然间,我们有了一个混乱。代码的某些部分使用final来表示一个 "最终的"(不可变的)局部变量。而代码的其他部分则使用val。这种混合是完全错误的,而且这种混合是你在Scala或Kotlin中得不到的。

(也许你没有在每个局部变量上使用final来编码?我知道我没有。但我知道这是一个相当普遍的编码标准,旨在增加代码的安全性并减少错误)。

将上述情况与另一种情况进行对比。

 public double parSpread(

这在Java内部是比较一致的。final仍然是各地用来获取final(不可变)变量的机制。如果你像我一样,不担心final关键字,它就会减少到这样。

 public double parSpread(

我理解许多读者现在的反对意见--认为应该有两个新的 "关键字",一个用于可变的局部变量,一个用于不可变的局部变量,而且两者的长度/权重应该相同(或者可变的那个应该更长),以推动人们更广泛地使用不可变的形式。

但是在Java中,这真的没有那么简单。我们有最终关键字已经很多年了。忽视它的结果是令人不快的和不一致的混乱。

总结

我个人根本不喜欢局部变量类型推理。但是如果我们要拥有它,我们必须让它很好地适应现有的语言。

我认为vallet根本不适合Java,因为final已经存在,而且在那个空间里有明确的含义。虽然不是很理想,但我必须为varfinal var争辩,因为这是唯一符合现有语言的关键标准的组合。