当我们看到var的时候,首先想到的会是javascript。如果我像下面这样写,会不会觉得有编译错误?var users = new ArrayList();
JAVA 10引入了var,这种写法已经合法。那为什么JAVA要引入var呢?这种写法到底好不好?我们探讨下。
一般我们在定义一个变量的时候,会在左右两边都写一遍类型,比如:URL url = new URL("www.baidu.com");
接下来会是这种代码:URL baidu = new URL("http://www.baidu.com");
URLConnection connection = baidu.openConnection();
Reader reader = new BufferedReader(new InputStreamReader(connection.getInputStream()));
我们定义这些只使用一次的中间变量/临时变量,还得把它的类型完整写出来,会不会觉得有点多余?可不可以省略这一步,让编译器来帮我们做?可以的。从JAVA 10开始,编译器可以推导这些类型,只要你使用var关键字。var baidu = new URL("http://www.baidu.com");
var connection = baidu.openConnection();
var reader = new BufferedReader(new InputStreamReader(connection.getInputStream()));
想想编译器会怎么做?很简单。对比上面的两个代码块,区别就在于一个有类型,一个只有var。编译器会根据等号右边的类型推导出左边的类型,替换掉var,并且写入字节码。实际上,最后上面两个代码块的字节码是一样的。
这样带给我们什么样的便利呢?首先肯定是少打了几个字母。其次,阅读起来很简洁。当然也有不好的地方:没法直观知道变量的类型。当然,你说不是还有IDE可以帮我们么?那我们做code review的时候呢?
另外,你可能会想,是不是JAVA 10之后方法名或者变量都不能定义成var了?不会的。var在JAVA 10中并不是一个关键字,而只是一个保留的通用类型名。什么意思呢?只要你不把类名定义成var,其他场景你随便用。
对于前后端都精通的人,代入感不要太强。这写的不是js,js的神奇在JAVA语言里是不存在的,比如下面这幅图。
javascript
好了,上面说的都懂了吧?懂了的话,我们来想想下面几个问题:
1. 什么时候可以用var?什么时候不能用?
大家先看看JEP286。如果觉得看的麻烦,我解释一下:定义一个有初始值的局部变量时就可以用。像下面这种写法就是不行的:var foo;
foo = "foo";
即便它是等价于var foo = "foo"也是不行的。下面这些写法也是不行的,包括lamda表达式方法引用:var ints = {0, 1, 2}; //要使用new int[] {0, 1, 2}
var appendSpace = a -> a + " ";
var compareString = String::compareTo;
private var getFoo() {
return "foo";
}
写成下面这样是可以的:var numbers = List.of("a", "b", "c");
for (var nr : numbers) //for遍历时使用var声明变量
System.out.print(nr + " ");
for (var i = 0; i < numbers.size(); i++) //for遍历时使用var代表索引
System.out.print(numbers.get(i) + " ");
另外,var也可以用于编程结构的改变。想象一下下面这种场景:(new Object(){
void foo(){
System.out.println("I am in foo");
}
}).foo();
定义了一个匿名对象,有一个方法叫foo。以前如果我们用Object接住这个类,那foo没有办法调用,因为它不是Object的方法。如果我们用var还可以这样写:var obj = new Object(){
public void foo(){
System.out.println("I am in foo");
}
};
......
obj.foo();
这里定义的匿名对象,编译器推断它有一个foo方法,使用var保留推断的类型信息,在后面调用foo方法都是没问题的。
所以,在以下场景使用var是完全没有问题的:
a. 局部变量。
b. for循环声明变量。
c. for循环索引变量。
2. 为什么成员变量和方法不能使用var?
这里的方法包括构造方法和一般性的方法。方法的参数和返回值都是不能使用var的。
成员变量和方法相对于局部变量来说,作用范围更大,使用var更容易出错,比如在方法中修改var变量的类型导致运行时异常。还有,对于使用var的地方,编译器都必须能够准确推断出类型信息,而成员变量和方法都是很难推断的。
3. 以后是不是本地变量都要用var呢?
未必。使用var确实能给我们带来便利,但是随之而来的是代码可读性变差。如果太多的var,看代码的人可能会很困惑,花不少时间在看类型上面。所以使用要适度,毕竟代码要给人看的,要是只有你一个人,那当我没说。Oracle JAVA架构师Brian Goetz这样说:Use the var construct when it makes the code clearer and more concise and you’re not loosing essential information.
他的意思其实就是我们要把握好尺度,既要保证代码清爽精练,还要不能丢掉必要的信息。
好了,本次介绍var就到这里。如有介绍不清的地方,尽管拍砖。