Java 10 局部变量类型推断功能
1. 概述
JDK 10 中最明显的增强功能之一是使用初始化器对局部变量进行类型推断。 本教程通过示例提供了此功能的详细信息。
2. 简介
在 Java 9 之前,我们必须明确提及局部变量的类型,并确保它与用于初始化它的初始化程序兼容:
String message = "Good bye, Java 9";
在 Java 10 中,我们可以这样声明局部变量:
@Test
public void whenVarInitWithString_thenGetStringTypeVar() {
var message = "Hello, Java 10";
assertTrue(message instanceof String);
}
我们不提供消息的数据type。相反,我们将message标记为var,编译器会根据右侧的初始化程序类型推断message 的类型。
在上面的例子中,message的类型是String。 **请注意,此功能仅适用于具有初始值设定项的局部变量。**它不能用于成员变量、方法参数、返回类型等——初始化器是必需的,因为没有它编译器将无法推断类型。 此增强功能有助于减少样板代码;例如:
Map<Integer, String> map = new HashMap<>();
现在可以重写为:
var idToNameMap = new HashMap<Integer, String>();
这也有助于关注变量名称而不是变量类型。
另一件需要注意的事情是var不是关键字——这确保了使用var作为函数或变量名的程序的向后兼容性。var 是保留的类型名称,就像int一样。 最后,请注意使用**var没有运行时开销,也不会使 Java 成为动态类型语言。**变量的类型仍然在编译时推断,以后不能更改。
3. 非法使用var
如前所述,如果没有初始化程序, var将无法工作:
var n; // error: cannot use 'var' on variable without initializer
如果用null初始化也不会工作:
var emptyList = null; // error: variable initializer is 'null'
它不适用于非局部变量:
public var = "hello"; // error: 'var' is not allowed here
Lambda 表达式需要明确的目标类型,因此不能使用var :
var p = (String s) -> s.length() > 10; // error: lambda expression needs an explicit target-type
数组初始值设定项也是如此:
var arr = { 1, 2, 3 }; // error: array initializer needs an explicit target-type
4. 使用var的指南
有些情况下var可以合法使用,但这样做可能不是一个好主意。 例如,在代码可能变得不那么可读的情况下:
var result = obj.prcoess();
在这里,虽然var是合法使用,但很难理解 process()返回的类型,从而降低了代码的可读性。 java.net 有一篇专门的文章Style Guidelines for Local Variable Type Inference in Java 讲了我们在使用这个特性时应该如何使用判断。 最好避免使用var的另一种情况是在具有长管道的流中:
var x = emp.getProjects.stream()
.findFirst()
.map(String::length)
.orElse(0);
使用var也可能会产生意想不到的结果。
例如,如果我们将它与 Java 7 中引入的菱形运算符一起使用:
var empList = new ArrayList<>();
empList的类型将是ArrayList<Object>而不是List<Object>。如果我们希望它是ArrayList<Employee>,我们必须明确:
var empList = new ArrayList<Employee>();
将var与不可表示的类型一起使用可能会导致意外错误。 例如,如果我们将var与匿名类实例一起使用:
@Test
public void whenVarInitWithAnonymous_thenGetAnonymousType() {
var obj = new Object() {};
assertFalse(obj.getClass().equals(Object.class));
}
现在,如果我们尝试将另一个Object分配给obj,我们会得到一个编译错误:
obj = new Object(); // error: Object cannot be converted to <anonymous Object>
这是因为obj的推断类型不是Object。