Java Generics – were they a good idea?
No. I think that all told, while implemented with the best of intentions, Java Generics were a bad idea. While they do provide welcome and useful functionality in some cases, overall the costs outweigh the benefits.
This new language feature and its use throughout the new Java 1.5 libraries have added a significant amount of complexity to the world of the Java developer. From the slightly counter intuitive (e.g. List<String> is not a subtype of List<Object>) to the profoundly metalicious (e.g. Enum<E extends Enum <E>>), generics can be subtle and difficult to fully understand for the average Java developer. Ask the average Java 1.4 programmer to read and explain this to you:
TypeVariable is the common superinterface for type variables of kinds. A type variable is created the first time it is needed by a reflective method, as specified in this package. If a type variable t is referenced by a type (i.e, class, interface or annotation type) T, and T is declared by the nth enclosing class of T (see JLS 8.1.2), then the creation of t requires the resolution (see JVMS 5) of the ith enclosing class of T, for i = 0 to n, inclusive. Creating a type variable must not cause the creation of its bounds. Repeated creation of a type variable has no effect. (
So what do we get for all this? The way I see it, there are really only two benefits to Java generics:
(1) They allow the compiler to catch some programming errors that would otherwise be detected at runtime as ClassCastExceptions (i.e. generics can prevent you from placing an Integer into a List of Strings).
(2) They make *certain* declarations more “self-documenting”. If I see a method signature that declares a parameter as a List of Strings (List<String>) it is much clearer to me how to use the method correctly and is more reliable than the documentation, if it even exists.
For me, it’s not worth it. So I have to cast more and perhaps catch some programming errors at runtime. In my experience the vast majority of ClassCastExceptions are the result of programming errors that you will catch very early while running and testing your code anyway. You fix the code and move on. Also, if you structure your error handling correctly, you should not need to wrap each cast in a try/catch block. Bottom line: the core problem generics aim to solve is not that bad of a problem.
As for (2) I would have to say that for every example of code that generics have made easier to understand there is at least one example where it has done just the opposite. Furthermore, in real-world programming with real-world class names method signatures become multi-line monsters that are quite ugly, hard to read, and a real burden to type (so much for the keystroke savings of not needing casts).
Adding language features are a big deal. You can’t undo them and they can have far reaching consequences. Java as a language, its documentation, the number of concepts its user has to manage, and the user’s learning curve have become much more complex for marginal benefit. Any addition to the language should have the effects of making programs easier to both read and write, making concepts simpler to express, and enabling the programmer to be more productive. If anything I would have liked to have seen the addition of multiple dispatch to Java (sometimes called generic methods (yes confusing) – perhaps more on this in another post).
Do I use it?
For the cases where I have no choice (grrr) and for the cases where it truly is a harmless perk (like Map<String, List>), yes, sometimes. Otherwise I avoid it.