This article provides details about a Local-Variable Type Inference introduced as a new feature in Java 10. It explains the need for Local-Variable Type Inference and how to use it in your program while using Java 10.
Introduction
We all know that Java is very concern about type safety of variables and instances. The addition of generics in Java 5 strengthens the type safety in Java. But there are many other programming languages like C++, Go, Scala, Kotlin, etc, which infer the type of a variable by itself.
Now with the addition of JEP 286, we have Type Inference in java for local variable declarations with initializers. A thing to keep in mind that Java will still be strong statically typed language. The new feature just allows it to infer the type of local variables at compile time.
The main idea behind introducing this feature is to:
- Reduce the boilerplate code
- Reduce ceremony associated with the code
- Increase code readability
Note: The type inference feature is for local variables only. The compiler will not infer type for instance or class variables.
What is Type Inference?
Type Inference refers to an automatic detection of the data type of a variable/expression.
In Java when we declare any variable, we have to specify it’s data type in the declaration as well as initialization. For example:
BigDecimal bigDecimal = new BigDecimal("123"); String myString = "My String"; Integer myInt = 1234; StringBuffer stringBuffer; stringBuffer = new StringBuffer();
In Java 10 using var
we no longer need to specify the data type while declaring local variables if we initialize them at the same time. With that said, in Java 10 above code will change as follow:
var bigDecimal = new BigDecimal("123"); var myString = "My String"; // infers as String var myInt = 1234; // infers as Integer var stringBuffer; // will NOT compile as not initialized stringBuffer = new StringBuffer();
In above code, except stringBuffer, every variable is valid and the compiler will infer it’s respective data type. var stringBuffer; will not compile because we are not initializing it.
“var” a reserved type name
You must be wondering what the word var means in code given in the previous section? It sounds familiar if you already worked in javascript(though no relations with javascript here).
The identifier
var
is not a keyword; it is a reserved type name.
You can use var for following things:
- As local variable name
- var var = 123;
- As method name
- public void var() { }
- In package name
- package com.bytestree.core.var;
You cannot use var for following things:
- Class name
- Interface name
- Enum name
Local Variable Type Inference Rules
We can use Local Variable Type Inference for:
- Local variable declarations with initializers
- Enhanced for loop indexes
- For index variable in traditional for loop
You already know about local variable declarations with initializers given in the previous section. Now check how to use Local Variable Type Inference in for loop:
var integerList = Arrays.asList(1, 2, 3, 4); // enhanced for loop indexes for (var number : integerList) { System.out.println(number); } // traditional for loop index (i) for (var i = 0; i < integerList.size(); i++) { System.out.println(integerList.get(i)); }
In above example, you also see how var is used for Collections.
Examples of Type Inference
With above three cases, following are also valid uses of Local Variable Type Inference:
Diamond Operator
var list = new ArrayList<>(); // List of Objects
In above code, due to the absence of left-hand side details, the compiler cannot infer the exact type of data in ArrayList, so it infers to supertype which is Object. Though you can use diamond operator here, it’s better to avoid it and specify the type on the right-hand side for better readability of code and correct inference like given below:
var listOfString = new ArrayList<String>();
Stream
Use of var for the stream is perfectly valid.
var stream = list.stream();
Anonymous Class
Variables can have Anonymous class type.
var inner = new Thread() { @Override public void run() { System.out.println("Running Thread"); } }; inner.start();
Examples of Limitations of Type Inference
Following are the incorrect ways or limitations of using local variable type Inference and var reserved type name:
Without Initializer or initialize with null
var withoutInitializer; var initializeToNull = null;
Both lines in above code will give compilation error “cannot infer type for local variable…”
Multiple variable instantiations
You cannot instantiate multiple var variables at the same time as given below:
var a = "a", b = "b";
Lambda Expressions initializer
There are no type details on the right-hand side, due to which you cannot use lambda expression initializer.
var x = () -> { };
Method Reference initializer
You cannot use method reference initializer like the following code. You will get an error message: method reference needs an explicit target-type
var integerFunction = Integer::intValue;
Array Initializer
You cannot initialize an array like given below:
var numbers[] = {1, 2, 3, 4};
The correct way of initializing an array with var is:
var numbersRight = new int[]{1, 2, 3, 4};
var in the method signature
You cannot use var in the method signature, therefore you cannot use it as a return type or method parameter.
private var varInSignature(var value) { return null; }
Source Code
All code used to test Type Inference given above is available in GitHub.
Hope this article has given you details about what Local Variable Type Inference is and how to use it in your code. For any questions or suggestions, please leave a comment.