The type inference allows the compiler to deduce the static type of a local variable from its initializer.
If you’ve been following the course, in the previous article we were very insistent that Java has strong and static typing. We said you have to declare the type of everything:
String greeting = "Hello World";
int number = 42;
URL url = new URL("https://luisllamas.es");This is great because it’s explicit, but sometimes, especially with long class names, it becomes redundant. The Java compiler is smart. If on the right side of the equals sign there is the text "Hello World", the compiler already knows that’s a String. Why force us to write it twice?
To solve this, we have the var keyword.
What is var?
var allows us to declare local variables without explicitly specifying their type, letting the compiler “infer” (deduce) the type based on the value we assign.
Let’s see the change:
// Classic way (Java 9 and below)
String message = "Hello everyone";
int counter = 0;
ByteArrayOutputStream output = new ByteArrayOutputStream();
// Modern way (Java 10+)
var message = "Hello everyone"; // The compiler knows it's a String
var counter = 0; // The compiler knows it's an int
var output = new ByteArrayOutputStream(); // The compiler knows what it isImportant: var is NOT a data type. It’s an instruction to the compiler that says: “look at what’s on the right side of the equals sign and assign that type to the variable”.
What var is not
Using var does not break static typing. The variable still has a fixed type, you just don’t write it.
Once the compiler decides it’s a String, it will be a String forever.
var price = 10.5; // The compiler decides 'price' is a double
price = 20.0; // Correct, it's still a double
price = "Expensive"; // COMPILATION ERROR! You can't put a String into a double.Limitations: where can I use it?
Type inference in Java is conservative. It’s not valid everywhere. You can only use var in initialized local variables.
Initialization is mandatory
The compiler needs the value to deduce the type.
var name; // ERROR: What type is it? I don't know.
var name = "Luis"; // Correct.Direct nulls are not allowed
null has no type (it can be any object), so the compiler doesn’t know what to do.
var object = null; // ERROR
var object = (String)null; // Works (but is pointless)Only in local variables
You cannot use var for class attributes (fields) or method parameters.
public class User {
var name = "Pepe"; // ERROR: Not allowed in class attributes
public void greet(var text) { // ERROR: Not allowed in parameters
// ...
}
}The reason is that attributes and methods define the public API of your class and must be explicit so others know how to use them without having to read the internal code.
When to use var?
Here comes the eternal debate. Should we always use var?
Code is read more often than it is written. The goal of var is to reduce visual noise, not to hide important information.
✅ When to use it
- When the declaration is redundant:
// Repetitive and noisy
FileInputStream fis = new FileInputStream("file.txt");
// Clean and clear
var fis = new FileInputStream("file.txt");- In for-each loops:
for (var user : userList) {
// ...
}- With complex generic type names:
This is where
varshines.
// Eye strain
Map<String, List<Map<Integer, String>>> data = new HashMap<>();
// Peace of mind
var data = new HashMap<String, List<Map<Integer, String>>>();❌ When not to use it
When the type is not obvious from looking at the right side.
var result = processData(); // What does this return? An int? A String? An Object?In this case, you are forcing the reader (or yourself in 3 months) to navigate to the processData() method to find out what the heck result is. Here it is much better to be explicit:
ProcessResult result = processData();