W3docs

Palabra clave var en Java (Inferencia de tipo para variables locales)

Usa var para la inferencia de tipo de variables locales en Java, cuándo mejora la legibilidad y cuándo no.

Desde Java 10, puedes declarar una variable local con var y dejar que el compilador infiera su tipo a partir del inicializador. var greeting = "hello"; es exactamente lo mismo, bytecode compilado incluido, que String greeting = "hello"; — el tipo sigue siendo String, simplemente no lo escribiste dos veces. Esto es inferencia de tipo para variables locales: una conveniencia sintáctica que elimina nombres de tipo redundantes sin hacer Java dinámicamente tipado. Bien utilizada elimina ruido; usada sin cuidado oculta exactamente la información que un lector necesita.

Esta página cubre qué hace y qué no hace var, exactamente dónde es legal, los casos en que resulta beneficioso, los casos en que perjudica la legibilidad, y un programa ejecutable que demuestra que los tipos inferidos son los que esperas.

var es inferencia, no tipado dinámico

El hecho más importante: var no es un nuevo tipo "comodín". El compilador lee el lado derecho, determina el tipo estático y lo fija. A partir de ese momento la variable tiene un tipado tan fuerte como si hubieras escrito el tipo a mano — no puedes reasignarla a un tipo diferente, y el tipo inferido queda fijo en tiempo de compilación.

var name = "Ada";   // name has static type String, forever
name = "Lovelace";  // fine, still a String
name = 42;          // compile error: int cannot be assigned to String

var es un nombre de tipo reservado, no una palabra clave — todavía puedes usar var como nombre de variable o método (aunque no deberías). Solo activa la inferencia en la posición de declaración de variable local.

Dónde se permite var — y dónde no

var solo funciona para variables locales que tienen un inicializador. El compilador necesita un lado derecho del que leer el tipo; sin él no hay nada que inferir.

Posición¿var permitido?Motivo
Variable local con inicializadorEl inicializador proporciona el tipo
Índice/elemento en bucles forLa expresión del bucle proporciona el tipo
Variable en try-with-resourcesLa expresión del recurso proporciona el tipo
Variable local sin inicializadorNoNo hay nada de lo que inferir
Campos / variables de instanciaNoLa inferencia es solo local por diseño
Parámetros de métodoNoSon los llamadores, no los inicializadores, quienes suministran valores
Tipos de retorno de métodoNoMisma razón que los parámetros
Inicializado solo con nullNonull no tiene tipo concreto
Parámetros lambda (básicos)Especial(var x, var y) -> ... está permitido desde Java 11
var x;                       // error: cannot infer type, no initializer
var nothing = null;          // error: null has no type to infer
public var field = 1;        // error: var not allowed on fields
void m(var p) { }            // error: var not allowed on parameters

La verdadera ventaja: reducir los genéricos ruidosos

var justifica su existencia cuando el nombre del tipo es largo, repetido o con muchos genéricos. El caso clásico es una declaración donde el tipo aparece completo en ambos lados del =:

// Before: the type name is written twice
Map<String, List<Customer>> byCity = new HashMap<String, List<Customer>>();

// After: the right side already says everything
var byCity = new HashMap<String, List<Customer>>();

También resulta útil con iteradores, el Map.Entry que obtienes de un HashMap, y otros tipos verbosos que no aportan claridad cuando se escriben completos:

for (var entry : byCity.entrySet()) {     // Map.Entry<String, List<Customer>>
  System.out.println(entry.getKey() + " -> " + entry.getValue().size());
}

Cuándo NO usar var

var ayuda cuando el tipo es obvio por el lado derecho y perjudica cuando no lo es. Si un lector tiene que ejecutar el código mentalmente para conocer el tipo, escribe el tipo explícitamente.

var result = service.process(input);   // unclear: what does process return?
Order result = service.process(input); // clear: an Order

var flag = true;                       // fine, obviously boolean
var count = list.size();               // fine, obviously int

Ten cuidado con la trampa de los literales numéricos: var infiere el tipo del literal, no el tipo que quizás pretendías.

var n = 100;        // int, not long  — for a long you must write 100L or long n
var f = 3.14;       // double, not float
byte b = 1;         // explicit type narrows; var b = 1 would be int

Evita var cuando pierdas un tipo de interfaz deliberado. var list = new ArrayList<String>(); tipifica list como ArrayList<String>, no como List<String> — correcto localmente, pero si tu intención era programar contra la interfaz, indícalo explícitamente.

Un ejemplo práctico que puedes ejecutar

Este programa ejercita var en todas sus posiciones legales — valores simples, un mapa genérico, un bucle for mejorado, un bucle for con índice — y usa getClass().getSimpleName() para demostrar que los tipos inferidos en tiempo de ejecución son exactamente lo que el lado derecho implicaba.

java— editable, runs on the server

Lo que puedes extraer de la ejecución:

  • greeting.getClass().getSimpleName() imprime String, demostrando que var greeting = "hello" produjo un String genuino — var es inferencia en tiempo de compilación, y en tiempo de ejecución el objeto es exactamente lo que el literal implicaba, nada dinámico al respecto.
  • count + 1 = 43 y price * 2 = 19.98 confirman las reglas de inferencia numérica: 42 hizo que count fuera un int, 9.99 hizo que price fuera un double. El tipo del literal — no tu intención — decide, lo cual es la trampa a recordar cuando necesitas un long o un float.
  • scores type = HashMap muestra que var capturó el tipo concreto del lado derecho HashMap, no la interfaz Map; el diamante <String, List<Integer>> del lado derecho le dio al compilador todo lo necesario aunque el lado izquierdo solo dijera var.
  • total chars = 10 proviene de for (var name : names) donde name fue inferido como String, por lo que name.length() se resolvió correctamente (3 + 3 + 4) — var funciona en bucles for mejorados, infiriendo el tipo del elemento a partir del iterable.
  • 0..4 sum = 10 proviene de for (var i = 0; ...) donde i fue inferido como int a partir del literal 0; el bucle indexado es uno de los lugares más limpios para usar var porque el tipo es inconfundible.

Práctica

Práctica
¿En cuál de estas declaraciones es 'var' legal e infiere el tipo que indica el comentario?
¿En cuál de estas declaraciones es 'var' legal e infiere el tipo que indica el comentario?

Temas relacionados

Was this page helpful?