8

When is it recommended to do:

public <E> boolean hasPropertyX(List<E extends User> alist);

versus

public boolean hasPropertyX(List<? extends User> alist);

It would appear they both work just as well.

wrongusername
  • 18,564
  • 40
  • 130
  • 214
  • 1
    `This reflects the fact that the type parameter is not being used to express any kind of interdependency between the type(s) of the argument(s), the return type and/or throws type. In the absence of such interdependency, generic methods are considered bad style, and wildcards are preferred.` Java Language Specification 8 §4.5.1-2. Basically, if there is a dependency on the type beyond the method, the first should be used. Otherwise, use the second. – Obicere Mar 21 '15 at 03:48

5 Answers5

4

Without typed return value, the only difference I can think of is explicit typing of the first way of declaration during method call.

So for example you are using it inside typed class C<K extends String>

List<V extends String> input = ...;
boolean var = obj.hasProperty<K>(input);

will raise the compiler error. But why would any one want to do so...

Nice question even if most likely the answer is both are the same.

Zielu
  • 8,312
  • 4
  • 28
  • 41
2

Explicitly naming the generic type as E and not ? has these uses (as far as I can think of):

0) To tie the return type to some part of the argument type - for example:

public <E> E getSomeElement(List<E> lst) { ... }
// ^ If we don't name the argument type as having E,
// then we can't specify the return type as being E

1) To tie some part of the argument type to some part of the enclosing type:

class Storage<E> {
    E item;
    public void replace(Storage<E> st) { item = st.item; }
    // ^ This wouldn't work if we wrote Storage<?> instead
}

2) To tie some combination of the argument types, return type, and enclosing type (see #0 and #1).

We can get away with the anonymous type name ? if we don't care about the actual type. Here is a basic example:

boolean allEqual(List<?> lst, Object y) {
    for (Object x : lst) {  // Any reference can be stored as Object
        if (!y.equals(x))  // equals takes an Object
            return false;
    }
    return true;
}
// ^ We could also rewrite this example with List<E> and "E x".

Another example:

int intSum(List<? extends Number> lst) {
    int sum = 0;
    for (Number x : lst)  // We only care that the list element is a Number
        sum += x.intValue();
    return sum;
}
// ^ We could also rewrite with List<E extends Number> and "E x".

Alternate reading: http://docs.oracle.com/javase/tutorial/extra/generics/wildcards.html

Nayuki
  • 17,911
  • 6
  • 53
  • 80
2

I suppose in that particular example they both do work effectively the same way in terms of type checking. However, if you extend the generic type to require a base or superclass of some class it can be useful. e.g.

public <E extends User> boolean hasPropertyX(List<E> alist);

This at least enforces that you're receiving some subclass of User.

EDIT

You can use a wildcard to achieve the same thing:

public boolean hasPropertyX(List<? extends User> alist);

But this won't work if, for example, you want to use the generic for multiple parameters:

public <E extends Automobile> void crashAutos(List<E> list1, List<E> list2);

This enforces the generic type on both arguments, whereas the following code does not force the two lists to contain the same type:

public void crashAutos(List<? extends Automobile> list1, List<? extends Automobile> list2);

I could call that method with two different subclasses of the Automobile class:

List<Car> cars = ...
List<Truck> trucks = ...
crashAutos(cars, trucks);

Whereas using generics enforces the same type for both arguments.

kuujo
  • 7,785
  • 1
  • 26
  • 21
  • 1
    You can do the same with the wildcard though, at least in the `drawAll` example here: http://docs.oracle.com/javase/tutorial/extra/generics/wildcards.html – wrongusername Mar 21 '15 at 03:28
  • Good point. I tend to favor the generic over the wildcard as Java tends to complain about it less (unchecked cast warnings). – kuujo Mar 21 '15 at 03:36
2

Differences between generics and wildcard unknown types:

  • Enforcing a relationship on the types of method arguments (Use Generics)
  • Supporting multiple bounds (Use Generics)
  • Supporting both upper and lower bounds (Use Wildcard)

The related question:

When to use generic methods and when to use wild-card?

Community
  • 1
  • 1
1

Use ? extends when you only need to retrieve from the List:

User getElement(List<? extends User> list, int i) {
    return list.get(i);
}

Use ? super when you only need to add to the List:

void addElement(List<? super User> list, User u) {
    list.add(u);
}

Use E extends when you both need to retrieve and add:

<E extends User> void swapElements(List<E> list, int i, int j) {
    E temp = list.get(i);
    list.set(i, list.get(j));
    list.set(j, temp);
}
  • ? extends User: We don't know the exact type of the List, but we can retrieve a User from it.
  • ? super User: We don't know the exact type of the List, but we can put a User in it.
  • E extends User: We don't necessarily know the exact type of the List but it conforms to constraints such that:
    • We give its actual type the name E.
    • We know E is at least User.
    • We can both retrieve E from the List and put E in the List.

See also:

Community
  • 1
  • 1
Radiodef
  • 37,180
  • 14
  • 90
  • 125
  • This should be the accepted answer. It is the only one that really answers the question in a correct way. The others all read like "I don't know but this *may* happen or it may not who really knows?". – Adowrath Jan 14 '17 at 18:30