3.13 Local Variable Type Inference
A variable declaration requires the type of the variable to be specified in the declaration. However, in the case of local variables, the type can be specified by the reserved type name var, if the local declaration also specifies an initialization expression in the declaration. The compiler uses the type of the initialization expression to infer the type of the local variable. The restricted type name var denotes this inferred type in the local declaration. This is an example of type inference, where the type of a variable or an expression is derived from the context in which it is used. If the compiler cannot infer the type, it reports a compile-time error. A local variable declaration that uses var is also called a var declaration. A local variable declared this way is no different from any other local variable.
It is important to note that the type of the local variable is solely inferred from the initialization expression specified in the declaration. The following variable declaration in a local context (e.g., body of a method) is declared using the reserved type name var:
var year = 2022;
The compiler is able to infer that the type of the initialization expression 2022 is int in the above declaration, and therefore the variable year has the type int. The declaration above is equivalent to the declaration below, where the type is explicitly specified:
int year = 2022;
A cautionary note going forward: This subsection refers to many concepts and constructs that might not be familiar at this stage. It might be a good idea to get an overview now and to come back later for a more thorough review of this topic. The exhaustive index at the end of the book can of course be used at any time to look up a topic.
The class ValidLVTI in Example 3.17 illustrates valid uses of the restricted type name var. The comments in the code should be self-explanatory.
The var restricted type name is allowed in local variable declarations in blocks (including initializer blocks), constructors, and methods, as can be seen in the class ValidLVTI at (1a), (1b), and (2) and the method main(), respectively.
Note that at (3b) and (3c), the compiler is able to infer the type of the local variable from the return type of the method on the right-hand side.
It is worth noting that the cast operator, (), can be necessary to indicate the desired type, as shown at (5) and (7).
For array variables, the initialization expression must be an array creation expression that allows the array size and the array element type to be inferred, as shown at (11a), (11b), (11c), and (11d). A local declaration with var requires an initialization expression, which in the case of local arrays must be either an array creation expression or an anonymous array expression. In other words, it should be possible to infer both the array element type and the size of the array. It cannot be an array initializer.
The bodies (and the headers) of the for(;;) and for(:) loops can define their own local variables in their block scope. The type of the local variable vowel at (13) is inferred to be char from the array vowels (of type char[]) in the header of the for(:) loop. The type of the local variable i in the header of the for(;;) loop at (16) is determined to be int from the initial value. The switch statement also defines its own block scope in which local variables can be declared, as shown at (18).
Example 3.17 Illustrating Local Variable Type Reference
// Class ValidLVTI illustrates valid use of the restricted type name var.
public class ValidLVTI {
// Static initializer block:
static {
var slogan = “Keep calm and code Java.”; // (1a) Allowed in static
} // initializer block
// Instance initializer block:
{
var banner = “Keep calm and catch exceptions.”; // (1b) Allowed in instance
} // initializer block
// Constructor:
public ValidLVTI() {
var luckyNumber = 13; // (2) Allowed in a constructor.
}
// Method:
public static void main(String[] args) {
var virus = “COVID-19”; // (3a) Type of virus is String.
var acronym = virus.substring(0, 5); // (3b) Type of acronym is String.
var num = Integer.parseInt(virus.substring(6)); // (3c) Type of num is int.
var obj = new Object(); // (4) Type of obj is Object.
var title = (String) null; // (5) Initialization expression type is String.
// Type of title is String.
var sqrtOfNumber = Math.sqrt(100); // (6) Type of sqrtOfNumber is double,
// since the method returns
// a double value.
var tvSize = (short) 55; // (7) Type of tvSize is short.
var tvSize2 = 65; // (8) Type of tvSize2 is int.
var diameter = 10.0; // (9) Type of diameter is double.
var radius = 2.5F; // (10) Type of radius is float.
// Arrays:
var vowels = new char[] {‘a’, ‘e’, ‘i’, ‘o’, ‘u’ }; // (11a) Type of vowels
// is char[]. Size is 5.
var zodiacSigns = new String[12]; // (11b) Type of zodiacSigns is String[].
// Size is 12.
var a_2x3 = new int[2][3]; // (11c) Type of a_2x3 is int[][]. Size is 2×3.
var a_2xn = new int[2][]; // (11d) Type of a_2xn is int[][]. Size is 2x?,
// where second dimension can be undefined.
// The for(:) loop:
var word1 = “”; // (12) Type of word2 is String.
for (var vowel : vowels) { // (13) Type of vowel is char in the for(:)loop.
var letter = vowel; // (14) Type of letter is char.
word1 += letter;
}
// The for(;;) loop:
var word2 = “”; // (15) Type of word2 is String.
for (var i = 0; i < vowels.length; i++) { // (16) Type of i is int in
// the for loop.
var letter = vowels[i]; // (17) Type of letter is char.
word2 += letter;
}
// switch-statement:
switch(virus) {
case “Covid-19”:
var flag = “Needs to be tested.”; // (18) Type is String.
// Do testing.
break;
default: // Do nothing.
}
}
}