4 things you didn't know you could do with Java
Java is often described as a simple programming language. While this is arguably true, it has still retained the ability to surprise me after using it full time for years.
This blog post describes four features that are obscure enough that they’ve surprised either me or one of my seasoned colleagues.
Abstract over thrown exception type
Yes, throws
clauses may contain type variables. This means that this sort of thing is admissable:
As the example suggests, this pattern is frequently useful if you want to do functional abstraction without having to rethrow exceptions as RuntimeException
everywhere.
The place people are most likely to encounter this for the first time is when looking at the Throwables
utilities in Guava.
Intersection types
This refers to the ability to write down a type that is the set intersection of two other types – so the type A & B
is only inhabited by values that are instances of both A
and B
. Java lets you use this sort of type within generic bounds, but not anywhere else:
One place this comes up in practice is where you need to know that something is both of some useful type and also, for resource managment purposes, Closeable
.
Constructor type parameters
Constructors are somewhat analagous to static methods. Did you know that just like static methods, constructors can take type arguments? Observe:
This feature is useless enough that I’ve never felt any desire to do this. In fact, I only noticed it when I was reading a formal grammar for Java.
Note that the type parameters you write here are not the same as the type parameters of the enclosing class (if any). This means that unfortunately there is no way to write the static create
method below as a constructor, since it requires refining the bounds on the class type parameters:
Inline classes
I’m sure everyone is aware that you can declare anonymous inner classes within a method body like this:
But did you know that you can also declare named inner classes too?
The inner class (which may not be static) can close over local variables and is subject to the same scoping rules as a variable. In particular, this means that a named inner class can use itself recursively from within it’s definition, but you can’t declare a mutually recursive group of multiple classes like this: