2

Is there any difference between the following pieces of code?

public static <E> void printElements(List<E> list) {
    for (E elem : list) {
        System.out.println(elem);
    }
}

and

public static void printElements(List<?> list) {
    for (Object elem : list) {
        System.out.println(elem);
    }
}

If yes, can someone explain the difference and when to use what ?

raggy
  • 59
  • 1
  • 5
  • 2
    This has been asked so many times... why don't you search the site for it? – SJuan76 Dec 14 '13 at 20:09
  • 1
    Try invoking `list.add` and you'll notice the difference. – Marko Topolnik Dec 14 '13 at 20:11
  • Just to be fair, neither of the "duplicates" actually is one. OP is asking about a difference subtler than those questions. – Marko Topolnik Dec 14 '13 at 20:47
  • @MarkoTopolnik - Sort of. Effectively the OP is asking the wrong question - the answer to his question is "no" since he's only calling `toString()` which is defined in `Object` (which has little to do with the difference between `E` ans `?`). It would do the exact same thing without generics. – Brian Roach Dec 14 '13 at 21:04

2 Answers2

0

The first statement used a Bounded Type Paramater E, whereas the 2nd statement uses a Wildcard Parameter. The first statement is bounded as it "restrict the types that can be used as type arguments in a parameterized type". The ?, in your case, says that it's a list of some type, but we don't know what it is. It's unbounded type.

Buhake Sindi
  • 87,898
  • 29
  • 167
  • 228
0

There is a difference, although it's not intuitive. I recommend reading the java standard tutorial for more details.

Basically, the two are different and incompatible types. List<E> can store objects that extend, subclass, or actually are type E, but it's its own type. You cannot refer to a List<String> from a List<Object> reference, even though you can add a String to a List<Object>.

List<?> means that it's a list reference that can refer to any parameterized reference of it. A List<?> can refer to a List<String> or a List<Integer>. It's most useful when it's bounded by some interface or class. For example, the first method below (adapted from the java standard tutorial) will only take List<Number>, and not anything like List<Double> or List<Integer>.

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

But the following code using wildcards can take List<Double> or List<Integer>. It's more flexible.

public static double sumOfList(List<? extends Number> list) {
    double s = 0.0;
    for (Number n : list)
        s += n.doubleValue();
    return s;
}
Scott Jordan
  • 122
  • 1
  • 6
  • But ` double sumOfList(List list)` will take a list with any type parameter, and that is what OP is asking about. – Marko Topolnik Dec 14 '13 at 20:20
  • But then it is not typesafe. If you just say List, then you can pass it a List and you might get a runtime exception based on what your method does. But a List extends Number> ensures the parameterized type is something your method can work with. – rapidclock Oct 11 '16 at 18:53
  • This difference is very difficult for me to understand, why `List` does not take `Double`s and `Integer`s if they are subtypes? I implemented an example by my own, where `Bmw` is a subclass of `Vehicle` and the following `List list = new ArrayList<>()` can accept also `Bmw` types – karlihnos Jan 25 '19 at 10:31