Java 10 LocalVariable Type-Inference – Java 10局部变量的类型推理

最后修改: 2018年 5月 16日

中文/混合/英文(键盘快捷键:t)

1. Overview

1.概述

One of the most visible enhancements in JDK 10 is type inference of local variables with initializers.

JDK 10中最明显的改进之一是对带有初始化器的局部变量进行类型推理。

This tutorial provides the details of this feature with examples.

本教程提供了这一功能的细节和例子。

2. Introduction

2.绪论

Until Java 9, we had to mention the type of the local variable explicitly and ensure it was compatible with the initializer used to initialize it:

在Java 9之前,我们必须明确提到局部变量的类型,并确保它与用于初始化它的初始化器兼容。

String message = "Good bye, Java 9";

In Java 10, this is how we could declare a local variable:

在Java 10中,我们可以这样声明一个局部变量。

@Test
public void whenVarInitWithString_thenGetStringTypeVar() {
    var message = "Hello, Java 10";
    assertTrue(message instanceof String);
}

We don’t provide the data type of message. Instead, we mark the message as a var, and the compiler infers the type of message from the type of the initializer present on the right-hand side.

我们不提供message的数据类型。相反,我们将消息标记为var,编译器从右侧出现的初始化器的类型来推断message的类型。

In above example, the type of message would be String.

在上面的例子中,message的类型应该是String

Note that this feature is available only for local variables with the initializer. It cannot be used for member variables, method parameters, return types, etc – the initializer is required as without which compiler won’t be able to infer the type.

注意,该功能仅适用于带有初始化器的局部变量。它不能用于成员变量、方法参数、返回类型等–初始化器是必需的,因为没有初始化器,编译器将无法推断出类型。

This enhancement helps in reducing the boilerplate code; for example:

这一改进有助于减少模板代码;例如。

Map<Integer, String> map = new HashMap<>();

This can now be rewritten as:

现在,这可以改写为。

var idToNameMap = new HashMap<Integer, String>();

This also helps to focus on the variable name rather than on the variable type.

这也有助于将注意力集中在变量名称上,而不是变量类型上。

Another thing to note is that var is not a keyword – this ensures backward compatibility for programs using var say, as a function or variable name. var is a reserved type name, just like int.

另外需要注意的是,var不是一个关键字–这确保了使用var的程序的向后兼容性,例如,作为一个函数或变量名称。var是一个保留类型名,就像int一样。

Finally, note that there is no runtime overhead in using var nor does it make Java a dynamically typed language. The type of the variable is still inferred at compile time and cannot be changed later.

最后,请注意使用var没有运行时的开销,也没有使Java成为动态类型语言。变量的类型仍然是在编译时推断出来的,以后不能改变。

3. Illegal Use of var

3.非法使用var

As mentioned earlier, var won’t work without the initializer:

如前所述,没有初始化器,var将无法工作。

var n; // error: cannot use 'var' on variable without initializer

Nor would it work if initialized with null:

如果用null进行初始化,也不会起作用。

var emptyList = null; // error: variable initializer is 'null'

It won’t work for non-local variables:

它对非本地变量不起作用。

public var = "hello"; // error: 'var' is not allowed here

Lambda expression needs explicit target type, and hence var cannot be used:

Lambda表达式需要明确的目标类型,因此不能使用var

var p = (String s) -> s.length() > 10; // error: lambda expression needs an explicit target-type

Same is the case with the array initializer:

数组初始化器的情况也是如此。

var arr = { 1, 2, 3 }; // error: array initializer needs an explicit target-type

4. Guidelines for Using var

4.使用var的准则

There are situations where var can be used legally, but may not be a good idea to do so.

在有些情况下,var可以合法使用,但可能不是一个好主意。

For example, in situations where the code could become less readable:

例如,在代码可能变得不那么可读的情况下。

var result = obj.prcoess();

Here, although a legal use of var, it becomes difficult to understand the type returned by the process()making the code less readable.

在这里,虽然合法地使用了var,但变得难以理解process()返回的类型,使得代码的可读性降低。

java.nethas a dedicated article on Style Guidelines for Local Variable Type Inference in Java which talks about how we should use judgment while using this feature.

java.net有一篇关于Java中局部变量类型推断的风格指南的专门文章,其中谈到了我们在使用这一功能时应该如何进行判断。

Another situation where it’s best to avoid var is in streams with long pipeline:

另一种最好避免var的情况是在长管道的流中。

var x = emp.getProjects.stream()
  .findFirst()
  .map(String::length)
  .orElse(0);

Usage of var may also give unexpected result.

var 的使用也可能产生意想不到的结果。

For example, if we use it with the diamond operator introduced in Java 7:

例如,如果我们将其与Java 7中引入的钻石运算符一起使用。

var empList = new ArrayList<>();

The type of empListwill be ArrayList<Object>and not List<Object>. If we want it to be ArrayList<Employee>, we will have to be explicit:

empList的类型将是ArrayList<Object>而不是List<Object>。如果我们想让它成为ArrayList<Employee>,我们就必须明确说明。

var empList = new ArrayList<Employee>();

Using var with non-denotable types could cause unexpected error.

使用var与非可拒绝的类型可能会导致意外的错误。

For example, if we use var with the anonymous class instance:

例如,如果我们使用var与匿名类实例。

@Test
public void whenVarInitWithAnonymous_thenGetAnonymousType() {
    var obj = new Object() {};
    assertFalse(obj.getClass().equals(Object.class));
}

Now, if we try to assign another Objectto obj, we would get a compilation error:

现在,如果我们试图将另一个Object分配给obj,我们会得到一个编译错误。

obj = new Object(); // error: Object cannot be converted to <anonymous Object>

This is because the inferred type of obj isn’t Object.

这是因为obj的推断类型不是Object

5. Conclusion

5.总结

In this article, we saw the new Java 10 local variable type inference feature with examples.

在这篇文章中,我们通过实例看到了新的Java 10局部变量类型推断功能。

As usual, code snippets can be found over on GitHub.

像往常一样,代码片段可以在GitHub上找到over

Next »

Java 10 Performance Improvements