0

The following code searches a file given an user input, and if there's a match, the line on the match is added to an ArrayList.

I seem to have a problem with the ArrayList, as I'm getting java.util.ConcurrentModificationException on ArrayList.

This question has been answered before but I still don't understand what issue in my code is causing this problem.

Any help would be appreciated.

import java.io.File;
import java.io.FileNotFoundException;
import java.util.ArrayList;
import java.util.ListIterator;
import java.util.Scanner;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.JOptionPane;


public class Test {

    public static void main(String[] args)
    {
        String givenAccnt;

        Scanner scan = new Scanner(System.in);
        System.out.println("Enter an account...");
        givenAccnt = scan.nextLine();
        findPasswords(givenAccnt);
    } 

    private static void findPasswords(String userInput)
    {
        File file = new File("C:\\Users\\Nuno\\Documents\\my_passwords.txt");   //file to search
        Scanner scan = new Scanner(System.in);                                  //Scanner object to get user input
        String accntToken;                                                      //first string token of a line, i.e. "account"
        String getLine;                                                         //this is the line that contains the password the user is looking for. There may be +1 lines thus I have to return them all.*** must use ArrayList of strings (lines of strings) instead of Array
        ArrayList<String> collectedLines = new ArrayList<>();                   //any matched line(s) is collected to an ArrayList of strings (lines)
        ListIterator<String> outputMatches =  collectedLines.listIterator();    //iterator for ArrayList... used to iterate and display collected lines to output window
        String nextOutput;                                                      //line(s) that was collected from ArrayList
        boolean isFound = false;
        int i;                                                                  //delineator... finds index of 1st space " " on that line  (or try ' '), so we can get to the 1st token of a line i.e. "account"
        int v = 0;                                                              //counter... everytime an input is matched to a line, the line is collected to ArrayList... increas    e v... the pane will also display number of accounts found (i.e. v)

        try
        {   
            Scanner scanFile = new Scanner(file);                               //Scanner object to scan file
            while(scanFile.hasNextLine())                                       //Scanner scans file... until end of file
            {
                getLine = scanFile.nextLine();                                  //gets a line
                i = getLine.indexOf(" ");                                       //get index of substring (account) token
                accntToken = getLine.substring(0, i);                           //gets the account (1st string token in the line, after " ")                        
                if(userInput.equalsIgnoreCase(accntToken))                      //if given input account equals the account on the line 
                {     
                    collectedLines.add(getLine);                                //append the line to the ArrayList collectedLines
                    isFound = true;                                             //flag
                    v++;                              //increment number of matches found
                }
            }
            System.out.println(v + " matches were found and added to the ArrayList!"); //tests to see search algorithm is working
            while(outputMatches.hasNext())                                      //loop iterates the ArrayList to write collectedLines to the dialog
            {
                nextOutput = (String)outputMatches.next();                      //get line(s) from the ArrayList

                if(!isFound)
                {
                } else 
                    {
                        System.out.println("Passwords found: " +nextOutput);
                        outputMatches.remove();
                    }
            }                  
        }catch (FileNotFoundException ex) 
        {
            Logger.getLogger(PassLock_Main.class.getName()).log(Level.SEVERE, null, ex);
            System.out.println("Error processing file!");
        }
    }
}
codEinstein
  • 9
  • 1
  • 6
  • it seems you are trying to manipulate the same arraylist at the same time from two different threads. can't do that – ja08prat Aug 07 '17 at 18:39
  • @ja08prat how do I fix that? – codEinstein Aug 07 '17 at 18:41
  • @codEinstein set a breakpoint at the very beginning and step through line by line until you find the issue, can't answer for sure by just looking at it – ja08prat Aug 07 '17 at 18:43
  • @ja08prat You don't need multiple threads to get a `ConcurrentModificationException` (as evidenced by the code in question which has a single thread). – Kayaman Aug 07 '17 at 18:49
  • @Kayaman true, I was just spitballing, if i was more confident that that was the issue i wouldve posted it as an answer – ja08prat Aug 07 '17 at 18:55

1 Answers1

-1

The problem arises when you do the following:

  1. Obtain an iterator (or list iterator) from an ArrayList
  2. Modify that ArrayList (in your case, you add() to it)
  3. Use iterator from item 1

You need to either avoid modifying the list you are iterating over, or use some collection implementation that supports concurrent modification+iteration.

For example, you could try using CopyOnWriteArrayList instead, but be aware that it makes a copy of the list each time you modify it.

Update: in your case you just need to get iterator after you modify the collection. Try moving

ListIterator<String> outputMatches =  collectedLines.listIterator();

after the following line:

System.out.println(v + " matches were found and added to the ArrayList!");
Roman Puchkovskiy
  • 11,415
  • 5
  • 36
  • 72
  • Great! That works, now I see why... I am just not too familiar using this type of container. Thanks Roman – codEinstein Aug 07 '17 at 18:54
  • 2
    @codEinstein As explained in the duplicate, you can use a `ListIterator` and its `add()` and `remove()` methods to modify the list while iterating through it. – Kayaman Aug 07 '17 at 18:55
  • @codEinstein I'm glad I could help you. Please don't forget to accept the answer. – Roman Puchkovskiy Aug 07 '17 at 18:57
  • Roman, can you show me how to "accept the answer"? I'm not very familiar with StackOverflow. I tried click the ^ to vote up but it says it wont count 'cause I have less than 15 reputations – codEinstein Aug 07 '17 at 19:33
  • Here is the post that explains how accepting an answer works: https://meta.stackexchange.com/questions/5234/how-does-accepting-an-answer-work – Roman Puchkovskiy Aug 08 '17 at 05:44