Share this:

Like this:

It is surprising to see that there are still many people who do not use generics even when they are using JDK 5 or higher. I can often see it especially when I teach some Java programming subjects at uni. Generics can be very useful and I use it a lot in my libraries and projects. So I’d like to talk about generics but not a basic knowledge of it. I will talk about Java generics in real life programming and how it can be useful as well as some unusual cases may occur and annoy you. I am also going to explain some common cases of generics usage in my next post that I have plan to write soon (hopefully). Then I’m going to write about more complex cases in the sense that it’s complex when it’s designed but rather simple when it’s used, and it’s also more practical. It means I’ll probably write two more posts about generics so stay tuned if you’re interested.

Before I start to talk about usefulness of it, let’s start with problems that can happen if you don’t use generics when using generified types.
If your code looks like this, you’re making your code error-prone.

List list = new ArrayList();

As it discards all the generic type information in the class. To see what exactly happens, better take a look at some example.

Then you will get ClassCastException saying “java.lang.String cannot be cast to java.lang.Integer” in runtime but no errors in compile-time. Why? because it uses public void test(final List<Integer> integerList) method instead of public <E> void test(final Collection<E> collection). But why does it use the one taking List of Integer instead of the one with the Collection of some type E when the passed parameter is a List of String which is a Collection of some type E, in this case, String? The reason is that SomeType is generified but when using it, no generics are used. If generified type is used without generic type info specified, the Java compiler makes it like the old type in JDK prior to 5.0 which doesn’t have generics.

So the closest type matched with a List of String is a List and that’s why public void test(final List<Integer> integerList) is called. But the method, public <E> void test(final Collection<E> collection), has nothing to do with the generic type specified in the class SomeType<T>. It’s just a generic method and the E has nothing to do with the T. Yeah, but if the type is generified, yet no generic type is specified when it is used, all the generics info including the ones in the generic methods is gone.

To solve the problem, you just need to specify the generic type. In the case above, you can even use just ‘?‘ (wildcard) since you’re not using the generic type specified in the class but the generic method, public <E> void test(final Collection<E> collection).

Now, with generics, you don’t have the problem you had before without generics.

So, it’s clear why you should use generics when using generified types. What I just explained is actually not new but well known to most Java programmers. Now, let’s talk about some benefits from using generics.

You can avoid a problem that you have with arrays if you use generics. Arrays of reference types in Java are covariant so you may have a problem like this.

Even this one causes the compile-time error too since a List of Integer is not a subtype of List of Object (In arrays, an Integer array is a subtype of Object array).

On the other hand, you may need to cast it although it happens very occasionally. Here is an example taken from one of my libraries.
In KommonLee ASM, there is a visitor class, MethodAnalysisClassVisitor.

This visitor collects all the methods / constructors and their parameter names. Why do I need this kind of tool? It’s because I needed to get the parameter names of constructors in a class for one of my libraries, JSON Statham, but there was no easy way to get the parameter names of methods or constructors in Java. Reflectionin Java certainly doesn’t have this convenience which is, I believe, an integral part for library / framework development although it would be depending on what sort of library it is. So I had to use ASM to get the method parameter names. I was shocked when I first discovered it. Anyway, back to the original topic again, the visitor is used by AsmMethodAndConstructorAnalyser.

I know that the type M defined in the MethodAnalysisClassVisitor is Constructor<T> in this particular method as I’m passing Class<T> and want to collect all the constructors in it which are all Constructor<T>, yet the Java compiler can’t figure it out so I get a compile-time error if I just do

Therefore, what I did was:
first, cast Map<Constructor<T>, String[]> constructorToParameterNamesMap to a raw type Map then it will lose all the generic type info.
second, I can cast it to Map of any key value pair since the Java compiler erases all the generic types when it’s compiled.
finally, I ended up having the following lines of code. I had to add @SuppressWarnings({ "cast", "unchecked", "rawtypes" }) to make the compiler happy. I could do it because I know the constructors stored in the Map are all Constructors of T type.

This doesn’t happen often though. So most of the time, you don’t need to do it and can enjoy type safety that generics offer.

Along with the benefit I mentioned above with the case compared with arrays, generics offer convenience of postponing specifying the type information until it is used with compile-time type safety. One example that everyone knows is Java’s collections framework. The programmer of collections didn’t know what types would be stored in the collections when it was created, thus when it came out, it stored just an object type as there were no generics. This is the part where Java loses static typing although it’s a static type language. However, after introduction of generics, the users of collections can have compile-time type safety. Ironically, the collections are one of the most popular examples of how generics can be useful, yet according to Neal Gafter, it’s one of the most important reasons why generics are implemented using type erasure and wild-card, which make generics more complex. If you’re interested in it, you’d better watch his presentation.

