It’s been over 15 years since the introduction of the Java programming language (and the first edition of this book). In that time, the Java language has matured and come into its own. But it wasn’t until Java 5.0, the sixth major release of Java, that the core language itself changed in a significant way. Yes, there were subtle changes and drop-ins over the years. Inner classes, added very early on, were important. But no language improvements prior to that point affected all Java code or all Java developers in the way that generic types did in Java 5.0.
Generics are about abstraction. Generics let you create classes and methods that work in the same way on different types of objects. The term generic comes from the idea that we’d like to be able to write general algorithms that can be broadly reused for many types of objects rather than having to adapt our code to fit each circumstance. This concept is not new; it is the impetus behind object-oriented programming itself. Java generics do not so much add new capabilities to the language as they make reusable Java code easier to write and easier to read.
Generics take reuse to the next level by making the type of the objects with which we work into an explicit parameter of the generic code. For this reason, generics are also referred to as parameterized types. In the case of a generic class, the developer specifies a type as a parameter (an argument) whenever she uses the generic type. The class is parameterized by the supplied type to which the code adapts itself.
In other languages, generics are sometimes referred to as templates, which is more of an implementation term. Templates are like intermediate classes, waiting for their type parameters so that they can be used. Java takes a different path, which has both benefits and drawbacks that we’ll describe in detail in this chapter.
There is much to say about Java generics. Some of the fine points may seem a bit obscure at first, but don’t get discouraged. The vast majority of what you’ll do with generics is easy and intuitive. The rest will come with a little patience and tinkering.
We begin our discussion with the most compelling case for generics: container classes and collections. Next, we take a step back and look at the good, bad, and ugly of how Java generics work before getting into the details of writing generic classes. We then introduce generic methods, which intelligently infer their parameter types based upon how they are invoked. We conclude by looking at a couple of real-world generic classes in the Java API.