Local Type Inference in Java 10, Or If It Quacks Like a Duck
Quite recently, Oracle adopted a new strategy of releasing a new language version every six months. The strategy assumes that only every 3rd version will have long-term support, or LTS. Quick notes about it:
- Current version that has LTS is Java 8;
- Java 9 is only supposed to have support until March 2018, so it is already OVER;
- Java 10 is supported through September 2018;
- Next version to have LTS is supposed to be Java 11, which is supposed to be released in September 2018 and will be supported at least through to September 2023.
Our company still haven’t adopted Java 9, but now it looks that skipping it completely and jumping to the next LTS might be a valid option. There are many more concerns except for Java itself, for example Spring Boot Java versions etc, so we probably will tread carefully. Still, in view of the inevitable changes, I decided to look into what’s coming in Java 10. And it looks like the main thing that’s coming in that version is local type inference.
We all know this Java syntax:
Basically, local type inference is the possibility to replace it with:
This means that the code has a little less boilerplate, but you need to pay more attention to variable and method names, because the var keyword isn’t self-explanatory. There’s quite a good (though maybe a little too verbose) webinar from JetBrains explaining how to use local type inference while using IntelliJ IDEA for IDE.
Local type inference has been there for a long time in a lot of programming languages, such as Scala, C#, Go, and of course Kotlin. In that respect Java has been trailing behind, and now has decided to fix that. However, there was some controversy regarding the concrete implementation of this. For example, there was a possibility of:
- having val for local constants and var for variables as in Kotlin or Scala;
- having const or just final for local constants and var for variables since const and final are already reserved in Java;
- having final var for constants and var for variables;
- utilizing let, def or := ;
- and more on this here.
Finally, it was decided to keep the syntax closer to what’s already there and allow var for local variables and final var for local constants, so the example shown above will work in Java 10. However, the replacement isn’t always straightforward. For example:
Here in example two, with direct replacement of the left side the compiler isn’t able to infer the list type, so it’ll default to Object. Which will trip you when you try to process the items from the list.
One example where local type inference is helpful is data transformations. For example, you want to change the objects of one type into another, having different attributes, and use an anonymous class for that. In Java 8, you could only do it inside a stream scope, so for example the new properties would be accessible to you within a stream pipeline, but not outside.
In Java 10, you could use the transformed list of new object outside the stream pipeline.
So, after the stream closure is over, the mapped object properties are still accessible. However, as it is a local type inference, you won’t be able to use them outside the local scope of the current method. Var keyword won’t work in a method parameters declaration, and so you can’t pass in a var into another method. So, having var doesn’t mean that Java magically becomes dynamically typed. It is still typed statically, just with the added bit of syntactic sugar, and only in places where the compiler can infer the type.
To me, it is showing that Java strives to move forward, but is very much hindered by trying to keep to its historical roots, making backwards compatibility and not innovation its main priority.