views:

322

answers:

5

What is the correct type of argument to the addAll(..) method in Java collections? If I do something like this:

List<? extends Map<String, Object[]>> currentList = new ArrayList<Map<String, Object[]>>();
Collection<HashMap<String, Object[]>> addAll = new ArrayList<HashMap<String, Object[]>>();
// add some hashmaps to the list..
currentList.addAll(addAll); 

I understand I need to initialize both variables. However, I get a compilation error (from eclipse):

Multiple markers at this line
    - The method addAll(Collection<? extends capture#1-of ? extends Map<String,Object[]>>) in the type List<capture#1-of ? extends Map<String,Object[]>> is not applicable for the arguments (List<capture#2-of ? extends 
     Map<String,Object[]>>)
    - The method addAll(Collection<? extends capture#1-of ? extends Map<String,Object[]>>) in the type List<capture#1-of ? extends Map<String,Object[]>> is not applicable for the arguments 
     (Collection<HashMap<String,Object[]>>)

what am I doing wrong?

A: 

Your question basically boils down to this:

public static <T extends Collection<?>> void foo(T t) {
T x = null;
x.addAll(t);
}

This will fail with essentially the same error as you describe. Try something along these lines to fix it.

public static <T extends Collection<Y>, Y> void foo(T t) {
T x = null;
x.addAll(t);
}

Alternatively, in your example above you could change

List<? extends Map<String, Object[]>> currentList;

to

List<Map<String, Object[]>> currentList;

Generics gets hairy pretty quickly if you try to start passing around unspecified types.

Jherico
A: 

You cannot call any method with generic attributes on such a list. Basically, what ? extends Foo says is "something that extends Foo", but you don't know what that something is. When that type is returned, you can say that returned value is Foo or some subtype. But for any given value you cannot that it matches ? extends Foo generic.

In short: you need to change currentList declaration or cast it to List (without generics) and live with a warning or (if you know what you are doing) suppress it.

doublep
+3  A: 

Replace extends by super.

The addAll() itself takes an ? extends T argument and that won't work when T is ? extends Map<K, V>. With the change it will become effectively ? extends ? super Map<K, V>.

But still, better is just to remove that ? extends (or ? super). It's superfluous in this particular case. Just use List<Map<String, Object[]>>. The addAll() will then effectively take ? extends Map<String, Object[]>>.

BalusC
Sorry for the delete and undelete, but I got confused by other answers so that I first need time to start my IDE and verify it before I got voted down ;)
BalusC
why even declare the `currentList` as `List<? super Map<String, Object[]>>`, and not just `List<Map<String, Object[]>>` ? this part of his code seems unnecessary to me.
matt b
@matt: That's also what I said in last paragraph :)
BalusC
A: 

just remember:

for <? extends ...>, you cannot put things (except null) into it

for <? super ...>, you cannot get things (except Object) out of it

newacct
+2  A: 

You can only insert instances of T into a List<T>.

The type List<? extends Map<X,Y>> stands for a list of an unknown type T which extends Map<X,Y>. For instance, it could stand for a List<LinkedHashMap<X,Y>>. Obviously, you may not insert an ordinary HashMap<X,Y> into such a list.

You probably want:

List<Map<String, Object[]>> currentList;

Or if you want to be really flexible you could do:

List<? super Map<String, Object[]>> currentList;

Which would allow you to do crazy things like:

currentList = new ArrayList<Map<? super String, ? extends Object[]>>();

You might also wish to read Angelika Langer's Generics FAQ, particularly the section about wildcards.

meriton