2

Are there any implicit differences between these two types of generic functions, or does the compiler treat them as the same?

public static <T extends Number> void test(List<T> list) {
    for (T t : list) {

    }
}

Versus

public static void test(List<? extends Number> list) {
    for (Number t : list) {

    }
}

Also, are there any benefit of using one over the other?

Bloc97
  • 274
  • 1
  • 13
  • The first one is a [generic method](https://docs.oracle.com/javase/tutorial/extra/generics/methods.html) while the second one is not. – QBrute Jun 30 '17 at 14:09
  • Functionally identical. The benefit of the second is you don't have the redundant type variable. I think they are treated differently by the compiler though, because of the difference in the number of type variables. – Andy Turner Jun 30 '17 at 14:10
  • Also a good read: [When to use generic methods and when to use wild card?](https://stackoverflow.com/questions/18176594/when-to-use-generic-methods-and-when-to-use-wild-card) – azurefrog Jun 30 '17 at 14:17
  • 1
    Closed before I could answer, but use `javap -c` to examine bytecode -- you'll see that both compile to the same bytecode. – slim Jun 30 '17 at 14:22

1 Answers1

3

These are functionally identical. So the second one should be preferred as shorter :

public static void test(List<? extends Number> list) {
    for (Number t : list) {

    }
}

The first one makes more sense when you want to return something relying on the declared type.

For example this code is more flexible concerning the return type:

public static <T extends Number> List<T> test(List<T> list) {
    for (T t : list) {

    }
    return list;
}

you can invoke it in this way :

List<Integer> integers = ...;
integers = test(integers);

because with a declared parameterized type used in the return type, the compiler infers the return type from the type of the variable which you assign the result of the method (that has to be compatible of course with the type constraint).

But as List<Integer> is a subtype of List<? extends Number> you can also use this way :

List<Integer> integers = ...;
List<? extends Number> numbers = test(integers);

Without declaring a parameterized type in the return type of the List, you can only assign the result of the method to a type declared with List<? extends Number> :

public static List<? extends Number> test(List<? extends Number> list) {
    for (Number t : list) {

    }
    return list;
}

So, only this way is valid :

List<Integer> integers = ...;
List<? extends Number> numbers = test(integers);
davidxxx
  • 125,838
  • 23
  • 214
  • 215