java generics cheat sheet
December 1, 2016

Java Generics Cheat Sheet

Java Application Development

This post continues our series of one-page printable cheat sheets about Java and related technologies that we’ve been producing for almost a year now. Today it’s all about Java generics, a Java 5 language feature that helps to decrease verbosity in The feature was added to Java 10 years ago, and even today it still confuses many Java developers.

In this article, we'll give some background on Java Generics, look at wildcards, methods, and PECs. Then, at the end of the article, we'll share our free, one-page Java generics cheat sheet pdf.

What Are Java Generics?

Java Generics allow developers to implement a collection of types in a single declaration, reducing the verbosity of your code as well as its cost of maintenance.

Java Generics were added to the now ancient Java 5 way back in 2005 when the world was a much simpler place. The main idea of generics was to enhance the Java compiler by using additional information on the classes for additional type safety. The most prominent user of generics is, perhaps, the Java Collections framework, which consists of the classes that act as containers for other objects. For those speaking in C terminology, Java Generics are similar to "templates" in C.

Using Java Generics

Using Java Generics, a class can be parameterized with a type argument. For instance, consider class A, in the example below.


    class A {
    ...
    }


You can make it a generic type by declaring it as A (pronounced A of T). Now, you can use the type variable T, in the body of class A, as if it were a proper type.


    class A { 
    T myFieldOfTypeT;
    ...
    }


To instantiate A, you need to provide the arguments for the type parameters, which is the actual type you want to use:


    A a = new A(); 


Now a is an instance of the A class, which is a proper parameterized generic class. Here we need to clarify a few definitions:

  • Generic Type - A generic type is a class that is parameterized with type arguments, for example, ArrayList<T>.
  • Parameterized Type -  A parameterized type is a class where the type parameter is instantiated with a fixed argument, for example, ArrayList<Long>.
  • Raw Type - Araw type is a generic type that is not parameterized with anything, like new ArrayList(). 

But, why would you use a raw class? Well, in a nutshell, there are no benefits of using raw classes whatsoever. If you’re to take away one thing about the generics, here’s the most important bit: Generics do not exist at runtime! Generics are compile-time only. It means they are a utility for you to have a more readable code.

Java Generics Wildcard

You will often find a ‘?’ Symbol inside a generic parameter. It is a wildcard and stands for an arbitrary type. For example, an ArrayList<?> is an array list of any type. It means that it can represent an ArrayList of Strings, or an ArrayList of Integers, or whatever type. However, at the runtime, it will have some fixed type.

You might wonder what’s the difference between declaring your variable as List<Object> versus List<?>? In a nutshell, Collection<Object> is heterogeneous collection. It is parameterized with the common superclass of all classes in Java: java.util.Object. It means that this collection can take any object, and if you get an object from it, you cannot expect it to be anything more specific than an instance of the Object class.

Java Generics Wildcard
Wildcard Collection TypeDescription
Collection<Object>Any object goes in.
Collection<?>Homogenous collection of arbitrary type.

On the other hand, Collection<?> is a homogenous collection of arbitrary type. It means that at some point of time the compiler will figure out the bound for the types itself. So if the situation arises, we’ll get a Collection<Set> or Collection<CharSequence>, but it will be parameterized specifically. So it’s a very generic way of writing code.

In general, you can safely avoid wildcards in the generics, until you understand what it is doing to your code. Most of the time you’ll be completely fine without them.

Method Overloading and Overriding

When you use generics with overloaded methods, you may be surprised at what you see. Imagine the code below. What do you think the return value will be if you call generic(“hello world”)?


    String f(Object s) { 
      return "object";
    } 
    String f(String s) { 
      return "string";
    } 
     void generic(T t) { 
      f(t); 
    } 


It can appear unreasonable, but the returned value will be "object.” The reason for that is that generics do not exist at runtime. It’s a compile time concept, and the compiler will generate just a single implementation of the generic method. And since the code has to be ready to accept Object as a parameter, it will only generate code that calls f(Object s).

The situation with overriding methods is often even trickier. So be prepared to dive into the implementation details and peek at the generated bytecode to better understand the behavior.

Producer Extends Consumer Super (PECS)

Take a look at the centerpiece of the cheat sheet, the PECS image. PECS stands for Producer Extends Consumer Super, and it’s a nice rule of thumb for designing an API that uses generics. java-generics-cheat-sheet-graphic-v1

The image is a reworked illustration by Andrey Tyukin available under the CC-BY-SA.

First of all, there are two keywords used for type parameters. The extends keyword, in the <T extends X> declaration means that T is restricted to the subtypes of X, including X itself. The super means the opposite: <T super X> restricts T to be X or a superclass of X.

For the explanation of the PECS concept, look at the signature of the Collections.sort method.


Collections.copy(List<? super T> dest, List<? extends T> src)


The copy methods copies (duh!) elements from the src list to the dest list. The src list produces elements of type T or subtypes of T. The dest list accept elements, of type T or supertypes of T.

Generic Collections and Designing a Java API 

When you’re designing your own API, think about how you want to use generic collections in your code. If you’re retrieving elements from it, parameterize your method arguments using <? extends T>. It will make your code more inclusive, as the method will be usable not just by collections of T, but by its subtypes too. On the other hand, if you intend to put the elements into the collection, parameterize it with <? super T>, so someone can pass you any collection that accepts T: a collection of T, or a collection of Objects, for example.

If you plan on using the collection for both types of operations: consuming objects and producing them, it becomes harder. You probably need to just parameterize it as <T>, but then again maybe you want to rethink your API altogether. If you have a hierarchy of types, the collections of these types follow the hierarchy when they are producers, and the reverse when the hierarchy are consumers.

In the cheat sheet, we also mention recursive generics declarations. You can use this neat trick to add additional constraints on your type parameters to allow the compiler to infer more information about the types in your code.

Before we go, let’s reiterate the most important point you have to keep in mind about the generics: Java generics do not exist at runtime, it’s a compile-time concept. The main idea is to allow you write more general, less verbose code that is easier to read and maintain.

Additional Resources

Perhaps the most complete and advanced resource about Java Generics is the FAQ by Angelika Langer. It’s not a tutorial, but it answers almost all the questions you might have about Java generics. Or you can go through the Oracle tutorial about Java Generics.

Both are quite long, so if you prefer video Richard Warburton and Raoul-Gabriel Urma have a great session about Java Generics, their past, present and future development.

We also have a lot of other Java cheat sheets and guides that you should check out:

Download the Java Generics Cheat Sheet PDF

In this cheat sheet, we looked at Java generics, including their use cases, rules of thumb, and best practices. We by no means think that a one-page cheat sheet with a blog accompanying it can explain all of the details you need to master generics, but it’s a nice starting point.

java generics

Get the Cheat Sheet