Back to Blog
Java

Java Type Inference var: How It Works and When to Use It

java type inference var: Learn how Java's var keyword works for type inference, where it can be used, its limitations, and how it affects readability and performance.

JavaType InferencevarLocal VariablesJava 10Code Readability
Illustration of Java code with var keyword and an arrow showing the inferred type, representing type inference.

Java's var keyword, introduced in Java 10, lets you declare local variables without specifying their type explicitly. The compiler infers the type from the initializer. This article explains how java type inference var works, where it is allowed, and how to use it without sacrificing clarity.

What var Actually Does

When you write var count = 0;, the compiler determines that count is an int because 0 is an int. The variable is still statically typed; var is not a dynamic type. The inferred type is fixed at compile time and cannot change later. This is different from languages like JavaScript or Python where a variable can hold different types over time.

var count = 0; // inferred as int var name = "Java"; // inferred as String var list = new ArrayList<String>(); // inferred as ArrayList<String>

The key point is that var only works for local variables with an initializer. It cannot be used for method parameters, return types, or fields. The type must be inferable from the right-hand side.

Where var Is Allowed

var is permitted in several contexts:

  • Local variable declarations with an initializer
  • Enhanced for-loop variables
  • Try-with-resources declarations
  • Loop variables in traditional for loops (but only with an initializer)

For example:

for (var item : items) { // item type is inferred from items } try (var reader = Files.newBufferedReader(path)) { // reader is a BufferedReader }

In a traditional for loop, var can be used for the loop variable if it has an initializer:

for (var i = 0; i < 10; i++) { // i is int }

Common Mistakes and Misconceptions

A frequent mistake is assuming var makes the variable type flexible. It does not. The type is fixed at compile time, so reassigning a different type causes a compile error.

var value = "hello"; value = 42; // error: incompatible types

Another misconception is that var can replace explicit types everywhere. It cannot be used without an initializer:

var x; // error: cannot infer type for local variable x

Also, var cannot be used with the diamond operator on anonymous classes. When you write var obj = new Object() { ... };, the inferred type is the anonymous class, which is not accessible. This can lead to issues if you try to call methods defined only in the anonymous class.

Readability: When var Helps and When It Hurts

var improves readability when the type is long and the initializer makes the intent clear. For example:

Map<String, List<Map<Integer, String>>> data = new HashMap<>(); var data = new HashMap<String, List<Map<Integer, String>>>();

The second line is shorter and still clear. However, var hurts readability when the initializer does not reveal the type. Consider:

var result = service.getResult();

Without knowing the return type of getResult(), you have to inspect the method. In such cases, an explicit type is better. A general guideline is to use var when the type is obvious from the initializer, such as with constructors or literals, and to avoid it when the type is hidden behind a method call.

var with Lambdas and Anonymous Classes

Java 11 extended var to lambda parameters. This allows you to apply annotations to lambda parameters without specifying the full type:

BiFunction<String, String, String> concat = (@Nullable var a, @Nullable var b) -> a + b;

However, var is not allowed for lambda parameters in Java 10; it was added in Java 11. For anonymous classes, var can be used, but the inferred type is the anonymous class itself, which is not referable. This means you cannot assign the result to a variable with an explicit type of that anonymous class, and you cannot use it in a way that requires naming the type.

Performance and Runtime Impact

var has zero runtime cost. It is a compile-time feature; the compiler replaces var with the inferred type in the bytecode. There is no reflection, no dynamic dispatch, and no performance penalty. The generated bytecode is identical to what you would get with an explicit type. Therefore, using var does not affect execution speed or memory usage.

Compatibility and Migration Considerations

var was introduced in Java 10, so code using it requires a compiler and runtime that support at least Java 10. For projects targeting older Java versions, var is not available. When migrating existing code, you can introduce var incrementally, but you must ensure your build tool and CI environment use Java 10 or later. Also, var is not a keyword; it is a reserved type name. This means you can still have a variable named var, but you cannot declare a class, interface, or enum named var. This subtle distinction can affect code that previously used var as an identifier.

When adopting var, consider your team's familiarity with the codebase. If the type is not obvious from the initializer, an explicit type is often more maintainable. Use var for local variables where the type is clear and the declaration becomes more concise, and avoid it in public APIs where the type is part of the contract.

java type inference var: Practical Usage and Code Examples | RYUSLOG DEV