Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Java generics : wildcards

Tags:

java

generics

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?

like image 281
Jon Taylor Avatar asked Feb 28 '13 01:02

Jon Taylor


People also ask

What are wildcards in generics in Java?

The question mark (?) is known as the wildcard in generic programming. It represents an unknown type. The wildcard can be used in a variety of situations such as the type of a parameter, field, or local variable; sometimes as a return type.

What is the difference between generics and wildcards in Java?

Wildcards are nothing but the question mark(?) that you use in the Java Generics. We can use the Java Wildcard as a local variable, parameter, field or as a return type. But, when the generic class is instantiated or when a generic method is called, we can't use wildcards.

Why wildcards are used in generics?

In generic code, the question mark (?), called the wildcard, represents an unknown type. The wildcard can be used in a variety of situations: as the type of a parameter, field, or local variable; sometimes as a return type (though it is better programming practice to be more specific).

What is the difference between bounded and unbounded wildcards in Java generics?

both bounded and unbounded wildcards provide a lot of flexibility on API design especially because Generics is not covariant and List<String> can not be used in place of List<Object>. Bounded wildcards allow you to write methods that can operate on Collection of Type as well as Collection of Type subclasses.


2 Answers

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.

like image 113
Raufio Avatar answered Oct 12 '22 15:10

Raufio


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.

like image 42
Matt Ball Avatar answered Oct 12 '22 15:10

Matt Ball