lostars
发布于 2020-04-14 / 2791 阅读
0

JAVA 10 新特性 - 局部变量推断

Java 10 添加了一个非常重要的新特性:局部变量类型推断。

在声明局部变量的时候使用下面的方式:

var intValue = 1;
var doubleValue = 1.1;
var stringValue = "string";
var list = new ArrayList<>();
var map = new HashMap<>();

局部变量推断使用的是 var ,同时 var 并不是一个关键词,而是一个保留类型名,所有使用var进行命名的方法、属性、变量都不会受到任何影响;但是使用var命名的类名和接口会受到影响,如果是新建类或者接口使用var则会编译不通过。后者其实可以忽略,因为类名和接口命名都是遵循的驼峰,刚好规避了var这个单词。

就从编码上来说,代码上会简洁不少,少了挺多的冗余代码。但是有好处就有坏处,代码的可读性比以前低,无法直观的看到变量类型,如果存在大量局部变量的调用和声明代码读起来可能就不太舒服了。不过个人觉得是提升了不少效率,再也不用显示声明变量类型了。

变量推断可以使用的场景:

  • 局部变量的初始化,不能使用 var 进行不初始化的声明;
    比如:
    var a;
    
  • for循环(包括for-each)迭代中的索引和迭代元素引用(其实也算是局部变量);

同时需要注意下面几点:

  • 无法从null值中推断,也就是说如果声明的地方有隐式的null值会抛出空指针;
    比如:
    public void loop(List<Integer> ints) {
        for(var i : ints) {
            // ...do something
        }
    }
    // 调用会直接抛出空指针
    loop(Arrays.asList(1, null, 2, 4))
    
  • 无法使用在方法中、构造器、返回值、属性声明、异常处理和其他变量初始化场景,可以直接直接理解成只能使用在局部变量上;
    比如下面的代码:
    public var test(var p1, var p2) {...}
    
  • 无法推断未初始化的变量;

看下上面代码的class文件反编译后的代码:

int intValue = true;
double doubleValue = 1.1D;
String stringValue = "string";
new ArrayList();
new HashMap();

编译完后的class中其实已经是正确的类型了,可以知道类型推断是发生在编译期的,在编译期间,编译器会执行推断进行类型转换,如果变量为null则会抛出空指针异常。
可以看到其实局部变量推断是一种新的语法糖,jvm是不认识这个东西的,整个推断过程都是发生在编译期,jvm不需要任何的改动来支持这个特性。

参考文档:
https://openjdk.java.net/jeps/286


整个Java10的新特性看了一遍,也就这个是个比较大的改动,并且是直接对编码上有着不少的效率提升。