The dos and don’ts of Local Variable Type Inference
Local Variable Type Inference was undoubtedly the biggest feature in Java 10. Even though Java 10 is already old news, the enthusiasm for this feature has not faded away. If you’re still now sure why or how to use it, Oracle’s Brian Goetz recently wrote a FAQ. Let’s have a look!
Java 10’s Local variable type inference (JEP 286), which enhances the Java language to extend type inference to declarations of local variables with initializers, got a lot of people excited. Even though Java 10 is already old news, the enthusiasm for this feature has not faded away.
In an interview series about the most popular (and useful!) Java 10 features, Nicolai Parlog said the following:
Java 8’s lambda expression required quite a lot of engineering time and had a big impact on the look of Java code. Java 9 took even longer, but code will look pretty much the same. Java 10 comes with local variable type inference, i.e. the
varkeyword, which, compared to lambdas and the module system, is a pretty straightforward feature. In essence, it’s “just a small change in the compiler”. But if widely adopted, it will change the way Java code looks even more profoundly than lambda expressions did. Let’s see whether that will be the case.
At the same time, Greg Luck, CEO of Hazelcast, described JEP 286 as a feature “all Scala lovers will appreciate the most since it allows to skip the type declaration for local variables and loops.” However, he also pointed out that the functionality is limited only to local variables and for-loop indexes.
Local Variable Type Inference explained
Java SE 10 introduced type inference for local variables. Previously, all local variable declarations required an explicit (manifest) type on the left-hand side. With type inference, the explicit type can be replaced by the reserved type name
varfor local variable declarations that have initializers. The type of the variable is inferred from the type of the initializer.
Have you read the style guidelines for Local variable type inference? If the answer is no, you should do that asap in order to understand some of the tradeoffs, and to properly use
If you still don’t know when and how to use it, you should know that Brian Goetz, Java Language Architect at Oracle recently wrote a FAQ about this feature.
For example, he mentioned that “local variables are used only in the block in which they are declared, so the compiler can ensure that they’re always initialized before they’re used.” He emphasized that when it comes to understanding code, the name and initial value of a local variable are oftentimes more important than the type of the local variable. Even though one should not underestimate the importance of the type is important, “the way the name is used on the next line might be more important,” he explained. Therefore, using
var can help make the important parts of the local variable declaration stand out.
When you use
var instead of a type, the Java compiler infers the type of the variable from its initial value. This will come in handy when the type
- has a long name,
- is a complex parameterized type, or
- if the type is redundant with the initial value.
In short, your code will be more concise if you chooose to use
var. Not only is readability not sacrificed but in some cases, it can even be improved by removing redundancy.
However, the addition of
vardoesn’t make Java dynamically typed:
var, the Java compiler infers the type of the variable at compile time, using type information obtained from the variable’s initializer. The inferred type is then used as the static type of the variable. Typically, this is the same as the type you would have written explicitly, so a variable declared with
varbehaves exactly as if you had written the type explicitly.
– Brian Goetz
Speaking of debunked myths, you should also know that local variables declared with
var are non-final by default. You can, however, add the
final var person = new Person();
Keep in mind that you can only use
var where type inference is desired; if a type is explicitly declared, you won’t be able to use it. Even if you added
val, it too could be used only where type inference is used. “The use of
val in Java could not be used to control immutability if the type were declared explicitly,” Brian explained.
var cannot be used for:
- method parameters, and
- method return types.
Types in the locations mentioned above appear explicitly in class files, as well as in javadoc specifications. “With type inference, it’s quite easy for a change to an initializer to cause the variable’s inferred type to change. For local variables, this is not a problem, because local variables are limited in scope, and their types are not recorded directly into class files.” It only becomes problematic if types for fields, method parameters, and method return types were inferred.
var can be used for:
- declaring local variables,
- including index variables of for-loops and
- resource variables of the try-with-resources statement.
We’ve barely scratched the surface so make sure the read the entire FAQ before using Local Variable Type Inference.
Local variable type inference (JEP 286) is part of Project Amber. Its goal is to explore and incubate smaller, productivity-oriented Java language features that have been accepted as candidate JEPs under the OpenJDK JEP process.
Two JEPs have already been delivered: one is JEP 286 Local-Variable Type Inference (
var), delivered in JDK 10 and the other is JEP 323 Local-Variable Syntax for Lambda Parameters, delivered in JDK 11.