Introduced as a new feature in Java 11, Local variable type inference allows to use the var
word instead of the “type” when declaring a variable into local block-codes, and the compiler is able to infer the corresponding type of that variable from value you are assigning. That’s a feature that can be found in other JVM languages (Scala, Kotlin).
Once of the features of Java as language is that it’s strongly type-safe, and with this feature it continues as the Type-Safe language. The feature is using the information and context the compiler and runtime already have to determine that type when the variable is assigned, once it’s assigned, the type will not change (as it can be done on JavaScript or Python).
Using wisely this feature can help us to make our code more readable and less verbose (a common complaint to Java code). However, there are developers that believe the feature is an anti-pattern, a code smell, and should be avoided. That’s why I have decided to share some points about why var
is very useful in some situations and should not be afraid of using it.
Why developers might want to about it?
Let’s analyze some of the reasons why some developers might want to avoid using this feature, and desmitify some of those reasons if possible.
1) Hides the type and requires effort to figure it out
One of the reason why some developers say we should not use the var
“keyword” in Java is because “using var is hiding the type from the person reading the code and will require them to have to figure out what is being done“.
public void myMethod(){ var counter = 0; var message = ""; while(counter < 10){ //some logic here message += "some value"; count++; } }
But let’s see that scenario. You don’t need to figure out what is the type, it’s there just a few lines above. The same effort to check type is required to see the right side of that declaration and realize it’s a number or a String. And that effort is minimum, the declaration is in in the same block of code a few lines above.
And if you need to scroll up a lot to see the declaration of the variable to see the type, the problem might not be the type is inferred and not explicit, the big problem is the name is not meaningful and, also you might need to refactor your method to reduce the lines of code it requires. Those two are more important “code smell” to handle.
2) It might be confusing with polymorphism
Another reason, for polymorphism, it could be confusing to determine what is the type. One example that I saw for “supporting” that idea.
public class MyService { public Mustang getCar(){} } public class Mustang extends Car {} //Another place in the code void myMethod(){ var myCar = service.getCar(); //here the type is hidden because it's not explicit in the right side. .... //some lines later //WHAT TYPE COULD BE myCar? }
Here the problem is again not using meaningful names for the method and the variable. If the getCar()
method is returning a Mustang
maybe naming the method getMustangCar()
is a better option. Also, naming the variable var myMustangCar
instead of just myCar
is a better practice.
Actually in the above scenario we are not using polymorphism, because it’s returning a “concrete” type, not the abstraction. And using var
keyword is forcing us to follow other good practices when I can use better names improving truly readability in the code.
3) Don’t know the return type of the method
I agree partially with this argument, there could be some scenarios where maybe just by the method name, and the variable name during the declaration there is not enough information or context to determine the type.
var descriptor = service.getDescriptorSpecification(); var ratio = foo.calculateRatio();
That’s true, what could be the type of descriptor
, it might be a String
, or Map<Long,String>
or another Class, we don’t know. If we want to use some behavior from descriptor
it could be harder to realize the type.
For those cases, using the type explicitly could be the best choice.
Map<String, String> descriptor = service.getDescriptorSpecification(); int ration = foo.calculateRation();
However, now a days, 99% of Java developers use IDE (IntelliJ, VS Code, NetBeans, Eclipse, etc) with the capability to provide us the type. The IDE usually adds a label, or tooltip next to the variable declaration, or display type by moving the mouse over the method, and when we use the variable the IDE provide us with the autocomplete option displaying the options for that type.
Scala and Kotlin developers does not complain because the type is not always there, why should we do it in Java.
Have you forgotten lambda expressions input variables?
What about the input variables of the lambda expressions. Something like these ones:
//Example 1 (a, b) -> a+b //Example 2 v -> v.toUpperCase().trim() //Example 3 d -> d.doSomething() //Example 4 (x, y) -> { //What type is x, what type is y? String message = ""; if(x > 20){ message = "dummy"; } else { message = y.getMessage().trim(); } return message; }
In this case, the type is inferred by the compiler, and doesn’t have context – like the right side of the assignment – to determine its type. Also, it’s very common to only use short names in the variables (not meaningful). You would need to rely on the IDE capabilities or jumping to the definition of the class to see the functional interface and the types of the parameters of its input variables.
However, developers does not complain about that feature … Interesting … If you as developer use lambda expression without complaining about the type being inferred, why would you complain for the var
keyword in other local blocks?
Good use cases for var
So, as mentioned before, there could be some scenarios where there are some arguments about if using var
or not could be useful or not. However, there are some scenarios where using var
is the best option, and nothing can argue the opposite.
Making Generics more readable
Introduced in Java 5, Generics allows the developer to create more powerful type-safe patterns, but it might make your code very verbose.
Map<String,List<MyClass>> myMap = new HashMap<String, List<MyClass>>();
There are some enhancements to reduce verbosity and also infer the type in Java 7. However, var
is the pinacle of those improvements.
var myMap = new HashMap<String, List<MyClass>>();
It really reduces verbosity of our code, and make it more readable.
Classes with Long names
A good practice is to use meaningful class names, but it some cases it can makes create classes with very long names.
class SnafuVeryLongFooBarDescriptorMap {} //In another place in the code public void myMethod(){ SnafuVeryLongFooBarDescriptorMap myMap = new SnafuVeryLongFooBarDescriptorMap(); }
In that case it might be considered redundant and unnecessary to defined twice the long name of the class. And trust me, I have seen longer names than that one.
class SnafuVeryLongFooBarDescriptorMap {} //In another place in the code public void myMethod(){ var myMap = new SnafuVeryLongFooBarDescriptorMap(); }
Local Type Inference variable – var
– to the rescue!!!.
Conclusion
I am not telling everybody should use var
everywhere, just DO NOT BE AFRAID OF USING IT, it there is a scenario where using var
improves readability or reduce verbosity, let’s use it, it was added to the language with a purpose.
Java is considered a verbose language (compared with other language), most of the time is because of the Type Safe provided by the language, there is a good feature available to reduce verbosity in some cases – like generics – and keeping type-safety.
With 4 years creating also code in Scala, and creating some code in Kotlin, I have not seen developer complaining because the type is inferred and use var
or val
, they use it in many case, and use explicit type in other cases, just following good practices in naming convention and the capabilities of modern IDEs.
When doing code reviews (maybe from Git Hub) where I am not using a modern IDE, having good naming in variables and methods helps more than the explicit type of the variable. Take advantage of the var
when possible, and even forces you to implement other good practices.
DO NOT BE AFRAID OF USING VAR, use it when it helps with readability, and use it wisely.
References
- https://blog.adamgamboa.dev/java-local-variable-type-inference/
- https://medium.com/@spextreme/java-var-should-be-a-code-smell-17af0be79646