7

So I was reading up on generics to re-familiarize myself with the concepts, especially where wildcards are concerned as I hardly ever use them or come across them. From the reading I've done I can not understand why they use wildcards. One of the examples I keep coming across is the following.

void printCollection( Collection<?> c ) {
  for (Object o : c){
    System.out.println(o);
  }
}

Why would you not write this as:

<T> void printCollection( Collection<T> c ) {
    for(T o : c) {
        System.out.println(o);
    }
}

Another example from the oracle website:

public static double sumOfList(List<? extends Number> list) {
    double s = 0.0;
    for (Number n : list)
        s += n.doubleValue();
    return s;
}

Why is this not written as

public static <T extends Number> double sumOfList(List<T> list) {
    double s = 0.0;
    for (Number n : list)
        s += n.doubleValue();
    return s;
}

Am I missing something?

Jon Taylor
  • 7,865
  • 5
  • 30
  • 55

3 Answers3

3

Why make things more complicated than they need to be? The examples demonstrate the simplest thing that could possibly work – and these examples are not trying to illustrate generic methods.

Why would you not write this as:

<T> void printCollection( Collection<T> c ) {
    for(T o : c) {
        System.out.println(o);
    }
}

Because System.out.println() can accept objects, so nothing more-specific is needed.

Why is this not written as

public static <T extends Number> double sumOfList(List<T> list) {
    double s = 0.0;
    for (Number n : list)
        s += n.doubleValue();
    return s;
}

Again, because you don't need a different parameterization for every different T extends Number. A non-generic method which accepts a List<? extends Number> is sufficient.

Matt Ball
  • 354,903
  • 100
  • 647
  • 710
  • I think I may just be misunderstanding the difference between the two, or are they the same? What situation would I ever be in that cannot be solved using T rather than ?. I have a feeling I am completely missing the point of the wildcard. – Jon Taylor Feb 28 '13 at 01:14
  • 2
    @JonTaylor: There isn't really any situation that you couldn't solve with `T` instead of `?`, but the point is that `?` doesn't need a name and signifies that you really don't care what the type is. – Louis Wasserman Feb 28 '13 at 01:30
  • @LouisWasserman `Class.forName` returning a `Class>` might be an example of only a wildcard being appropriate. – Paul Bellora Feb 28 '13 at 02:28
3

It is true that if a method parameter type has a first level wildcard with an upper bound, it can be replaced by a type parameter.

Counter examples (wildcard can't be replaced by a type parameter)

    List<?> foo()  // wildcard in return type  

    void foo(List<List<?>> arg)   // deeper level of wildcard

    void foo(List<? super Number> arg)   // wildcard with lower bound

Now for cases that can be solved by either wildcard or type parameter

        void foo1(List<?> arg)

    <T> void foo2(List<T> arg)

It is generally considered that foo1() is more stylish than foo2(). It's probably a bit subjective. I personally think foo1() signature is easier to understand. And foo1() is overwhelmingly adopted in the industry so it's better to follow the convention.

foo1() also treats arg a little more abstractly, since you cannot easily do arg.add(something) in foo1(). Of course that can be easily worked around (i.e. pass arg to foo2()!). It is also a common practice that a public method looks like foo1(), which internally fowards to a private foo2().

There are also cases where a wildcard won't do and a type parameter is needed:

    <T> void foo(List<T> foo1, List<T> foo2);  // can't use 2 wildcards.

This discussion so far is about method signature. In other places, wildcards can be indispensable where type parameters cannot be introduced.

irreputable
  • 44,725
  • 9
  • 65
  • 93
  • +1 For mentioning that type parameters [can't have lower bounds](http://stackoverflow.com/questions/2800369/bounding-generics-with-super-keyword). – Paul Bellora Feb 28 '13 at 02:32
3

From Oracle:

One question that arises is: when should I use generic methods, and when should I use wildcard types? To understand the answer, let's examine a few methods from the Collection libraries.

interface Collection<E> {
     public boolean containsAll(Collection<?> c);
     public boolean addAll(Collection<? extends E> c);
 }

We could have used generic methods here instead:

interface Collection<E> {
     public <T> boolean containsAll(Collection<T> c);
     public <T extends E> boolean addAll(Collection<T> c);
     // Hey, type variables can have bounds too!
 }

However, in both containsAll and addAll, the type parameter T is used only once. The return type doesn't depend on the type parameter, nor does any other argument to the method (in this case, there simply is only one argument). This tells us that the type argument is being used for polymorphism; its only effect is to allow a variety of actual argument types to be used at different invocation sites. If that is the case, one should use wildcards. Wildcards are designed to support flexible subtyping, which is what we're trying to express here.

So for the first example it's because the operation doesn't depend on the type.

For the second, it's because it only depends on the Number class.

Stephen
  • 2,365
  • 17
  • 21