Although Generics were introduced in JDK 5.0, the GJ compiler that can handle generics were introduced much earlier in JDK 1.3 but it was disabled according to the Java language specification.

Generics give us compile-time type safety but it’s compile-time only because, as I just mentioned, it does type erasure which means the compiler removes all the generic type information when it compiles, and that’s why we can’t create a generic type object or array like.

T t = new T();
T[] t = new T[10];

This is impossible in Java and that’s why you don’t see method like E[] toArray() but Object[] toArray() and <T> T[] toArray(T[] a) in the Collection class and its sub classes. You can create an array of E type if an instance of array of E is given as a parameter value. For example,

It takes an array of E object then creates a new array object of E then copies all the elements in the given one to the new one then returns it.

How is it possible? It’s possible because now I’m dealing with an ‘array object’ of E type not the generic type E directly so I can get the class of the array object in order to take the component type of the element stored in the array. So first, get the class of E[] ‘object’ (not class) which is a parameter value and given in runtime, then I can get the component type of it. However, the following case is impossible.

Because there is no such thing as an NE[] ‘class’ (not object), there is no way to get the class. When it’s compiled, NE[] becomes an Object array (Object[]).

I used to hate this type erasure as I had some issues when I developed my libraries. However, I do not anymore. It’s not just because of the reason mentioned here. I have mine and will explain it later in this post.

So let me talk about why we use generics again. We use it to have compile-time type safety without having to decide the type when designing the API. One example can be found in my old post about Easier and Better Way to Use JDBC. Simply, it makes use of callback function object much more useful.

Let’s say you want to map a type stored in a List to some other type. If you don’t use generics, you probably need to make a method for each mapped type like

Now, you don’t have compile-time type safety anymore so you may pass a List of any type.
So the following code doesn’t cause any compile-time error but the runtime exception that is java.lang.ClassCastException.

Or getting all the prices from the List of Product object as I already showed. Unfortunately Java’s Collections don’t have those methods. Well, my collection library has it, but it’s incomplete and not so compatible with existing code using Java’s collections although it has a way to convert from and to Java ones. So to keep using Java’s collections, I made some helper methods to achieve the goal which is having one generic method to apply different kinds of functions to all the elements in the collections. By the way, why do I bother about it? Can’t I just use for or foreach loop? Sure, I can. So why? With the generic methods mentioned above and function objects, I can focus on the actual problems. For instance, to get all the prices from the list of Product, my concern should be getting the price of each Product not how to use for or foreach loop.

Since Java doesn’t support first-class function, the syntax is not so pleasant. However, JDK 8 will have lambda expression to support it so when it comes out, it can probably be like.

List<BigDecimal> productPriceList = productList.map((product) -> product.getPrice());
// It hasn't been finalised yet so the syntax can be different.

Anyway, Java collections still don’t have those methods so, as I said already, I made the ones for the collections. So let me talk about one of these that is Selector. What Selector does is checking all the elements in a collection and takes only the ones that meet the given Condition. I wanted to have only one Selector that can easily deal with all the classes extends Collection instead of having one for each (e.g. ListToArrayListSelector, ListToHashSetSetSelector, SetToListSelector, and so on). Thus I made it like this.

Why is it Iterable of any type extends E (? extneds E)? Otherwise, you can’t use a List of any sub type of E.
It would be easier to understand with an example. Let’s say you need to get a List of Product the price of which is greater than 50 dollars. If it’s just Iterable<E> then you have no problem with passing a List of Product yet you do have when you try to pass a List of DiscountedProduct which is a sub class of Product and it should be perfectly valid to pass it as a parameter of the selector made for Product (Think about Liskov substitution principle).
If you have Iterable<? extends E>, you can pass E type and any sub-types of E, in this case, Product and DiscountedProduct are all fine.

Then why T extends Iterable? Can I just have Iterable for the input type then I can remove the generic type T? Yes, it’s OK, but what if there is anyone who wants to extends this class and wants to restrict the input type to only List instead of any sub-type of Iterable (probably if you care about Open/closed principle)?
If you have a class like this.

You will get a compile-time error because T is not the same as “? extends T“. In this case, “Iterable<? extends E>” specified as a generic type T for the Selector1<T, C, R> is not the same as “? extends T” that is, in here, List<? extends E> (one of “T extends Iterable<? extends E>“) in the overridden method select() (It’s not actually overridden as List<? extends E> can’t be a substitute for Iterable<? extends E> here). Still not sure why List can’t be used? Well, think about this. List<String> is not the same as and can’t be a substitute for List<Object>. You know it, and I already explained it earlier when I talked about the side-effect of using arrays. Then think about this one. Can List<List<?>> be a substitute for List<Iterable<?>>? No, it’s just like List<String> and List<Object>, and the problem we have here is the same.

