98

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?

Eric Leschinski
  • 146,994
  • 96
  • 417
  • 335
Tony Le
  • 983
  • 1
  • 7
  • 4
  • ? is a shorthand notation; internally compiler replaces it with a type parameter anyway; when there's compiler error, you'll see the surrogate type parameter, instead of the ? – irreputable Aug 15 '10 at 18:18
  • 9
    correction: my previous comment is WRONG. wildcard is more sophisticated than I thought. – irreputable Aug 23 '10 at 17:46
  • @irreputable while it is more complicated indeed, your point about replacing it with a type parameter is entirely valid; it's just one that you can't declare. – Eugene Jul 09 '19 at 11:40
  • if we look at _just_ these two methods as they are - there is no difference and just a matter of style; otherwise (if you add some more generic parameters), things will change – Eugene Jul 09 '19 at 11:50

5 Answers5

149

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.

Related questions


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
Community
  • 1
  • 1
polygenelubricants
  • 376,812
  • 128
  • 561
  • 623
  • Thank you very much, your explanation is very clear and instructive – Tony Le Aug 16 '10 at 08:02
  • 1
    @Tony: The book also has a short discussion on how to choose between wildcard vs type parameter when there is no bound. Essentially, if the type parameter appears only once in a method declaration, use wildcard. See also the `reverse(List>)` example from JLS http://java.sun.com/docs/books/jls/third_edition/html/conversions.html#5.1.10 – polygenelubricants Aug 16 '10 at 08:17
  • I am getting the UnsupportedOperationException for the following code, public static void add(List super T> list, T num) { list.add(num); } – Samra Sep 23 '13 at 05:30
  • 2
    Also - you cant pass `?` as a method parameter like `doWork(? type)` because then you can not use that parameter in method. You need to use type parameter. – Tomasz Mularczyk May 22 '16 at 20:44
  • @polygenelubricants How can I write replacement of `public void addIfPretty(List shapes, T shape) ` using wildcards, which does not give compiler error, like you mentioned which is NOT TYPE SAFE? I am still not able to understand any use case which cannot be done using type parameter, but can be done using wildcard – Vivek Vardhan Apr 14 '18 at 15:44
  • 1
    @VivekVardhan you can't create such a method using wildcards, that is the point. When deciding which to use, [this](http://www.angelikalanger.com/GenericsFAQ/FAQSections/ProgrammingIdioms.html#FAQ302) is one of the best sources explaining. – Eugene Jul 09 '19 at 12:59
6

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.

Andrei Fierbinteanu
  • 7,656
  • 3
  • 31
  • 45
2

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.

chammu
  • 1,275
  • 1
  • 18
  • 26
1

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.

0

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.

Nikita Rybak
  • 67,365
  • 22
  • 157
  • 181