> 文章列表 > Java 17 vs Java 8 (1) : var 详解

Java 17 vs Java 8 (1) : var 详解

Java 17 vs Java 8 (1) : var 详解

JEP (Java Enhancement Proposal) Link: https://openjdk.org/jeps/286

1. 基本用法对比

	// java 8 wayMap<String, List<MyDtoType>> myMap = new HashMap<String, List<MyDtoType>>();List<MyDomainObjectWithLongName> myList = aDelegate.fetchDomainObjects();// java 10 var myMap = new HashMap<String, List<MyDtoType>>();var myList = aDelegate.fetchDomainObjects()

2. var 是类型名,并不是关键字

var 是 Java 10 开始作为 局部变量类型推断 引入,在处理 var 时,编译器先是查看表达式右边部分,也就是构造器,并将它作为变量的类型,然后将该类型写入字节码当中(让编译器自己去推断类型);

这样避免了信息冗余,而且对齐了变量名,更容易阅读。当然:有些变量,比如以下例子当中的 connection,就无法立即知道它是什么类型的:

	var codefx = new URL("http://codefx.org");var connection = codefx.openConnection();var reader = new BufferedReader(new InputStreamReader(connection.getInputStream()));

不用担心变量名或方法名会与 var 冲突,因为 var 实际上并不是一个关键字,而是一个类型名,只有在编译器需要知道类型的地方才需要用到它。除此之外,它就是一个普通合法的标识符。也就是说,除了不能用它作为类名,其他的都可以,但极少人会用它作为类名:

	// invalid// int int = 2;// possible to usevar var = 2;

3. 使用范围 & 限制( 整理自 JEP )

适用范围

// 1. Local variables with initializersvar str = "Java 17 vs Java 8 (1) : var 详解 by Claudia.";// 2. Indexes in the enhanced for-loop / Locals declared in a traditional for-loopfor (var str : stringList) {System.out.println(str);}for (var i = 0; i < 3; i++) {System.out.println("index: " + i);}// 3. try-with-resources blockstry (var file = new FileInputStream("no-such-file")) {new BufferedReader(new InputStreamReader(file)).lines().forEach(System.out::println);} catch (IOException e) {// at least, we triedSystem.out.println("There's actually no `no-such-file`. :)");}

不适用范围

// 1. No Initialization// var x;// 2. No Explicit Target-Type in Lambda Expression// var lambdaFunc = () -> { };// 3. Null Initialization// var str = null;// 4. Method Formals// var returnValue = func();// 5. Lambda Assignment// var name = RandomClassWithRatherTediousName::getProperty;// 6. Array Initializer// var arr = { 1 , 2 };// 7. other cases: Constructor Formals, Method Return Types, Catch formals, etc.

4. AAD 错误

AAD: Action At A Distance,按照预期,编译器应该能够找出最具体的那个类型,但实际上它不会,JDK 团队想要避免“Action At A Distance”错误(AAD),也就是说,他们希望在某处修改了代码不会影响到其他很“远”的地方。比如:

import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;public class DemoVarAAD {public static void main(String... args) {// back in Java 8List<RandomClassWithRatherTediousName> clazzList8 = new ArrayList<>();clazzList8 = new LinkedList<>();// Java 17: cross fingers that compiler infers List<RandomClassWithRatherTediousName>var clazzList17 = new ArrayList<RandomClassWithRatherTediousName>();// actually it won't, below is a compiling error// clazzList17 = new LinkedList<>();}
}

在 Java 8 里编译器会推断出 clazzList8 是 List 接口类型并且是 ArrayList 具体实现类,所以当 clazzList8 被赋 LinkedList 具体实现类时是 OK 的,我们希望 Java 17 也能像 8 一样,实际并不是,Java 17 编译器不会认为 clazzList17 是 List 接口类,而是 ArrayList,和 LinkedList 是完全不同的类,所以 clazzList17 = new LinkedList<>(); 会出现编译报错,由此避免 AAD 错误。

以上,感谢浏览,不足欢迎指正 😉