The “var” syntax for local variables since Java 10

Java 10, released on March 2018, has introduced the new “var” syntax, a small but useful feature that allows you to declare local variables using the word “var” instead of specifying the type of the variable. This articles is focused on describing all the important rules about this new feature in a clear and concise way.

Introduction

The new “var” syntax brings a new level of type inference into the Java language, because the compiler can now infer the type of the variable from the initialized value. In practice, it’s possible to do something like:

var message = "Hello";                   // Java 10+
var bignum = BigInteger.valueOf(1234);   // Java 10+

instead of:

String message = "Hello";
BigInteger bignum = BigInteger.valueOf(1234);

There are some well known rules and restrictions on this new syntax. Some of these rules are quite easy and obvious to understand, while others are a bit less intuitive. However, all these rules are here to stay, so you must learn and remember all them as described in the following sections.

The word “var” is not a keyword

The Java Language Specification (JLS for short, available at the Java SE Specifications page) is quite clear on this point. The section §3.9. Keywords of the JLS clearly states that “var” is not a keyword and thus it is not a reserved word of the language.

Instead, “var” is a contextual keyword, a word with a special meaning only in the context of local variable declarations. This has some particular and surprising conseguences, because the word “var” can still be used as normal identifier in other variable or parameter declarations. For example, it is perfectly legal to do this:

public static int square(int var) {   // Ok
    return var * var;
}

and also this:

BigInteger var = BigInteger.valueOf(1234);   // Ok

And it is even possible (but please, never do this!):

var var = "Hello";   // Yes, it's legal!!
System.out.println(var);

Can only be used for “local” variables

The main and most important restriction of the new “var” syntax is that it can be used only on local variables. Thus, you can use it for:

  • local variables in any method, constructor and instance/static initialization block
  • the variable declared in the “classic” for cycle and also in the enhanced-for cycle (the so called “for-each”) available since Java 5
  • variables declared in the try-with-resource statement, available since Java 7

However, the new syntax cannot be used for:

  • parameters of methods/constructors
  • the declared return type of a method
  • “instance” (non-static) and “class” (static) variables
  • the parameter of the catch clause

Must always be explicitly initialized with a value

The variable declared with the new “var” syntax must always be initialized at the same time of the declaration. This is perhaps the most important rule of this new feature. The reason of this requirement is because the compiler needs to infer the type from the initialized value. In other words, the initialization cannot be done in a second separate step.

// ❌ NO, ERROR!
var num;
num = 123;
var num2;
num2 = Math.random();
// ✔️ OK
var num = 123;              // Ok, num is inferred of type int
var num2 = Math.random();   // Ok, num2 is inferred of type double

For the same reason, it makes absolutely no sense to initialize the variable assigning the result of a void method, since there is no returned value.

// ❌ NO, ERROR!
var res = System.out.println("hello");   // println is void !

Note: remember that void is not a data type, not even a reference type! (and not to be confused with java.lang.Void)

Can have the final modifier and/or annotations

A local variable declared using the new “var” syntax can have the final modifier (which makes it a “constant”) and/or one or more annotations. This works exactly like any other “classic” local variable declaration.

final var num = 123.456;   // Ok, num is a constant of type double
@SomeAnnotation var str = "Hello";   // Ok with an annotation

Note: annotations on local variables are very very rarely used!

Cannot be initialized with a literal null

The null reference, represented in source code by the literal null, is a value of the special null type that denotes the absence of reference to an object. Furthermore, the null reference is also technically the subtype of all the other reference types. For these reasons, you cannot use the new “var” syntax to initialize a variable with a literal null, because the compiler would not be able to deduce a type.

// ❌ NO, ERROR!
var str = null;   // What type???

If you really wanted to initialize the variable with a null value you may help the compiler by inserting an explicit cast, like the following:

var str = (String) null;   // Ok, but ... pointless

This would give the compiler sufficient informations to deduce the type of the variable. However I think this is a bit pointless and in my opinion it’s better to use the “classic” variable declaration ( String str = null; ), which is also shorter.

Cannot define more variables in the same declaration statement

The “classic” way of declaring variables allows you to define (and possibly initialize) more than one variable in the same declaration statement, as shown below:

