I have created a List of Lists with a default size set.  Therefore, I am adding the data to the lists using the set method. 
My Code:
package test;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
public class Test2 {
public static void main(String args[]) {
    List<List<String>> keys = new ArrayList<>(Collections.nCopies(3, new ArrayList<>()));
    List<String> values = keys.get(2);
    values.add("Hello");
    values.add("One Two");
    keys.set(2, values);
    List<String> tempList = keys.get(1);
    tempList.add("Now adding at 1");
    keys.set(1, tempList);
    System.out.println("Position 1 " + keys.get(1).toString());
    System.out.println("Position 2 " + keys.get(2).toString());
}
}
My Output:
Position 1 [Hello, One Two, Now adding at 1]
Position 2 [Hello, One Two, Now adding at 1]
Why is it doing this? The first data get's appended onto the second as well? What am I doing wrong ?
List<List<String>> keys = new ArrayList<>(Collections.nCopies(3, new ArrayList<>()))
In this statement it's not creating three new instances of ArrayList<>. It creates one instance of it and creates a list with three references to the same instance. Hence each location in the list of lists is a reference to the same ArrayList instance.
The simplest thing you can do to get around this is to use a for loop:
for(int i = 0; i < numCopies; i++) {
    keys.add(new ArrayList<>());
}
An equivalent solution using Java 8's streaming API:
IntStream.range(0, n).mapToObj(i -> new ArrayList<String>()).forEach(keys::add);
Or you can create keys in one go like so:
List<List<String>> keys = IntStream.range(0, numCopies)
                                   .mapToObj(i -> new ArrayList<String>())
                                   .collect(Collectors.toList());
We use i -> new ArrayList<String>() instead of ArrayList<String>::new because there is an ArrayList<T> constructor that takes in a single integer argument for the initial capacity, which means that it ends up actually being new ArrayList<String>(0), new ArrayList<String>(1), and so on, which is not what we want.
A more elegant option is to use Stream.generate:
Stream.generate(ArrayList<String>::new).limit(n);
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With