java-inferencia-tipos-var

Type Inference in Java: The var Keyword

  • 4 min

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");
Copied!

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 is
Copied!

Important: 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.
Copied!

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.
Copied!

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)
Copied!

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
        // ...
    }
}
Copied!

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

  1. When the declaration is redundant:
// Repetitive and noisy
FileInputStream fis = new FileInputStream("file.txt");

// Clean and clear
var fis = new FileInputStream("file.txt");
Copied!
  1. In for-each loops:
for (var user : userList) {
    // ...
}
Copied!
  1. With complex generic type names: This is where var shines.
// Eye strain
Map<String, List<Map<Integer, String>>> data = new HashMap<>();

// Peace of mind
var data = new HashMap<String, List<Map<Integer, String>>>();
Copied!

❌ 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?
Copied!

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();
Copied!