In this post, I’m going to talk about some actual examples on how we can use Java generics to make our own code type safe.
In my last article, I explained how generics provide type safety in our code. More specifically, I explained how using code that has been implemented by other people using generics can give us the benefits of type safety.
In this post, I’m going to talk about how we can utilize generics in our own code (not someone else’s code) to achieve type safety and to brag to your friends how esoteric your code is (just kidding, I do not advocate unreadable code, it’s a pain for people reading your code).
And as always, I love examples that explain the motivation. I think it makes much more sense.
Disclaimer: You might have seen these examples somewhere on the Internet. If you find another article that explains these concepts, I would like to give the author credit for that.
Example 1: DRY Principle when Initializing a Generic Class
I just love this pattern. Google’s Guava library provides the
object to do precisely this.
So you’re just happily declaring lists in Java SE 6 as follows.
1 2 3
Don’t you wish you could just not repeat yourself typing the same type parameter on the right hand side of the expression? I guess Java SE 7 helps alleviate this issue a little bit by incorporating the diamond operator.
1 2 3
Hmm, slightly better. But we can do even better using Google Guava’s
1 2 3 4 5 6 7 8 9
“Wait, what? What is this magic? What just happened?”
Let’s take a look at the function signature of
1 2 3
For those of you who are not accustomed to the syntax, you might find this really bizarre. Turns out it’s not as bad as it looks.
<E> that comes after the
static keyword is called a type
parameter for the method. It’s like telling the compiler, “Hey, in the scope
newArrayList() method definition,
E is not an actual class name,
but a placeholder for some class! So don’t complain when you don’t find a
E anywhere in the classloader.” Also, by convention, we use
single capital letters for type parameters, to avoid confusion with actual
classes that exist in the class loader.
So how does the compiler know where to find
E? It turns out that when evaluating
The compiler is smart enough to figure out that since the return value of
newArrayList() in this expression has to be assigned to a variable of type
List<String>, then the
ArrayList<E> has to be equal to
This is called type inference.
And while I’m at it, Scala has a ridiculously much better type inference than Java. It does hurt the Scala compiler’s compile times, though.
Example 2: Map with Predefined Values and Types
You have a map that you wish to use across different parts of your code. The map itself can contain objects of various types. However, you have already defined beforehand what kind of objects are allowed in the map, and also their types.
Let’s say your map can only contain:
- a user ID of type
- a user of type
- a user’s purchase orders that are of type
You will have something like this.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
It might seem pointless that we’re passing in a type parameter to
we’re not using it anywhere in the class. The use will hopefully become
apparent once I write the next class.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
I don’t even want to explain the type inference that happens in the example
above, since it’s favorably magical. But to briefly explain, the cast in the
return statement of
get() will always type check by our implementing the
We can only put items in the Map using the
put() method, which requires you
to pass a
Tag object containing the type information of the object.
Therefore, we know specifically the type of all the items that get put inside
the map beforehand. When we
get() the items from the map, the class cast
will always work.
Examples of usage:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
The value of using
TaggedMap becomes apparent when we realize that we can
directly use the
Map<String, Object> as follows, leading to a lot of
confusion especially in large code bases.
1 2 3 4 5 6 7 8 9 10 11 12
That’s it for now, I will post more examples as I find more!