Recently, I read this article: http://download.oracle.com/javase/tutorial/extra/generics/wildcards.html
My question is, instead of creating a method like this:
public void drawAll(List<? extends Shape> shapes){
for (Shape s: shapes) {
s.draw(this);
}
}
I can create a method like this, and it works fine:
public <T extends Shape> void drawAll(List<T> shapes){
for (Shape s: shapes) {
s.draw(this);
}
}
Which way should I use? Is wildcard useful in this case?
It depends on what you need to do. You need to use the bounded type parameter if you wanted to do something like this:
public <T extends Shape> void addIfPretty(List<T> shapes, T shape) {
if (shape.isPretty()) {
shapes.add(shape);
}
}
Here we have a List<T> shapes
and a T shape
, therefore we can safely shapes.add(shape)
. If it was declared List<? extends Shape>
, you can NOT safely add
to it (because you may have a List<Square>
and a Circle
).
So by giving a name to a bounded type parameter, we have the option to use it elsewhere in our generic method. This information is not always required, of course, so if you don't need to know that much about the type (e.g. your drawAll
), then just wildcard is sufficient.
Even if you're not referring to the bounded type parameter again, a bounded type parameter is still required if you have multiple bounds. Here's a quote from Angelika Langer's Java Generics FAQs
What is the difference between a wildcard bound and a type parameter bound?
A wildcard can have only one bound, while a type parameter can have several bounds. A wildcard can have a lower or an upper bound, while there is no such thing as a lower bound for a type parameter.
Wildcard bounds and type parameter bounds are often confused, because they are both called bounds and have in part similar syntax. […]
Syntax:
type parameter bound T extends Class & Interface1 & … & InterfaceN wildcard bound upper bound ? extends SuperType lower bound ? super SubType
A wildcard can have only one bound, either a lower or an upper bound. A list of wildcard bounds is not permitted.
A type parameter, in constrast, can have several bounds, but there is no such thing as a lower bound for a type parameter.
Quotes from Effective Java 2nd Edition, Item 28: Use bounded wildcards to increase API flexibility:
For maximum flexibility, use wildcard types on input parameters that represent producers or consumers. […] PECS stands for producer-
extends
, consumer-super
[…]Do not use wildcard types as return types. Rather than providing additional flexibility for your users, it would force them to use wildcard types in client code. Properly used, wildcard types are nearly invisible to users of a class. They cause methods to accept the parameters they should accept and reject those they should reject. If the user of the class has to think about wildcard types, there is probably something wrong with the class's API.
Applying the PECS principle, we can now go back to our addIfPretty
example and make it more flexible by writing the following:
public <T extends Shape> void addIfPretty(List<? super T> list, T shape) { … }
Now we can addIfPretty
, say, a Circle
, to a List<Object>
. This is obviously typesafe, and yet our original declaration was not flexible enough to allow it.
<? super T>
mean and when should it be used and how this construction should cooperate with <T>
and <? extends T>
?