There will be a compile-time error when passing a Set instead of a List for the input value of the select() method.

C extends Condition1<? super E>

Next one is C extends Condition1<? super E>. What? Why is the input type of the Condition1 “? super E“? Because, with “? super E“, I can have one Condition1 object for many sub-types of the type E. Imagine that you want to get a List of Product the price of which is greater than 20, you can have a Condition1 for Product, then if you also need to get a List of DiscountedProduct the price of which is also greater than 20, you can reuse that Condition1 object for it as DiscountedProduct is a sub-type of Product which means Condition1<Product> is a kind of Condition1<? super DiscountedProduct>. If I have “C extends Condition1<E>” then I can’t do that, but because it’s “C extends Condition1<? super E>“, I can.

R

The last one is R. R extends Collection<E> so it can be any sub-type of Collection.

Now let’s look at the method. Here I have some problem.

public R select(final C condition, final T source)
{
final R result = // <- How can I get the Collection instance of R???
for (final E element : source)
{
if (condition.isMet(element))
{
result.add(element);
}
}
return result;
}

If it’s one type of Collection, I can easily create it but it’s not determined yet. It will be set when it’s used. Then why don’t I postpone instantiation of it until it’s used. More precisely when the selector is instantiated. So I just create another type to create one of Collection also using generics.

Wait, do I have to create the IterableToCollectionSelector whenever I need to use it for a different type? It seems like it’s waste of memory and not to mention of boilerplate code. OK, here comes why I don’t hate generics’ type erasure anymore. Considering type erasure, both objects, used above, actually have no difference in runtime.

So what I can do is that I can create a helper class containing one really generic IterableToCollectionSelector then cast it using a generic method so that it always returns the same instance but can be used for different types with compile-time type safety. It would be clear if I just show the code.

This is possible due to type erasure, so you don’t have to create many objects of the same type with different generic type info (e.g. instances of the same type, ‘IterableToCollectionSelector‘, with ‘different generic types’ like different E, T, C) which will be all the same in runtime. That’s why I do not hate type erasure anymore. Of course, you need to @SuppressWarnings to make the compiler quiet, but it’s not a big deal and I know what I’m doing. It’s perfectly valid.

Each time when you get an instance of IterableToCollectionSelector using the getIterableToCollectionSelector() method, you get the same IterableToCollectionSelector instance.

OK, that sounds good but do I really need to know all those complex E, T, C, R and even wildcard like “? extends E” or “? super E“? Well, you don’t have to. It depends on what you do. If you’re a library or framework developer, you should probably. Otherwise, not really. The library or API designer should carefully design it to offer APIs that are easy to use and understand for the users of the library. The designer or architect, on the other hand, should know the things I talked about here to make complex things simple. That’s our job, isn’t it? Making a complex thing simple then solve it. Anyway, most of the time, you don’t need to deal with that kind of complex API if you’re an application developer. Your company should have at least one person who can deal with it and he/she should provide easy to use APIs. If your company doesn’t have any, ask your boss to hire one. Using well designed good APIs can surely save your time which means saving your company’s money. Also less error-prone.

So how can the IterableToCollectionSelector be simple so that the users wouldn’t need to care about E, T, C, etc.

The library designer should create more specific type of selector like

Yet, this doesn’t work. When getIterableToArrayListSelector() is called there is no generic type info given so it returns just an object of IterableToArrayListSelector<Object>. Thus it causes a compile-time error on calling select(greaterThan20, productList).

It’s not so elegant though. It can be solved as well. How? instead of having the getIterableToArrayListSelector() method to get an instance of IterableToArrayListSelector, why don’t I just create another generic select() method which does both getting the instance and calling the select() method in it.

As you can see, depending on how you use generics it can give you a really nice, simple and easy to use API.

Just a moment. It might not be enough. That select takes an Iterable object and returns an ArrayList object, but what if I want to get HashSet instead, or what about taking an array as an input parameter instead of an Iterable object? It can be accomplished too, but I’m not going to explain it here. I’ll do it later when I talk about good API design in another post not in the generics series.

In the meantime, you can use what I’ve already provided in my library that is KommonLee.

Next post about generics would be about something easier than the selector example. So it would be some practical but easier, then the final post would be about really complex one when it’s designed but easy when it’s used. It is also very practical and useful. Unfortunately, however, I can’t tell when I can write it as I need to think about good examples to explain. As you can see above, it can be difficult to understand without example code (or even with it, still difficult). I do actually have some examples but it’s the code I made for my work so I can’t just use it. Anyway, I will figure it out so stay tuned.