20

I have a method whose argument should be "a List of anything". The method will not modify the contents of the List. Is it more correct to define this method as

void foo(List<?> list) {
}

or

void foo(List<Object> list) {
}

and what exactly is the difference?

Dónal
  • 185,044
  • 174
  • 569
  • 824

6 Answers6

18

Short answer, using List<?> will allow you to accept something like List<String> while using List<Object> won't.

This is discussed in the official generics trail, here and here.

[...] here is a naive attempt at writing it using generics (and the new for loop syntax):

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

The problem is that this new version is much less useful than the old one. Whereas the old code could be called with any kind of collection as a parameter, the new code only takes Collection<Object>, which, as we've just demonstrated, is not a supertype of all kinds of collections!
So what is the supertype of all kinds of collections? It's written Collection<?> (pronounced "collection of unknown"), that is, a collection whose element type matches anything. It's called a wildcard type for obvious reasons. We can write:

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

and now, we can call it with any type of collection.

aioobe
  • 413,195
  • 112
  • 811
  • 826
5

The List<Object> has parameterized type Object which essentially means that you can add all objects in the list.

However, List<?> means that is a list of unknowns. As long as you're not going to add anything to the list, it's essentially the same as List<Object> but you will have to worry with circumstances as follows:

List<?> unknownList = new ArrayList<String>();
unknownList.add(new Object()); //Compilation error.

The ? (in this case) means that you can only add values of String or is subtype of String.

If you're just going to iterate through the list and retrieve values, List<?> and List<Object> is essentially the same.

More info here.

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

The two are quite different

void foo(List<?> list)

means you expect a list of something but you haven't specified what it is

void foo(List<Object> list)

Says you expect the list passed is a list of object, so if you try to pass a List it will not be accepted (as opposed to the first declaration)

A common mistake is to assume that List<String> is a subtype so to speak of List<Object> this is not the case even though String is a suptype of Object.

Dónal
  • 185,044
  • 174
  • 569
  • 824
hhafez
  • 38,949
  • 39
  • 113
  • 143
0

If you don't want to modify the list, than List<?> is more suitable.

This way you can pass e. g. List<String> and List<BigInteger> to your method.

DerMike
  • 15,594
  • 13
  • 50
  • 63
0

You need void foo(List<?> list), or else you won't be able, for example, to pass in a List<String>.

If you use void foo(List<Object> list), then you can only pass in List<Object>.

This is because, in Java, generics are not covariant: List<String> is not a subtype of List<Object>.

jqno
  • 15,133
  • 7
  • 57
  • 84
0

Section 3 and 4 of this tutorial should answer your question:

http://java.sun.com/j2se/1.5/pdf/generics-tutorial.pdf

Quoting from the tutorial:

In general, if Foo is a subtype (subclass or subinterface) of Bar, and G is some generic type declaration, it is not the case that G<Foo> is a subtype of G<Bar> ....

... Collection<Object>, which, as we’ve just demonstrated, is not a supertype of all kinds of collections! So what is the supertype of all kinds of collections? It’s written Collection<?> (pronounced “collection of unknown”) , that is, a collection whose element type matches anything.

However, under the strict assumption that the method foo will leave the collection unmodified, there should be no difference in implementation.

Community
  • 1
  • 1
CubaLibre
  • 1,675
  • 13
  • 22