42

Simply put, I have a method with an ArrayList parameter. In the method I modify the contents of the ArrayList for purposes relevant only to what is returned by the method. Therefore, I do not want the ArrayList which is being passed as the parameter to be affected at all (i.e. not passed as a reference).

Everything I have tried has failed to achieve the desired effect. What do I need to do so that I can make use of a copy of the ArrayList within the method only, but not have it change the actual variable?

fvgs
  • 21,412
  • 9
  • 33
  • 48
  • You could pass [`Collections#unmodifiable(yourList)`](http://docs.oracle.com/javase/7/docs/api/java/util/Collections.html#unmodifiableList(java.util.List)) in order to send an unmodifiable copy of your list. – Luiggi Mendoza Apr 03 '13 at 04:05
  • 1
    You could also create a new copy of the `ArrayList` in the method that is modifying it. While it won't effect the first `ArrayList`, any objects you change within will still be changed... – MadProgrammer Apr 03 '13 at 04:06
  • Are you modifying the list only? Or also what is inside of the list? – Daniel Williams Apr 03 '13 at 04:12
  • Does anyone know if System.arraycopy will just copy the references or clone the objects in the array as well?? I looked for the source and ran into an end because it's a native method.. – Thihara Apr 03 '13 at 04:48

8 Answers8

56

Even if you had a way to pass the array list as a copy and not by reference it would have been only a shallow copy.

I would do something like:

void foo(final ArrayList list) {

    ArrayList listCopy = new ArrayList(list);
    // Rest of the code

}

And just work on the copied list.

Avi
  • 21,182
  • 26
  • 82
  • 121
  • 1
    That will do it. I originally tried setting the internal list equal to the parameter, but that didn't work. This is by far the simplest solution. – fvgs Apr 03 '13 at 04:10
  • 1
    Indeed, there is a required waiting period before being able to accept an answer. – fvgs Apr 03 '13 at 04:22
  • 1
    It doesn't work when you have list of object! by changing objects as they are not final the list has changed too. – Parisa Baastani May 06 '20 at 06:58
22

You can create a copy of the ArrayList using ArrayList's copy constructor:

ArrayList copy = new ArrayList(original);

But if the elements of the list are also objects, then you must be aware that modifying a member of the copy will also modify that member in the original.

bchociej
  • 1,369
  • 9
  • 12
  • 3
    how would you make it so that modifying a member of the copy won't modify the original list? – Arjun Apr 28 '19 at 18:30
  • To answer @Arjun, I think for the scenario you mentioned, it would require a deep copy, instead of a shallow copy – Ghos3t Dec 06 '22 at 05:36
6

You could pass Collections#unmodifiableList(yourList) in order to send an unmodifiable copy of your list. By the way, your List<Whatever> is passed by value since Java always pass by value, note that in foo(List<Whatever> list) method you can not modify the list value but you can modify its contents.

public class MyClass {

    List<Whatever> list = new ArrayList<Whatever>();

    public void bar() {
        //filling list...
        foo(Collections.unmodifiableList(list));
    }

    public void foo(List<Whatever> list) {
        //do what you want with list except modifying it...
    }
}
Community
  • 1
  • 1
Luiggi Mendoza
  • 85,076
  • 16
  • 154
  • 332
3

You could use the .clone method or a CopyOnWriteArrayList to make a copy, thereby not impacting the original.

helion3
  • 34,737
  • 15
  • 57
  • 100
3

Try this in you method :

void method(List<Integer> list) {
        List copyList =  new ArrayList<Integer>();
        copyList.addAll(list); // This will create a copy of all the emlements of your original list
    }
Ankur Shanbhag
  • 7,746
  • 2
  • 28
  • 38
3

I'm not sure on why, even after new ArrayList<MyObj>(old) the object was still changing reference in places it wasn't supposed to. So I had to instantiate a new copy of the objects inside.

I made a copy constructor like the one on the ArrayList and did like

 newArray = new ArrayList<MyObj>();
        for (int i = 0; i < oldArray.size(); i++) {
            newArray.add(new MyObj(ondArray.get(i)));
        }

Just hope to help someone else if the answer from Avi is not enough in your case, like mine with a code too messy to even understand =P

Caio Faustino
  • 165
  • 1
  • 15
1

Just clone it.

public ArrayList cloneArrayList(ArrayList lst){
    ArrayList list = new ArrayList();
    for (int i=0; i<lst.size(); i++){
        list.add(lst.get(i));
    }
    return list;
}

Add suggested in the comments, you can also use

ArrayList copy = new ArrayList(original);

and also

ArrayList copy = new ArrayList();
copy.addAll(original);
Sri Harsha Chilakapati
  • 11,744
  • 6
  • 50
  • 91
0

On the lines of the existing answers but using the ArrayList API. You can use subList(fromIndex, toIndex) method. It explicitly creates a view of the list with only desired elements (of course, in sequence). Here, even if you modify the view with add/remove etc operations, it won't change the original list. It saves you from explicitly creating a copy.

Something like this:

public void recursiveMethod(List<Integer> list) {
    if(base)
         return;
    recursiveCall(list);

    // following will just create a tail list but will not actually modify the list
    recursiveCall(list.subList(1, list.size());
}
Parth
  • 51
  • 1
  • 5