int a = 123, b = 789;   // Ok, always legal

Unfortunately, the new “var” syntax prohibits this type of multi-variable declaration. You can define only one variable in a single declaration statement.

// ❌ NO, ERROR!
var a = 123, b = 789;
// ✔️ OK
var a = 123;   // Ok
var b = 789;   // Ok

Cannot use square brackets [] next to the variable name

The “classic” way of declaring array variables requires placing square brackets [] next to the variable name for each array dimension. The square brackets are generally and conventionally placed just on the right of the type, like in the example below:

int[] arr = new int[10];
double[][] matrix = new double[4][8];

With the new “var” syntax it is illegal to place the brackets [] next to the variable name, because the compiler automatically infers the array type from the assigned value.

// ❌ NO, ERROR!
var arr[] = new int[10];
var[] arr = new int[10];
var matrix[][] = new double[4][8];
// ✔️ OK
var arr = new int[10];           // Ok, arr is inferred of type int[]
var matrix = new double[4][8];   // Ok, matrix is inferred of type double[][]

Cannot initialize arrays using the short { } syntax

The “classic” way of declaring array variables allows you to initialize the array using the short form with curly brackets { } to enclose the values, like in the example below:

int[] numbers = { 10, 20 };        // Ok, always legal
String[] strings = { "A", "B" };   // Ok, always legal

With the new “var” syntax it is illegal to initialize the array using this short form, because the compiler would not be able to infer the array type just only from the values (at least not in all cases, to be precise). Indeed, there can be some particular or corner cases in which it is hard/impossible to deduce the correct or expected array type.

If you really wanted to initialize the array using the new “var” syntax, you must use what is called an anonymous array. This is a special form of array instantiation that uses the keyword new followed by the array type and then the values enclosed in curly brackets.

// ❌ NO, ERROR!
var numbers = { 10, 20 };
var strings = { "A", "B" };
// ✔️ OK
var numbers = new int[] { 10, 20 };        // Ok with anonymous array
var strings = new String[] { "A", "B" };   // Ok with anonymous array

Cannot be initialized with a lambda expression

Lambda expressions are a great feature introduced in Java 8 to define “functions” in a more compact and expressive way. A lambda expression must always be associated to a functional interface (a conceptually special type of Java interface) because the signature of the lambda expression depends on the functional interface.

For example:

IntBinaryOperator intAdder = (a, b) -> a + b;

In the above example, the compiler infers that the function takes two int and returns an int because IntBinaryOperator (the type of the intAdder variable) has the single “functional” method:

int applyAsInt(int left, int right)

This kind of type inference is exactly the opposite of the new “var” syntax, because with var the compiler must infer the type from the assigned value. For this reason, it is not possible to directly assign a lambda expression to a variable declared with the “var” syntax.

// ❌ NO, ERROR!
var intAdder = (a, b) -> a + b;   // What type is the function???

If you really wanted to assign a lambda expression to the variable, you may help the compiler by inserting an explicit cast, like the following:

// ✔️ OK
var intAdder = (IntBinaryOperator) (a, b) -> a + b;

In this latter case the compiler has sufficient informations to infer the appropriate type of the variable.

The word “var” can no longer be used as type name

At first this restriction may seem a little strange but it’s easy to understand. Since “var” can now be used in place of a type, it is no more possible to define a new type (e.g. a class or interface) using exactly the word “var”.

// ❌ NO, ERROR!
public class var { }
// ❌ NO, ERROR!
public interface var { }

Anyway, this restriction is in absolute the least important and the least problematic for one simple reason: declaring a type with the exact name “var” is a clear violation of the standard naming conventions.

There exist a set of naming conventions that are widely recognized and accepted by the Java developers community. According to these conventions, Java type names should begin with an uppercase letter (e.g. Person, Book, CardDeck). Therefore, if you follow and respect these conventions, you should never use the name “var” for a Java type.

Conclusions

In this article I have tried to explain the rules of the new “var” syntax in a complete but concise way. If you want to have more detailed and extensive informations, you can read the JEP 286 which is the JDK Enhancement Proposal that was written specifically for this new feature.

Similar Posts