Java: bounded wildcards or bounded type parameter?

JavaApiGenericsBounded Wildcard

Java Problem Overview


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?

Java Solutions


Solution 1 - Java

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.


Summary
  • Do use bounded type parameters/wildcards, they increase flexibility of your API
  • If the type requires several parameters, you have no choice but to use bounded type parameter
  • if the type requires a lowerbound, you have no choice but to use bounded wildcard
  • "Producers" have upperbounds, "consumers" have lowerbounds
  • Do not use wildcard in return types

Solution 2 - Java

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:

public <T extends Shape> T drawFirstAndReturnIt(List<T> shapes){
    T s = shapes.get(0);
    s.draw(this);
    return s;
}

or like polygenlubricants said, if you want to match the type parameter in the list with another type parameter:

public <T extends Shape> void mergeThenDraw(List<T> shapes1, List<T> shapes2) {
    List<T> mergedList = new ArrayList<T>();
    mergedList.addAll(shapes1);
    mergedList.addAll(shapes2);
    for (Shape s: mergedList) {
        s.draw(this);
    }
}

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.

Solution 3 - Java

Consider following example from The Java Programming by James Gosling 4th edition below where we want to merge 2 SinglyLinkQueue:

public static <T1, T2 extends T1> void merge(SinglyLinkQueue<T1> d, SinglyLinkQueue<T2> s){
	// merge s element into d
}

public static <T> void merge(SinglyLinkQueue<T> d, SinglyLinkQueue<? extends T> s){
		// merge s element into d
}

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.

Solution 4 - Java

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:

> Generic methods allow type parameters to be used to express > dependencies among the types of one or more arguments to a method > and/or its return type. If there isn't such a dependency, a generic > method should not be used. > > [...] > > Using wildcards is clearer and more concise than declaring explicit > type parameters, and should therefore be preferred whenever possible. > > [...] > > Wildcards also have the advantage that they can be used outside of > method signatures, as the types of fields, local variables and arrays.

Solution 5 - Java

The second way is a bit more verbose, but it allows you to refer T inside it:

for (T shape : shapes) {
    ...
}

That's the only difference, as far as I understand.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionTony LeView Question on Stackoverflow
Solution 1 - JavapolygenelubricantsView Answer on Stackoverflow
Solution 2 - JavaAndrei FierbinteanuView Answer on Stackoverflow
Solution 3 - JavachammuView Answer on Stackoverflow
Solution 4 - JavaMartin MaletinskyView Answer on Stackoverflow
Solution 5 - JavaNikita RybakView Answer on Stackoverflow