1

I see how to pass an ArrayList by its value so that the called method doesn't modify the original Arraylist. Passing ArrayList as value only and not reference However, I'm trying to pass an ArrayList that itself contains other Arraylists; that is Arraylist of Arraylist.

public class Test {
public static void main(String[] args){
     ArrayList<ArrayList<Integer>> lists = new ArrayList<ArrayList<Integer>>();

     for(int j=0;j<2;j++){           
         ArrayList<Integer> list=new ArrayList<Integer>();           
         for(int i=5;i>0;i--){
             list.add(i);
         }
         lists.add(list);
     }

     System.out.println("Before");
     printLists(lists);

     processLists(lists);

     System.out.println("\nAfter");
     printLists(lists);     
}   
public static void processLists(ArrayList<ArrayList<Integer>> list){

    ArrayList<ArrayList<Integer>> myTrace=new ArrayList<ArrayList<Integer>>(list);
    //myTrace.addAll(list);     
    for(int j=0;j<myTrace.size();j++){ 
        myTrace.get(j).remove(myTrace.get(j).size()-1); //remove last element in the inner lists
    }       
    System.out.println("\nInside");     
    printLists(myTrace);
}

public static void printLists(ArrayList<ArrayList<Integer>> lists){     
    for(int i=0;i<lists.size();i++){
        for(int j=0;j<lists.get(i).size();j++){
            System.out.print(lists.get(i).get(j)+" ");
        }
        System.out.println();
    }
}   
}

Suppose the above code generates output as:

Before: 5 4 3 2 1 \n 5 4 3 2 1

Inside: 5 4 3 2 \n 5 4 3 2

After: 5 4 3 2 \n 5 4 3 2

Here, processLists method is changing the original contents of 'lists'. How to restrict this modification? I've tried with the solutions mentioned in the link. Though it works with single ArrayList, but not with ArrayList of ArrayList.

Community
  • 1
  • 1

2 Answers2

2

The article you link to says to make and pass a copy of the list, so that the original can't be changed. The same technique can be applied here, but you have to copy everything.

Scott Hunter
  • 48,888
  • 12
  • 60
  • 101
  • Thanks for your suggestion. ArrayList> myTrace=new ArrayList>(list); isn't it copying everything? myTrace.addAll(list); doesn't help either. – Tanzeem Bin Noor Nov 05 '14 at 02:14
  • What isn't being copied? – Carcigenicate Nov 05 '14 at 02:18
  • @TanzeemBinNoor The elements of the `ArrayList`'s are references to other `ArrayList`s. When you use that constructor, it will create a new `ArrayList` but the contents will be the *same* references as the original one. If you need copies of all those lists, you'll have to do it yourself, either in a loop or using Java 8 streams. Is that what you're looking for? – ajb Nov 05 '14 at 02:29
1

When you say

ArrayList<T> a = new ArrayList<T> (b);

it will create a new ArrayList with a copy of the data from b. However, although a new ArrayList is created, it does not copy the objects that the elements refer to. Thus, each element of a will refer to the same object as the corresponding element of b.

Thus, in particular:

ArrayList<ArrayList<Integer>> myTrace = new ArrayList<ArrayList<Integer>>(list);

only creates one new ArrayList. It does not make copies of all the ArrayList<Integer> elements. Thus, after the above, myTrace.get(0) == list.get(0) will be true because they are the same reference [if the lists aren't empty]. And if you do something that modifies an element, the modification will show up in both:

myTrace.get(n).set(x,y)

will also affect the ArrayList<Integer> referred to by list.get(n), because myTrace.get(n) and list.get(n) will return the same reference.

You'll need a loop to copy the arrays:

ArrayList<ArrayList<Integer>> myTrace = new ArrayList<ArrayList<Integer>>();
for (ArrayList<Integer> sublist : list) {
    myTrace.add(new ArrayList<Integer>(sublist));  // makes a copy of the sublist
}

or use a stream in Java 8:

ArrayList<ArrayList<Integer>> myTrace = new ArrayList<> (
    list.stream().map(ArrayList::new).collect(Collectors.toList()));
Louis Wasserman
  • 191,574
  • 25
  • 345
  • 413
ajb
  • 31,309
  • 3
  • 58
  • 84