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?
The second way is a bit more verbose, but it allows you to refer
T
inside it:That's the only difference, as far as I understand.
Consider following example from The Java Programming by James Gosling 4th edition below where we want to merge 2 SinglyLinkQueue:
Both of the above methods have the same functionality. So which is preferable? Answer is 2nd one. In the author's own words :
"The general rule is to use wildcards when you can because code with wildcards is generally more readable than code with multiple type parameters. When deciding if you need a type variable, ask yourself if that type variable is used to relate two or more parameters, or to relate a parameter type with the return type. If the answer is no, then a wildcard should suffice."
Note: In book only second method is given and type parameter name is S instead of 'T'. First method is not there in the book.
As far as I understand, the wildcard allows for more concise code in situations where a type parameter is not required (e.g. because it's referenced at several places or because multiple bounds are required as detailed in other answers).
In the link you indicate I read (under "Generic Methods") the following statements which hint in this direction:
In your example you don't really need to use T, since you don't use that type anywhere else.
But if you did something like:
or like polygenlubricants said, if you want to match the type parameter in the list with another type parameter:
In the first example you get a bit more type safety then returning just Shape, since you can then pass the result to a function that may take a child of Shape. For example you may pass a
List<Square>
to my method, and then pass the resulting Square to a method that only takes Squares. If you used '?' you would have to cast the resulting Shape to Square which would not be type safe.In the second example you ensure that both lists have the same type parameter (which you can't do with '?', since each '?' is different), so that you can create a list that contains all elements from both of them.
It depends on what you need to do. You need to use the bounded type parameter if you wanted to do something like this:
Here we have a
List<T> shapes
and aT shape
, therefore we can safelyshapes.add(shape)
. If it was declaredList<? extends Shape>
, you can NOT safelyadd
to it (because you may have aList<Square>
and aCircle
).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
Quotes from Effective Java 2nd Edition, Item 28: Use bounded wildcards to increase API flexibility:
Applying the PECS principle, we can now go back to our
addIfPretty
example and make it more flexible by writing the following:Now we can
addIfPretty
, say, aCircle
, to aList<Object>
. This is obviously typesafe, and yet our original declaration was not flexible enough to allow it.Related questions
<? super T>
mean and when should it be used and how this construction should cooperate with<T>
and<? extends T>
?Summary