Skip to main content

Java with Generics

Posted by ddevore on January 12, 2006 at 12:06 PM PST

I have been using Generics now for almost a year now and have found a love/hate relationship with them. My introduction to what Generics would do to you was when I compile a project with a UniqueList utility class I have been using for years now. This is a simple extension to the ArrayList which does not allow duplicates, nulls and keeps them in order. I really like this class because it is easy to use and very simple to make. The problem was that when the compiler hit the class I though it was going to hit me over the head with a ball bat. It threw errors everywhere. Since Generics are not going to go away I figured I would start my Generics learning with rewriting my utility class. I started by reading what ever I could find about them then I found this tutorial, nice job Gilad, and went to work.

Modifying UniqueList
In modifying UniqueList I found that Generics were not all bad. It is a little confusing at times but in all it is workable. To get the compiler to put down the ball bat I basically had to add a couple of <E> codes and we were all happy again. I thought Great I am a Generics expert..that didn't take long. Curses that is not all there is to it.

On with Generics
From the start I found Generics easy to use though the implementation of classes/utilities which use Generics can be a little confusing as found in modifying the UniqueList but how often do you really create util classes? Also, if you are planning on using a generic with sub classes don't forget the <? extends String> notation. This blog is not to investigate the full use of Generics. It is to point out a few highs and lows of them.

Dislike
Then I started to do more work with it. Though I understand the Generics concept and know how it works you cannot use them in all conditions. Sometimes you need a list of undefined object types. So you go to the old reliable method of declaring a Collection.

ArrayList al = new ArrayList();

Instead of the new method.

ArrayList<String> al = new ArrayList<String>();

This is not a big deal until you use that variable and the compiler yells at you with ball bat in hand. For some reason the compiler thinks it knows more about Generics than I do which I am sure it does. The problem with this is that sometimes you need a "generic" object list and not a Generics list. There is no way to stop this checking and -Xlint:unchecked will show a detailed list of these warnings. Now I am the type of person who likes to have my code as clean as possible. I don't like turning off checking and I usually have checking for deprecated classes turned on to remind me of things which need to be cleaned up. When I find a warning I usually go fix it if there is any way I can do it be it my warning or someone elses. For me to have a clean command line and have this warning bugs me. This is the big dislike.

Then you have the length of the lines for Generics. As I mentioned above I like clean code. I keep my code within the 80 col marker when possible but like descriptive names for my classes. This creates a problem of long lines when you use Generics. Take for instance a class with the name AccountInformation used in a ArrayList.

ArrayList<AccountInformation> accountList = new ArrayList<AccountInformation>();

This line indented takes you over the 80 col limit so you have to wrap the line

ArrayList<AccountInformation> accountList =
        new ArrayList<AccountInformation>();

Which just isn't the same and if you like your code a certain way this may not be good. I like code on one line but I know that to have the descriptive names like I want you cannot always have the short lines. This is about all the dislikes yes there are only 2 and are very small considering the advantages Generics provide.

Likes
What I do like about the Generics outweighs the 2 minor dislikes considerably. Using Generics with the new and improved loop makes live much easier. Lets look at a loop using the new and old method with the accountList.

New Method

for (AccountInformation ai : accountList) {
    // Do something with the account information ai
}

Old Method

AccountInformation ai = null;
Iterator it = accountList.iterator();
for (int i = 0; i < accountList.size(); i++) {
    ai = (AccountInformation)it.next();
    // Do something with account infromation ai
}

As you can see from this simple example the new method is shorter and simpler to use. The compiler automatically puts in the casting of the type to the variable and iterates over the list. No more manual iteration over the list or unsafe casting. This is possible because the compiler does the type check for you to insure that the list contains only AccountInformation objects, this is where the warning from the dislikes comes in, so you always know what you are working with. If the Old Method above were to be written to insure safe casting it would look more like this.

Old Method with Safe Casting

Object obj = null;
AccountInformation ai = null;
Iterator it = accountList.iterator();
for (int i = 0; i < accountList.size(); i++) {
    obj = it.next();
    if (obj instanceof AccountInformation) {
        // Now you are asured that the type is correct and it is safe to cast.
        ai = (AccountInformation)obj;
        // Do something with account infromation ai
    } else {
        // Not safe to cast you must do something else.
        // Handle Error.
    }
}

You can see from the examples above that it lessens the code required for a loop and insures safe object casting. The compiler also insures the correct type improving the typeing of the objects and helps to eliminate the need for as much error checking.

Conclusion
Love them or hate them you should know them because they are not going away. If you are new to Generics remember they are there to make your life easier and from the examples above you can see that they do. Also, this is only one example of where they make life easier. You should try them out and see what they can do for you.

More information
For more information on Generics and other changes in Java SE 5 please see the following:
Java Tutorial
Java SE 5 Adoption

Update
Using @SuppressWarnings("unchecked") on methods which perform castings will tell the compiler to not warn on unchecked types. Thanks Dave for the information.

I have not looked at annotations yet I guess that should be my next task and I will test this one out then.

Related Topics >>