marcolopes
marcolopes

Reputation: 9287

Java addAll(collection) vs new ArrayList(collection)

Why do i get different behaviors with:

  1. Collection col2 = new ArrayList(col);

  2. Collection col2 = new ArrayList();
    col2.addAll(col)

I'm working with viewers, and the code is complex, and i'm trying to explain the "root" of the problem. Another interesting fact is the next one...

//IF i use this code i have the correct behavior in my app:
public void updateCollection(Collection<Object> col) {
    this.objectCollection.clear();
    this.objectCollection.addAll(col);
}

//IF i use this code i have unexpected behavior in my app:
public void updateCollection(Collection<Object> col) {
    this.objectCollection=new ArrayList(col);
}

Upvotes: 18

Views: 21576

Answers (3)

Carl Manaster
Carl Manaster

Reputation: 40336

This code works:

public void updateCollection(Collection<Object> col) {
    this.objectCollection.clear();
    this.objectCollection.addAll(col);
}

But this introduces problems:

public void updateCollection(Collection<Object> col) {
    this.objectCollection = new ArrayList(col);
}

I suspect that this variation on your first method would introduce identical problems:

public void updateCollection(Collection<Object> col) {
    this.objectCollection = new ArrayList();
    this.objectCollection.clear();
    this.objectCollection.addAll(col);
}

Why? Evidently you have another reference to objectCollection in use somewhere. Somewhere in your code, another object is saying (for instance):

myCopyOfObjectCollection = theOtherObject.objectCollection;

If you're using a getter, that doesn't change the underlying behavior - you are still keeping another reference around.

So if on initial assignment, say, the collection contained {1, 2, 3}, you start out with:

  • this.objectCollection: {1, 2, 3}
  • that.copyOfObjectCollection: {1, 2, 3}

When you assign a new ArrayList to this.objectCollection, and populate it with, say, {4, 5, 6}, you get this:

  • this.objectCollection: {4, 5, 6}
  • that.copyOfObjectCollection: {1, 2, 3}

So that is still pointing to the original ArrayList.

Upvotes: 17

zg_spring
zg_spring

Reputation: 359

    public List getAdminImIdsWithValidShortNames(){
    return adminImIdsWithValidShortNames;
}

public void setAdminImIdsWithValidShortNames(List adminImIdsWithValidShortNames){
    this.adminImIdsWithValidShortNames=adminImIdsWithValidShortNames;
}

I think, easy is beautiful, just generator setter/getter method is a good habit. if you first clear, then addAll, the list need to clear all elements of list, then addAll will be extra backing array expansion operation, that's not science.

just replacement, this variable will be point to new List, the old list will be auto-GC.

Upvotes: 0

Neeme Praks
Neeme Praks

Reputation: 9150

Collection col2 = new ArrayList(col);

will create a new ArrayList with size col.size() (+10%) and copy all elements from col into that array.

Collection col2 = new ArrayList();

will create a new ArrayList with initial size of 10 (at least in Sun implementation).

col2.addAll(col);

will copy all elements from col into the end of the col2 ArrayList, enlarging the backing array size, if needed.

So, depending on your col collection size, the behavior will be a bit different, but not too much.

It is preferable to use the first option - that will avoid at least one extra backing array expansion operation.

Upvotes: 7

Related Questions