var & Local Type Inference
IntermediateUse var (Java 10+) to let the compiler infer local variable types — less boilerplate, same static safety.
Overview
var is a reserved type name (not a keyword) introduced in Java 10 that tells the compiler to infer the type of a local variable from the initialiser. The variable is still statically typed — var is compile-time syntactic sugar. It reduces verbosity for complex generic types and long class names without sacrificing type safety. It cannot be used for fields, method parameters, or return types.
Using var — Rules & Restrictions
var rules: • Only for local variables with an initialiser • Not for fields, method parameters, return types, or catch variables (until Java 14) • Initialiser must not be null alone (type cannot be inferred) • Works in for-each loops and classic for init
import java.util.*;
import java.util.stream.*;
public class VarDemo {
public static void main(String[] args) {
// Basic inference
var message = "Hello Java 10"; // inferred: String
var count = 42; // inferred: int
var list = new ArrayList<String>(); // inferred: ArrayList<String>
var map = new HashMap<String, List<Integer>>(); // inferred: complex type
list.add("item");
System.out.println(message.toUpperCase()); // HELLO JAVA 10
// for-each with var
var names = List.of("Alice", "Bob", "Carol");
for (var name : names) {
System.out.print(name.length() + " "); // 5 3 5
}
System.out.println();
// Classic for init
for (var i = 0; i < 3; i++) System.out.print(i + " ");
System.out.println();
// try-with-resources
try (var reader = new java.io.StringReader("test")) {
System.out.println((char) reader.read()); // t
} catch (Exception e) { e.printStackTrace(); }
// INVALID uses:
// var field = "x"; // fields — compile error
// void method(var x) {} // params — compile error
// var x; // no initialiser — compile error
// var x = null; // ambiguous type — compile error
}
}var with Anonymous Types & Intersection Types
var captures the exact inferred type — even anonymous class types or intersection types that have no denotable name. This allows calling methods on an anonymous class through a var variable without a cast, which is impossible with an explicit type.
public class VarAdvanced {
interface Greeter { String greet(String name); }
public static void main(String[] args) {
// var captures anonymous class type — can call anon-specific methods
var obj = new Object() {
String value = "hidden";
public String compute() { return value.toUpperCase(); }
};
System.out.println(obj.compute()); // HIDDEN — impossible without var
System.out.println(obj.value); // hidden
// var in stream pipeline — reduces visual noise
var numbers = java.util.List.of(1, 2, 3, 4, 5);
var evens = numbers.stream()
.filter(n -> n % 2 == 0)
.collect(java.util.stream.Collectors.toList());
System.out.println(evens); // [2, 4]
// When NOT to use var — hurts readability
var x = getValue(); // reader cannot tell x is a String without IDE
System.out.println(x.length()); // compiles fine but obscure
}
static String getValue() { return "hello"; }
}var Best Practices
Use var when the type is obvious from the right-hand side (new ArrayList<>(), literal values, stream results). Avoid var when the type is not clear from context — it harms readability more than verbosity does. Good rule: if removing the explicit type forces the reader to look up the method return type, keep the explicit type.
import java.util.*;
import java.util.stream.*;
public class VarBestPractices {
public static void main(String[] args) {
// GOOD: type is obvious from RHS
var list = new ArrayList<String>();
var map = new HashMap<String, Integer>();
var pattern = java.util.regex.Pattern.compile("\d+");
// GOOD: reduces noise with complex generics
var entries = new HashMap<String, List<Map<Integer, String>>>(); // vs the full type
// GOOD: loop variables
for (var entry : map.entrySet()) {
System.out.println(entry.getKey() + "=" + entry.getValue());
}
// AVOID: type unclear from context
var result = process(); // What type is result? Must check method
// Better: explicit type here
String result2 = process(); // clear
// AVOID: primitive widening surprises
var x = 1.0; // inferred as double, not float
var y = 1; // inferred as int, not long
System.out.println(((Object)x).getClass().getSimpleName()); // Double
}
static String process() { return "processed"; }
}Key Points to Remember
- var is a compile-time feature — variables are still statically typed, not dynamically typed
- Only valid for local variables with an initialiser; not for fields, params, or return types
- var can capture anonymous class types — enabling method calls not possible with named types
- Avoid var when the type is not obvious from the right-hand side
- var x = null is illegal — the compiler cannot infer the type
- var works in for-each loops and try-with-resources (Java 9+ resources)
Practice var & Local Type Inference in the Playground
Run and modify code directly in your browser - no setup needed.
Interview Questions
Sign in to ask AriaWhat is var in Java? When was it introduced?
Is var a keyword in Java?
Can var be used for method parameters or return types?
What happens when you write var x = null?
How does var help with anonymous class types?
Ask Aria about var & Local Type Inference
Your personal AI tutor — ask anything about this concept