Archive for January, 2008

Why you should only return Collections with bounded wildcards

My post yesterday did not receive much compliance.

Many agreed, that collections with wildcards are usefull as method parameters, most deny their value as type for return values

That’s why I have created a small example that displays the problems not using wildcards. Unfortunately these problems are not very obvious and appear late. Besides that, most of the time the caller has to puzzle with it and maybe you will never hear about it.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
public interface TightList<E> {
  List<E> getIt();
}

final TightList<Integer> integerList = new TightList<Integer>() {
  public List<Integer> getIt() {
    return new ArrayList<Integer>();
  }
};

final TightList<Double> doubleList = new TightList<Double>() {
  public List<Double> getIt() {
    return new ArrayList<Double>();
  }
};


TightList<Number> wrapping = new TightList<Number>() {
  public List<Number> getIt() {
    if ( someFancyCondition ) {
      return doubleList.getIt(); //Compiler error
    } else {
      return integerList.getIt(); //Compiler error
  }
  }
};

I think it is quite obvious what happens here.

We have a simple interface called “TightList” that returns a collection without bounded wildcard. I created three implementations. The first two of them are straight forward – no problems occur here.

But the third one becomes critical. Wrapping the other TightLists is not possible.

Conclusion

There is at least one case, where returning collections without wildcard, is problematic.
Please, oblige the users of your API and add those wildcards (at least when the collection is unmodifiable – and it really should be).

Generics and Collections done right (1 foolproof step)…

Generics are surely the biggest change (considered from developers point of view) in Java since a very long time. And they are very powerful and comfortable to use. Learning a new API is *much* easier now.And it also saves a bunch of key presses when using an IDE (who needs Closures when your IDE creates generified anonymous classes?).

But unfortunately very often Generics are used wrongly.

Most of the time most of us are simply too stupid to understand Generics. Do you know anybody that completely understands the concepts? Me neither.

While Generics offer very big improvements for the user in conjunction with Collections, it seems to be hard to set them up correctly (for the design of an API). And there exist several famous failures…

Famous Failures

Google Guice

Although Bob Lee is a brilliant guy (much smarter than I ever will be) there exist several flaws within his great framework Guice.I have created a patch that solves the biggest mistake. Unfortunately the patch has been accepted only partially and just fixed the worst issues.

Glazed List

Uuuh… At least there exists a generified version. But that is the only positive thing that could be said about.Main problem: At the moment it is impossible to register an EventListener to an EventList that has a bounded wildcard (okay you can add some fancy casts to “solve” this issue…).

Assumed you have something like EventList (EventList extendes java.util.List). You won’t be able to register an EvenListener…

So now is the time to improve the world!

Now is the time to improve your API 100 times with just one simple, foolproof step.

You don’t have to fully understand the concepts of Generics (I am far away from it). Just follow this advice and most of the cases will work just as expected:

Never, never, never use any type of Collection *without* (bounded) wildcards in a method signature.

There only exist very few cases where a collection without a wildcard is needed. And most of these cases should be described accurately as hacks.

Don’t return a collection without a (bounded) wildcard.

Wrong:

public List getCustomers();

Instead use:

public List< ? extends Customer> getCustomers();

And please, please never accept a collection without a (bounded) wildcard.

Wrong:

public void addThings( Collection things);

Instead use:

public void addThings( Collection< ? extends Thing> things);

Why is it so important?

It is *very* important because it is not possible to widen a collection later:
List doubleList = new ArrayList();
List numberList = doubleList; //Compiler error!!!

numberList.add(new Integer(4)); //as numberList==doubleList
A list of Doubles is a completely other thing than a list of Numbers. It is often forgotten that Collection classes also offer *write* access. And the compiler must avoid the addition of objects to collections with the wrong type.

The killer argument

You *only* have to know the exact type of a collection, if you try to change that collection (e.g. add an element).

If you return an unmodifiable collection (and you really should in most cases), nobody will ever be able to add an element to that collection. So nobody will ever have to know the *exact* type of that collection.

Return a collection generified with a bounded wildcard and nobody will ever *think* about touching the list!

Same goes for method parameters. In the most cases only the content of the collection is used – no write access is needed! So it isn’t necessary to know the exact type of the collection. Offer the caller a little luxury and go without the additional but completely useless bit of information.

Conclusion:

As long as there is no need for changing a collection use wildcards.

Return top
 
10 visitors online now
10 guests, 0 members
Max visitors today: 19 at 06:08 am CEST
This month: 24 at 07-06-2010 06:16 pm CEST
This year: 54 at 05-11-2010 04:53 pm CEST
All time: 54 at 05-11-2010 04:53 pm CEST

Switch to our mobile site