Created By: Geoffrey Challen
/ Updated: 2022-05-23

In this lesson we'll examine Java generics. This is an advanced topic, but one that you are bound to encounter as you continue to use Java. Generics also allow the compiler to better check our code—and we always want that. So let's do this!

Using Generics

We've already seen generics at use when using Java's containers like Lists. We can create a bare List, but using one requires dangerous downcasting:

Instead, by providing a type parameter when we create the list, we can get the compiler to help us:

Remember: runtime errors cause things to fail right in the user's face. This is not good! Compiler errors, in contrast, must be caught in development. So transforming runtime errors to compiler errors helps us produce more correct programs. This is good!

Generifying Our Classes

OK—so now we know how to use classes that accept type parameters. But how about using the in our own classes? This turns out to not be too hard! Let's explore together.

To start, let's design a class that does not support type parameters:

Implement the LastN class without using generics.

Next, let's look at how to add a generic type parameter to our example above. This will allow the compiler to ensure that all of the values added to LastN are the same type!

Reimplement the LastN class using generics.

Compiling Generic Classes

There are a few important things to understand about how Java compiles generic classes. First, the type parameter is not a variable. You can use them in most places that you would normally use a type, but you can't assign to them, or use them in a constructor call:

One useful way to think about what happens when your program is compiled is that the compiler replaces the type parameters with types used in your code. So, given this generic class:

If I create a Example<String>, it's almost as if I had written this code:

Let's talk through a few more examples together:

Demonstrate what happens when the type parameter is rewritten.

Type Parameter Naming Conventions

You can use any name to name your type parameters. But Java has established some conventions. Specifically:

  • Type parameter names are a single upper-case letter
  • Certain type parameters have specific meanings: E for element (like a list), K and V for key and value (like a map), N for number

Parameterized Interfaces

Just like Java classes, interfaces can also accept type parameters. That includes one interface that we are fairly familiar with by now!

Demonstrate Comparable with a type parameter for the code above.

One Big Generic Gotcha

You may have noticed above that when we implemented LastN we used a List rather than an array. That wasn't an accident! Let's see why and what problems arise with generic arrays.

Demonstrate the problems with generics and arrays.

Bounded Type Parameters

(What follows is bonus bonus material, but very cool!)

Let's consider another example where we'd like to use generics:

Let's explore how we can complete the example above using another feature of Java's generics system: bounded type parameters.

Finish the example above using a bounded type parameter.

And There's More...

This lesson has barely scratched the surface of what is possible with Java generics. If you want to learn more, this is a good place to start.

Generics in Javadoc

You regularly see generic type parameters in Javadoc. Now that we've discussed a bit about how to use type parameters in our own code, we're more prepared to understand documentation for classes that use them. Let's look at one familiar example together and discuss how to identify and interpret these type parameters.

Show how to interpret generic type parameters in a familiar piece of Javadoc: like List or Map, or both.

Show how to complete the homework problem above. Feel free to cover multiple approaches!

More Practice

Need more practice? Head over to the practice page.