melreams.com

Nerrrrd

Back to basics: advanced Java generics

a white fox sits in the snow, looking toward the camera
Unrelated image from pexels.com to make this post look nicer in social media shares.

Last time I mentioned that there are bounded generic types and wildcards. I’ve never actually used one of those if I remember correctly, which I why I left them for a followup post.

Bounded generics are really cool – they let you narrow down which types you can use with a generic class or method while still having the flexibility to work with different types in the range you’ve defined. There are lower bounded and upper bounded generics. Upper bounded generics specify a superclass your generic type must extend and lower bounded generics specify a class your generic class must be a superclass of.

This means that you can do more interesting stuff with your generic param because you know something about what it is. Let’s use WordPress as an example. If you had a theme superclass (or probably an interface) that was extended or implemented by, say, oneColumnTheme, twoColumnTheme, gridLayout, etc you could have a theme preview page that accepts anything that extends the base theme class and calls getPreviewImage and getDescription on every item passed in, even if they’re different subclasses.

That method signature would look like:

public Result createPreviewPage(List<? extends Theme> themeList) {
    //code goes here
}

You can’t add anything except null to a collection that has an upper bounded generic type, though. Why? Java inheritance – if you have a class hierarchy of Vehicle -> Car -> Sedan -> Toyota Corolla then that Toyota is definitely a Sedan, a Car, and a Cehicle, but a Vehicle could very well be a Motorcycle or a Bus, not any variety of Car.

On the lower bounded end of bounded generics, you could have a method that takes anything that’s a superclass of integer (which could be a number or object) and adds all the numbers from 1 to 10 to it. Yes, I stole this example (and the following code) from the official docs. The code for that method looks like:

public static void addNumbers(List<? super Integer> list) {
    for (int i = 1; i &lt;= 10; i++) {
        list.add(i);
    }
}

With a collection with a lower bounded type you can add things. Taking my Vehicle -> Toyota Corolla class hierarchy above, if you have a List<? super ToyotaCorolla> then you know what the most specific thing it can be is so you can safely add one of those.

You have have a lower bound or an upper bound but not both. You can have neither, though! That’s called an unbounded wildcard and it looks like:

public boolean removeAll(Collection<?> c);

That’s from the List source code. Unbounded wildcards are for when you really just don’t care what the thing is and when you want to make sure you don’t make any major changes to your parameter. The only thing you can do with a Collection<?> is add null, you just don’t know enough about what’s in there to add an object or any sort.

In my admittedly limited experience with bounded generics, upper bounded generics are much more common so you shouldn’t be too worried if you can’t find a use for a lower bounded generic parameter. If you’re not sure when to use which kind of wildcard/bounded generic, there’s a handy guide in the official docs. There are also some really in-depth articles about generics here and here if you’d like much, much more detail :)

Back to basics: Java generics

a crowd of people release paper lanterns with candles inside that make them float into the sky. the dark sky is full of small glowing lanterns floating away.
Unrelated image from pexels.com to make this post look nicer in social media shares.

Every so often you’ve got to go back to basics no matter how long you’ve been doing something. It’s amazing how much you forget when you haven’t done something in a while, even if it’s kind of a core feature of a language you use all the time. Like Generics in Java!

So let’s talk about Generics. First of all, what is a Generic? It’s just a placeholder for a type. Where you would normally put a concrete type like String or Integer, you can put T instead.

Why should we care, though?

In short, because class cast exceptions are a pain to deal with. Back in the dark time before Java 5, you could put any object you wanted in a Collection but for that to work with Java’s type system, all of the Collections classes had to work with Objects. That meant you could put anything in, but when you got it out all Java knew was that it was an Object, so you had to know what to cast it to to use it for anything interesting.

As a bit of an aside: yes you can use arrays (not to be confused with ArrayLists) to avoid dealing with casting, but then you miss out on all the handy stuff Collections do for you, like automatically resizing themselves when you add more items. Collections for the win!

Compared to having to resize arrays manually, having to cast your objects back to the object you really wanted when you take them out of a Collection doesn’t sound so bad, but here’s the big problem with that: what if you mess up somewhere along the line and try to cast that object to something it can’t be cast to? Then you get a ClassCastException, which is really irritating because it’s a runtime exception (I should write a post about exception handling in Java shouldn’t I) for something the compiler shouldn’t have let you do in the first place. Not finding out your code is wrong in a totally predictable way until you run it sucks.

Generics to the rescue! With Generics, you can tell a collection what kind of things go in it when you create it, and then not have to do any casts when you take them out because you can only put one (depending on how you count subclasses) type of thing in there.

Okay great, but how do you actually use Generics?

If you just want to put things in a Collection and get them back out, it’s really simple. In general using existing code that uses Generics is super easy.

List<String> names = new ArrayList<>();
names.add("Amy");
names.add("Brianna");
names.add("Cara");

String name = names.get(0);

While I’m at it the <> operator (aka the diamond operator) is great. Before Java 7 you had to specify the whole type in both the declaration and instantiation, which kinda sucked if you needed, say a Map<String, List<ReallyLongTypeHere>>.

Where things get a little more complicated is writing your own code using Generics. There are two places you can put generic types, on the class declaration and on the method declaration and the really fun part is you can put different types in each place. You could put a different generic type on each method if you wanted to, but that would probably be evil so don’t do it :)

Let’s look at the List source code for an example:

public interface List<E> extends Collection<E> {
    int size();
    boolean isEmpty();
    boolean add(E e);
    E get(int index);
    <T> T[] toArray(T[] a);
}

FYI that’s a tiny subset of all the methods on the List interface, I just didn’t want to list a ton of methods that aren’t relevant to this post.

When you put a generic type like E on the class (or interface!) declaration, what you’re saying is that this class primarily deals with Es. That way when you use the same generic in methods like add and get, it’s obvious what’s going on.

Why E instead of any other letter? It’s short for element. This post has a nice list of the naming conventions for generic types. I can’t link directly to that section, so just search for “naming convention” and you’ll find it.

The toArray method declaration shows how you can use another generic type just for one method even if the class already has a generic type. The <T> just means that method takes a generic type T, it’s separate from the return value. Basically, every time you use a generic type, you’ve got to have a <T> (or <E>, or <N>, etc) somewhere so Java knows you’re using a generic and doesn’t go looking for a class named T.

One thing that’s a little tricky with generic types is getting their Class object. You need a Class for things like using Jackson to convert Json into an object in your system, but you can’t do E.class. Luckily, there’s a way around that, you can use Class<E> like so:

//here's an example method using a generic Class
public static <T> T decode(String json, Class<T> destinationClass) { //code goes here }

//and here's how you call it
Result decoded = decodeUtil.decode(myString, Result.class);

I forgot about Class<T> once and made a real mess of my code, but at least you get to learn from my mistakes. A good rule of thumb for using generics is that if you still need to cast anything, something is wrong.

There are a bunch more fancy things you can do with bounded generic types and wildcards, but I’ll get to those in another post. What I’ve covered in this post is the majority of what you’re likely to need to do with Generics, you’ll need to get a handle on this stuff anyway before the advanced stuff makes sense.