Introduction to Java Generics

0

In the real world analogy, if you are buying a house you know beforehand the rooms it will have like kitchen, living room, play room, bedroom etc. You know what each room is meant for and what it has to be furnished with. You already have all the required furniture and accessories and only need to move them to the new house. the movers arrive, and you instruct them about which items go where in the new house. They then organize and pack everything in boxes and move all the stuff to the new home. Like instructed, some boxes go into the kitchen, some into the bedrooms, some into the playroom and so on. When you proceed to unpack and arrange stuff the next day, you find that the boxes in the kitchen contain stuff meant for the living room, the boxes in the playroom have stuff belonging in the bedroom and boxes in the bedrooms have the kitchen accessories. How did this happen, you wonder. The boxes were not labelled!

In the Java world, Java Generics prevents us from getting into an issue like the above. It helps us to label so that we don’t end up using wrong types. It shows the developer exactly where the incorrect object is used at the compile time itself thus enforcing type safety.

It was added to Java 5 in 2004.

In this article, I will introduce you to generics and show you how it helps in finding issues at compile time rather than at runtime.

For example, consider the following code:

List playItemsBox = getPayItemsList();

Now we have want to know the no. of items in the box, we will call:

System.out.println(playItemsBox.size())

.
The type system ensures that whatever object getPayItemsList has method size() else it will show a compilation error. If we use the wrong method, we can fix it at compilation stage thus avoiding any runtime error.

Now suppose we want to get one of the play item and play. We might write.

List playItemsBox = getPayItemsList();
playItemsBox.get(0).play();

This is obviously incorrect and leads to a compile time error as list.get() returns Object and there is no method called play() in it.
One can solve this problem by type casting.

List playItemsBox = getPayItemsList();
((PlayItem)playItemsBox.get(0)).play();

Casting forces compiler to treat (PlayItem)playItemsBox.get(0) as a PlayItem object. This works but has one issue.

What if one adds a KitchenItem to playItemsBox? The compiler won’t be able check this problem and we will know it only at runtime when we try to typecast a kitchenItem to a PlayItem.

We can solve this problem by introducing a new class called PlayItemList, extending one of the List subclass. It can then have its own add(PlayItem) and PlayItem get() methods. If we follow this approach we will end up with a new class for each room. Whenever we introduce a new room, we will have to write a new custom list for that room. This would result in code duplication which is something we must always avoid.

With the introduction of generics, the above problem can be solved by creating a list just for type PlayItem. If you compare it to the real world Box problem we discussed in the beginning, it is just like labeling each box.

List playItemsBox = getPayItemsList();
playItemsBox.get(0).play();

In addition to type declaration, we can also use generics in methods. In my coming articles on Generics, I will cover each case.

About Author

Ram’s expertise lies in test driven development and re-factoring. He is passionate about open source technologies and loves blogging on various java and open-source technologies like spring.
You can reach him at [email protected]

Leave A Reply