You are currently viewing Type Inference in Java
java_logo

Type Inference in Java

1. Introducing var

Java 10 introduced a powerful feature called local variable type inference, allowing developers to use the keyword ‘var’ when declaring local variables. This feature simplifies code, improves readability, and maintains Java’s strong static typing. In this blog post, we’ll delve into the usage of ‘var’ for local variables, explore type inference, and clarify its limitations.

2. Using ‘var’ for Local Variables

When declaring local variables, you can replace the explicit type with ‘var,’ and the compiler will infer the type based on the assigned value:

var age = 25;           // int
var name = "John";      // String
var pi = 3.14;          // double
var isActive = true;    // boolean

In Java, the var keyword is specifically designed for local variable type inference and cannot be used for class variables (static fields). Class variables must declare their types explicitly. Attempting to use var for a class variable will result in a compilation error. Here’s an example to illustrate this:

public class MyClass {
    // Class variable (static) - Compiler error if you use 'var'
    static var myClassVar = "Class Variable";  // Compilation error

    // Other class members...
}

3. Type Inference with Local Variables

Local variable type inference allows the compiler to determine the type based on the assigned value during compilation. This feature is limited to local variables and does not apply to method parameters, fields, or return types.

var count = 10;      // Compiler infers int
count = count + 5;   // Value can change, but type remains int

In this example, the type of ‘count’ is inferred as int, and while the value can change, the type remains constant.

public class VariableReassignmentExample {
    public static void main(String[] args) {
        // Declare a variable with 'var' and initialize it with an int
        var myVar = 42; // Compiler infers type as int

        // Attempt to reassign 'myVar' to a String - Compilation error
        myVar = "Hello, Java!"; // Compilation error: incompatible types
    }
}

In this example, the compiler initially infers the type of myVar as int based on the assigned value 42. When attempting to reassign myVar to a String, a compilation error occurs because the type inferred by var cannot be changed at runtime.

implicit type conversion

Implicit type conversion, also known as widening or automatic type promotion, occurs when a value of a smaller data type is assigned to a variable of a larger data type. This process is safe when going from a smaller data type to a larger one because there’s no risk of losing precision or information.

public class TypeConversionExample {
    public static void main(String[] args) {
        // Assigning a byte to a short (implicit conversion)
        byte myByte = 100;
        short myShort = myByte; // implicit conversion from byte to short

        System.out.println("myShort: " + myShort);

        // Attempting to assign a larger value to a short (compilation error)
        int largeValue = 1000000;
        short myShort2 = largeValue; // Compilation error: incompatible types

        long longvalue = 1000000000L;
        var inferredInt = 100000;
        inferredInt = longvalue; // compilationError: incompatible types
    }
}

In this example, a byte variable myByte is assigned the value 100, and then it is assigned to a short variable myShort. This is a safe operation because a byte can be implicitly converted to a short without loss of information.

However, if you attempt to assign a larger value (outside the range of a short) to a short variable, you will get a compilation error. In the commented line, the int variable largeValue is assigned a value of 1000000, and trying to assign it to myShort2 (of type short) results in a compilation error.

In the example, the var inferredInt is initialized with the value 100000. The Java compiler infers the type of inferredInt to be int because the assigned value is within the range of an int. However, if you then try to assign a long value (longValue) to inferredInt, you will encounter a compilation error. This is because the inferred type of inferredInt is int, and you cannot assign a long value to an int variable without an explicit cast. The compiler prevents this assignment to avoid potential loss of information or precision.

var and null


var message = "Hello, Java!"; // Compiler infers String type
message = null // Object can be null

var number = 42; // Compiler infers int type
number = null; // Compilation error: int cannot be null

var nullString = null; // Compilation error

For the message variable, the compiler can easily infer that the type of message is String based on the assigned value. When the message variable is set to null, that is perfectly fine because message is of type String, which is an Object. However, when initializing a variable with null, there is no information about the type, leading to a compilation error, which is illustrated in the nullString. When the compiler infers an int type for the variable, that same variable can no longer be null, which is illustrated in the number example

4. Review of the ‘var’ Rules

  • var is used as local variable within methods, constructors, or initializer blocks.
  • var cannot be not used as a parameter in method or constructor declarations.
  • A var is always initialized on the same line where it is declared.
  • The type of a variable declared with var is inferred by the compiler based on the assigned value.
  • While the value assigned to a var variable can change, the type inferred by the compiler remains constant.
  • var cannot be directly initialized with null. It requires an initial value for the compiler to infer the type.
  • var is not permitted in a multiple variable declaration where multiple variables are declared in a single statement.