谈谈 Java10 中的 var 关键字

前言

几天前 Oracle 正式发布了 Java10,结果就是引来了一大波不懂 Java 的人跟风黑…… 然而这并不稀奇,几乎没有新鲜感可言。

因为真正关注 Java 的就应该知道,Java10 的发布周期和新特性在好几个月前都已经知道了,只不过这次正式发布的相关报道被幅度更大的传播出来了,让很多人以为这个新闻里边都是些以前从来不知道的新东西,其实在几个月前就基本上全部都知道了谢谢:)

最忍受不了的还是一些人跟风抖机灵,特别是对 var 的认知…… 所以我发这篇文章就是想吐槽一下这个现象。

var

在 Java10 中新增了一种在某些条件下可以使用 var 声明本地变量的方式,不必显式声明变量类型。这个特性可以看作是 Java 在语法层面上对“类型推断”的扩展支持。
为什么这么说?因为实际上局部类型推断(或者说推导)在 Java8 上就已经有体现了:Lambda 就是一个例子。所以说 Java10 才实现局部类型推断是不准确的。

还有抖机灵说 Javascript 抄了 Java 这么多年,总算轮到 Java 回头抄了一次 Javascript 了。甚至还有人说 Java10 越来越像 Javascript 了,对前端开发人员学习更友好……
我的天,这两者完全就不是一个概念。JS 中用 var 声明变量是因为它本身是一个弱类型语言,就是不用 var 那就用 let 用 const 但不可能在声明时就限定类型,除非你将 JS 改造为强类型语言。并且 JS 中的 var 跟类型推断没有关系:)

Java 中的 var 的功能其实很有限,作用很小但是对编写代码的友好程度有较高的提升。例如:

// Java 6
ArrayList<String> list6 = new ArrayList<String>();

// Java 7
ArrayList<String> list7 = new ArrayList<>();

// Java 10
var list10 = new ArrayList<String>(); 

从这段代码可以看出来,从 Java6 过渡到 Java7 的时候就已经减少了一点“编码形式”。当然这种程度仍然不够,既然在初始化值的时候就能确保推断出变量类型为什么还要用声明关键字多定义一次类型呢?所以 var 诞生了。

同样的,对于强类型语言,方法调用的返回值一定是类型固定和确定的。那么为什么还需要多余的定义一次类型声明呢?

// Java7
Stream<String> stream = list.stream();

// Java10
var stream = list.stream();

还有例如 for 循环中:

for(var i=0; i<list.size(); i++){
    System.out.println(list.get(i));
}

再看看我们平常接触的 Java 代码是不是有大量的显式声明类型的完全可以不存在的“形式代码”?所以说 var 作用虽小,但是对代码的编写友好度确实提高了很多。特别是对于非 IDE 用户,简直提升了几个次元。

不过有意思的是,Java 为了兼容旧版本代码,编译器不会将 var 当做保留字。也就是说,变量名或者方法名甚至类名等元素仍然可以 var 来命名,例如这样:

for(var var=0; var<list.size(); var++){
    System.out.println(list.get(var));
}

所以请不要将 var 当做保留字(或者关键字),你当它是一个比较特殊的存在就是了:)

关于争议

有些人认为 var 的引入并不是个好现象,因为代码不够直观了。这是毫无疑问的…… 任何有类型推断的语言或者弱类型语言都有这个现象。所以产生了一些针对动态类型语言的静态分析工具:)

当然,对于 Java 而言仍然是类型安全的,var 只是在代码层面存在的“表象”而已,编译后的字节码仍然定义了具体的类型。
因为我使用过很多的强类型但支持类型推断的语言,例如 Scala/Kotlin/Golang/Rust 甚至 C# 都支持。它们都可以用无类型的关键字声明变量,并且写这种代码很舒服,对 IDE 的依赖没有那么强烈,所以我当然是持乐观态度的。

至于有些只写 Java 代码的人,可能会觉得读代码的时候看到方法调用却不知道接收变量的类型会觉得不安心,那我只能跟你说,换一个支持代码跳转或能显示方法签名和注释的编辑器或者 IDE 即可:)

结束语

var 的加入让我对 Java 死板的语法又有了改观,半年一次的大版本更新周期计划让 Java 这个“老家伙”仿佛一下子充满了活力呢。