La inferencia de tipo de variable local se introdujo en Java 10 como una nueva característica del lenguaje y se mejoró en Java 11. Básicamente, permite al desarrollador usar la palabra var
en lugar del tipo al declarar variables locales (en métodos), el compilador puede para inferir el tipo del lado derecho de la asignación.
public String myMethod(int n){ var counter = 10; var idToNameMap = new HashMap<Integer, String>(); idToNameMap.foreach(e -> {/*some code*/}); var message = "Hello World"; message = message.toUpperCase(); return message; }
No es un concepto nuevo
Cuando se trata de “Inferencia de tipo”, este no es un nuevo concepto en Java. Por ejemplo, desde Java 5 para métodos genéricos, el tipo se infirió en función del contexto. En Java 7, con colecciones que usan genéricos, no era necesario definir el tipo “genérico” en ambos lados, se deducía del lado izquierdo de la instrucción.
Map<String, Long> myMap = new Hash<>(); //Type inference added in Java 7 List<Address> myAddress = new ArrayList<>(); //Type inference added in Java 7
Sin embargo, “Inferencia de variable de tipo local” en Java 10 lleva esas ventajas de las capacidades del compilador un paso más allá, proporcionando esta nueva característica que ayuda mucho en la legibilidad y mantenibilidad del nuevo código.
Consideraciones Importantes
var
solo funciona para variables locales en un método. Los miembros de campo, los parámetros de método, los tipos de devolución no pueden servar
.
public class Test { public var user; //Won't work, var scope is local private String fileName = "file-name.txt"; public void myMethod(var myParam){//Won't work, conflicts with overloaded methods var n = 1L; //THIS IS VALID. infers Long var list = new ArrayList<String>(); // THIS IS VALID. infers ArrayList<String> var stream = list.stream(); // THIS IS VALID. infers Stream<String> var path = Paths.get(fileName); // THIS IS VALID. infers Path var bytes = Files.readAllBytes(path); // THIS IS VALID. infers bytes[] } public var myOtherMethod(){//Won't work, Return type of the method can not be var. var n = 1L; //THIS IS VALID return n; } public Long myLastMethod(){//Will work, return type is Long (not var) var n = 1L; return n; } }
var
no funcionará si no inicializa la variable local o la inicializa connull
. La variable local debe inicializarse en el momento de la declaración; de lo contrario, el compilador no la inferirá y lanzará un error.
public void myMethod(){ var n; // Won't work, not able to infer the type var t = null // Won't work, not able to infer the type }
- La inferencia de variables locales está disponible dentro del bloque de inicialización de declaraciones de bucle, try-with-resources y expresiones lambda.
List<String> myList = Arrays.asList("a", "b", "c"); for (var element : myList) {...} // infers String try (var input = new FileInputStream("validation.txt")) {...} (var a, var b) -> a + b; //Válido desde Java 11.
- Sin cambio de tipo dinámico. Una vez que se infiere el tipo de variable local, no se puede cambiar.
public void myMethod(){ var myHello = "World"; //Type is inferred as String myHello = 123L; //Won't work. Not possible to assign another type value }
- Sin sobrecarga de tiempo de ejecución. Como el compilador infiere el tipo según el valor proporcionado, no hay pérdida de rendimiento.
Recomendaciones
Las declaraciones de variables locales pueden hacer que el código sea más legible al eliminar la información redundante. Sin embargo, también puede hacer que el código sea menos legible al omitir información útil. En consecuencia, utilice esta función con criterio; no existe una regla estricta sobre cuándo debe y no debe usarse.
Oracle, Documentación de Java 13
Como buena práctica, al declarar variables con var
, se recomienda agregar un nombre significativo a esa variable, lo que ayuda con la legibilidad y la capacidad de mantenimiento del fragmento de código.
public void myMethod(){ var n = "A string value"; //Este no es un nombre "significativo" var message = "A String value"; //Este es un nombre "significativo" var path = Paths.get(fileName); //Este es un nombre "significativo" var p2 = Paths.get(fileName2); //Este no es un nombre "significativo" }
La palabra var
no es una “palabra reservada” en Java. Debido a la compatibilidad con versiones anteriores del código existente con cualquier método, variable, clase llamada var
, y aún se puede usar como nombre de métodos o variables. Sin embargo, el compilador puede diferenciar cuándo se usa var
como el tipo o el nombre de la variable. Por lo tanto, como recomendación, evitemos nombrar variables con el nombre var
, es válido pero puede confundir a otros desarrolladores.
public void method(){ var var = "String value"; //Esto es válido. Pero evitemoslo } public void method2(){ String var = "Another String"; //Esto es válido, nombre de variable var, Pero evitemoslo }
Conclusiones
La inferencia de tipo local es una gran característica que permite reducir el código repetitivo complejo. Por supuesto, hay desarrolladores que preferirán usar la definición de tipo clásica en la mayoría de los escenarios, pero usarla de manera inteligente puede mejorar mucho la legibilidad y la capacidad de mantenimiento de nuestro código.
Los desarrolladores de otros lenguajes (Kotlin, Python, JavaScript) generalmente se quejan de evitar la verbosidad de Java, esta es una buena manera de reducir esa verbosidad, especialmente cuando se trabaja con colecciones genéricas.
Referencias
- https://developer.oracle.com/java/jdk-10-local-variable-type-inference.html
- https://openjdk.org/projects/amber/guides/lvti-faq
- https://blog.adamgamboa.dev/from-java-9-to-java-14-whats-new-part-1/
- https://docs.oracle.com/en/java/javase/13/language/local-variable-type-inference.html