tags:

views:

453

answers:

5

Hi!

I'd like to use a generic list, but the initialization method only returns a List. The following code works well:

List tmpColumnList = aMethodToInitializeTheColumnList();
tmpColumnList.add("ANICELITTLECOLUMN");

Java accuses that I'm using a raw type and I should paramerize the list. So I added the question mark parameterize this list.

List<?> tmpColumnList = aMethodToInitializeTheColumnList();
tmpColumnList.add("ANICELITTLECOLUMN");

Problem is: Now the add(..) method doesn't work anymore.
I cannot assure that the list only contains Strings as aMethodToInitializeTheColumnList() is not implemented in my code.

What is my mistake?

Thanks!

+8  A: 

You probably want to use List<String> - that's how Generics are intended to be used, i.e. add information about what kind of objects will be in a collection. If you're actually going to have a List containing mixed types (which is usually a sign of bad design) use List<Object>

For more information about the use of wildcards, look at the Generics Tutorial. But they're really only relevant when defining your own generic classes, or methods with generic parameters.

Michael Borgwardt
Thanks for the hint. I cannot assure that this list only contains strings.
furtelwart
In that case you could use List<Object>, or maybe something else, dependent on what you know the list will contain (for example List<Serializable>)
Fortega
In the Generics Tutorial there's the solution, see my own answer. I will consider accepting your answer because you gave me the hint.
furtelwart
+7  A: 

If you use <?>, you mean you aren't going to use the parametrized type anywhere. Either go to the specific type (in your case it seems List<String>) or to the very generic List<Object>

Romain
I don't want to specify it, but why is the normal `add` method failing then?
furtelwart
Well, the compiler enforces semantic consistency. You say you won't use the parametrized type, so it doesn't let you. The `add` method expects a parameter which type is the generic parameter, so you're not allowed to use it if you don't specify one.
Romain
Because the type is *unknown*. The compile has no possibility to determine whether a `String` would be appropriate so you’re not allowed to add a `String` to the list. (Actually, you’re not allowed to add anything to that list, except for `null`.)
Bombe
+5  A: 

From the Generics Tutorial. Thanks to Michael's answer!

It isn't safe to add arbitrary objects to it however:

Collection<?> c = new ArrayList<String>();
c.add(new Object()); // Compile time error

Since we don't know what the element type of c stands for, we cannot add objects to it. The add() method takes arguments of type E, the element type of the collection. When the actual type parameter is ?, it stands for some unknown type. Any parameter we pass to add would have to be a subtype of this unknown type. Since we don't know what type that is, we cannot pass anything in. The sole exception is null, which is a member of every type.

furtelwart
A: 

The List<?> means that the list is (or could be) typed, but the type is unknown**. So adding something to it could be wrong**, if you happen to be outside of the type. Because it is unknown, you are warned.

You can use List<Object>, which means a list that can contain any type.

KLE
I'm not only warned, code fails at compile time!
furtelwart
@furtelwart True, my wording was poorly chosen :-). But the point of this compile-time error is that the compiler signals that the code is potentially wrong. BTW, it is the whole point of the Generics subsystem as implemented, to search code safety at compile-time, and add casts at runtime...
KLE
+2  A: 

Another option in this case would be to declare your list to be a

List<? super String>

since this models exactly what you know about it. You say that you don't know exactly what its type bounds are, but from your second line it's fair to assume that it must be able to contain strings.

This compiles and to my mind, is a little nicer than a List<Object> as it encodes your uncertainty as to what can actually go in the list. Basically, you can only add Strings to it, but when you call get() the returned element could be anything (and Java will correctly infer this type to be Object).

In practical terms, the only difference between this and List<Object> is that the latter would allow tmpColumnList.add(3) or tmpColumnList.add(new Thread()) etc. I much prefer the semantics it carries as well as the practicality.

Andrzej Doyle