Make your code simpler with implicit casting in improved
instanceof
operator in Java 14.
The improvements in the instanceof
operator (JEP 305
) are not the most important feature of approaching Java 14. However, it finally implements the syntactic sugar that was available in Groovy for years, so I want to have my readers aware of it and simplify their code (once migrated to Java 14+ :-) ).
“instance of” usually is perceived as a scratch in well designed object oriented system. Nevertheless, there are places where it simplifies the code greatly and/or is the only sensible way to go.
The usual way
Double type checking in Java code is considered as something “normal” (or better something “common”):
if (o insteanceof String) {
useString((String)o);
}
The same with combined condition checking:
if (o instanceof String && (((String)o).lenght > 10) {
...
}
It looks even worse if the class name is longer, e.g. ContentHandlerAlreadyRegisteredException
(while received just Exception
or Throwable
).
The new way (Java 14+)
With fast approaching Java 14 (GA scheduler on 2020-03-17) it becomes much simpler:
if (o instanceof String s) {
useString(s);
}
The new binding variable (of type String
) is available in the if
block.
It works also for combined condition checking:
if (o instanceof String s && s.length > 10) {
...
}
It can be used also in more complex if..elseif..else
constructions. However, in those cases, the new switch..case
syntax with the pattern matching allowing - still on the work desk
- would be even more handy.
The Groovy way
I wouldn’t be myself, if I skipped a comparison with Groovy :-). In Groovy that double type checking mitigation has been available for years. Even better, thanks to the AST transformation there is no need to define an extra variable. We can just use the original name which is visible with proper typing inside the block:
if (o instanceof String) {
useString(o)
}
It is dead simple, but I have to admit that an extra binding variable with a custom name might be perceived as something slightly more readable with bigger block of code (which anyway could be usually moved to a separate method).
The switch..case
statement is very powerful in Groovy. Checking the instance type is very straightforward:
switch(o) {
case String:
println "String"
break
case Integer:
println "Integer"
break
default:
throw new IllegalArgumentException(...)
}
However, even in Groovy 3, there is no type changing withing the scope (available in the if..else
). As a result the following works without code completion with dynamic Groovy and fails with @CompileStatic
:
void sortItOut(Object o) {
switch(o) {
case String:
println "String: ${o.length()}" //only in dynamic Groovy
break
case Integer:
println "Integer: ${o.longValue()}" //only in dynamic Groovy
break
default:
throw new IllegalArgumentException(o.toString())
}
}
I have to raise a ticket to support that ;-)
Update. It’s been already proposed - GROOVY-8411 .
Summary
There is a number of small, yet useful changes introduced in Java 12+ (or waiting for implementation in the incoming releases). Multiline string, yield
in switch..case
or smarter NullObjectExcpetion
just to mention a few. Thanks to that Java becomes more and more compact (although Groovy or Kotlin are far ahead on that field).