eyt*
Dec 12, 2004

Static Generic Methods in Java...

I have been applying Java generics to my new code base, and thanks to it, I have already caught a few errors that I hadn't yet caught with inserting the wrong type into the container. Of course such errors would have been obviously caught by proper unit tests, but by using generics, I knew immediately the problem.

Earlier today, however, I was trying to sort a List, and using my C++-templates knowledge was not as intuitive as I thought it would have been, but this all just turned out to be my problem. The issue is that I had created a type, Type, that implemented the Comparable interface, but I had not made use of the generic type here, such as follows:

class Type implements Comparable {
 public Type() { /* ... */ }

 public int compareTo( Object rhs ) {
    if ( rhs instanceof Type ) {
      Type r = (Type)rhs;
      // Do the comparison
    } else {
      // Don't know what to do with this; make something up
    }
  }
}

The problem that I encountered though is when I went to sort a collection of this type. I had created a list of the type, so I was looking at using java.util.Collections's sort() method, so I pecked in the following code:

java.util.List<Type> list = new java.util.LinkedList<Type>();
// populate list
java.util.Collections.sort( list );

And by so doing, I received the ever-popular unchecked method invocation warning. My instinct was that it needed a hint about being Comparable, and I was surprised that the signature was not:

java.util.Collections<Type>.sort( list );

But rather:

java.util.Collections.<Type>sort( list );

This looks very awkward, to say the least, never-mind how I was thinking that it should infer this knowledge based on what I told it. But either way, it was still giving me that warning, and it was only when I started looking at the signature a bit closer that I realized my mistake.

The final version of the code is not unlike the original one after all, only much cleaner:

class Type implements Comparable<Type> {
 public Type() { /* ... */ }

 public int compareTo( Type rhs ) {
    // Do the comparison
 }

}

java.util.List<Type> list = new java.util.LinkedList<Type>();
// populate list
java.util.Collections.sort( list );

If you look at the actual changes in the code, the code is actually extremely cleaned up. The ugly case of figuring out what to do if compareTo is called on a type that you do not know anything about, for example, is completely removed, since it is no longer possible to be called this way.

This is exactly what I was thinking about when I was writing Java Generics: Better Code or Worse?, but I had not really come across such a solid example as this one. Most of the people who preach Java generics generally do so by showing you how you no longer need to cast types from Object in containers and the safety that this awards you. And while this is an extremely visible portion of generics, generic interfaces such as Comparable allow you to very clean code, as illustrated above, allowing you to focus on the types you care about and not the odd-ball cases.

Filed In

Navigation

eyt*