Search code examples
javalistreferencecopydeep-copy

Java: deepcopy list entry without instancing a new list


I've got a little problem while doing my programming task. I want to read some lines from a file (no problem so far) and tokenize it. Every line has about 4 tokens and each of them should find a place in a list. In the end, every line should be in a list too.

A little example to clarify this:

File Content:

foo boo bar
bii buu baa

output:

[[foo, boo, bar], [bii, buu, baa]]

And heres the code I'm dealing with

String fileContent = fileloader(file.toString());
List<String> linesList = new ArrayList<String>();
String[] lines = fileContent.split("\n"); 
for(String line:lines){
  String[] splittedLine = line.split("\t");
  for(String words:splittedLine){
    linesList.add(words);
  }
  lexiconContent.add(linesList); 
  linesList.removeAll(linesList);
}

I guess there's a problem with the references, because the first iteration works well! But in the second iteration, it copies the actual second content also to the first (0) list position and so on.

Finally I got something like [[], [], [], []]


Solution

  • The problem is that, you have created only one list, and adding a reference to that list to your outer list, by modifying it on each iteration. So, the final modification done to that list will be reflected for all the references.

    You can solve this problem by creating a new linesList each time in the loop: -

    List<String> linesList = null;  // Don't initialize here
    String[] lines = fileContent.split("\n"); 
    
    for(String line:lines){
        String[] splittedLine = line.split("\t");
        linesList = new ArrayList<String>(); // Initialize a new list everytime.
    
        for(String words:splittedLine){
            linesList.add(words);
        }
        lexiconContent.add(linesList); 
    }
    

    And yes, you can also simplify your for loop to: -

    for(String line:lines){
        String[] splittedLine = line.split("\t");
        lexiconContent.add(new ArrayList<String>(Arrays.asList(splittedLine))); 
    }
    

    This way, you don't have to iterate over your array, and add individual elements to your List. In fact, you don't need an intermediate list at all.