迭代时如何仅在 ArrayList 中避免 ConcurrentModificationException?

白边0013

澄清一下 - 我不想从 ArrayList 中删除任何内容。因此,我发现的所有答案中有 90% 实际上并不适用。我在这里或其他地方找不到任何对我有很大帮助的东西!

我正在编写一个 Java 应用程序来玩 Hangman,对手(计算机)本质上是在作弊,从某种意义上说,它不“选择”一个词,它有一组词并决定玩家的猜测是正确还是不正确,这取决于哪个词组更难猜测。

简而言之,我的问题是这样的:

我有一个 ArrayList, masterList,其中有一组单词、一本字典(如果你愿意的话)以及各种方法遍历它以执行各种任务。我的代码是单线程的,其中一个方法ConcurrentModificationException在第二次迭代中尝试访问 ArrayList 中的下一个对象时抛出 a 但是,我找不到在迭代过程中实际更改 ArrayList 的任何内容。

import java.io.*;
import java.util.*;

public class Main {
    private ArrayList<String> masterList;
    private ArrayList<String> contains;
    private ArrayList<String> doesNotContain;
    private HashMap<Integer, ArrayList<String>> wordLengthList;
    private HashMap<Integer, ArrayList<String>> difficultyList;
    private int guesses = 10;
    private Scanner sc;
    private FileReader fr;
    private BufferedReader br;
    private String guessString;
    private char guessChar;
    private static final String DICTIONARY = "smalldictionary.txt";
    private String wordLengthString;
    private int wordLengthInt = 0;


    public Main(){

        masterList = new ArrayList<String>();
        contains = new ArrayList<String>();
        doesNotContain= new ArrayList<String>();
        wordLengthList = new HashMap<Integer, ArrayList<String>>();
        difficultyList = new HashMap<Integer, ArrayList<String>>();

        sc = new Scanner(System.in);

        importTestDictionary(); //does not use masterList

        br = new BufferedReader(fr);

        importWords(); //Adds to masterList. Both readers closed when finished.

        catalogLengths(); //Iterates through masterList - does not change it.


        do{
            setWordLength(); //does not use masterList
        }while(!(validateLengthInput(wordLengthString))); //validation will change the set of masterList if valid.

        //Main loop of game:
        while(guesses > 0){

            do{
                getUserInput();
            }while(!(validateInput(guessString))); 

            splitFamilies();//will change set of masterList when larger group is found. Changes occur AFTER where Exception is thrown
            printDifficultyList();
        }
    }

    private void importWords(){ //Adds to masterList. Both readers closed when finished.


        try{
            while(br.readLine() != null){
                line = br.readLine();
                masterList.add(line); 
            }
            br.close();
            fr.close();
        }catch(IOException e){
            System.err.println("An unexpected IO exception occurred. Check permissions of file!");
        }
    }


    private boolean validateLengthInput(String length){ //validation will change the set of masterList if valid.
        try{
            wordLengthInt = Integer.parseInt(length);
            if(!(wordLengthList.containsKey(wordLengthInt))){
                System.out.println("There are no words in the dictionary with this length.\n");
                return false;
            }
        }catch(NumberFormatException e){
            System.out.println("You must enter a number.\n");
            return false;
        }
        masterList = wordLengthList.get(wordLengthInt);
        return true;

    }


    private void splitFamilies(){ //will change set of masterList when larger group is found. Changes occur AFTER where Exception is thrown
        Iterator<String> it = masterList.iterator();
        int tempCount = 0;
        while(it.hasNext()){ 
            tempCount++;
            System.out.println("tempCount: " + tempCount);
            String i = it.next(); //Still throwing ConcurrentModification Exception
            if(i.contains(guessString)){
                contains.add(i);
            }else{
                doesNotContain.add(i);
            }
        }

        if(contains.size() > doesNotContain.size()){
            masterList = contains;
            correctGuess(); //does not use masterList
            profileWords();

        }
        else if(doesNotContain.size() > contains.size()){
            masterList = doesNotContain;
            incorrectGuess(); //does not use masterList
        }
        else{
            masterList = doesNotContain;
            incorrectGuess(); //does not use masterList
        }

    }



    private void printMasterList(){ //iterates through masterList - does not change it.
            for(String i : masterList){
                System.out.println(i);
            }
        }


    private void catalogLengths(){ //Iterates through masterList - does not change it.
        for(String i : masterList){
            if(i.length() != 0){
                if(!(wordLengthList.containsKey(i.length()))){
                    wordLengthList.put(i.length(), new ArrayList<String>());
                }
                wordLengthList.get(i.length()).add(i);
            }
        }
    }
}

抛出异常的行在代码中标记在上面。任何使用的masterList方法也被标记,任何不使用它的方法都包含在内,没有反对意见。

我确实阅读了一些答案,其中一些建议使用Iterator以避免异常。这是在上面的splitFamilies(). 原始代码如下:

private void splitFamilies(){ //will change set of masterList when larger group is found. Changes occur AFTER where Exception is thrown
        int tempCount = 0;
        for(String i : masterList){  //This line throws ConcurrentModificationException
            tempCount++;
            System.out.println("tempCount: " + tempCount);
            if(i.contains(guessString)){
                contains.add(i);
            }else{
                doesNotContain.add(i);
            }
        }
....continue as before

tempCount总是2在抛出异常时。

也许我错过了一些非常简单的东西,但我已经尝试过跟踪它,但无法找出为什么我会收到此异常!

我试图从代码中删除所有不相关的内容,但是如果有人真的想查看完整内容,我想我可以在问题中转储我所有的代码!

纪尧姆 F.

问题来自这样masterList一个事实,即对第一次拆分containsdoesNotContain之后的引用当您对 进行迭代时masterList,您实际上也在同一时间对另一个列表进行迭代。

因此,然后您将项目添加到列表中:

if(i.contains(guessString)){
    contains.add(i);
}else{
    doesNotContain.add(i);
}

在这里,您不仅可以向containsor添加项目doesNotContain,还可以向 潜在添加项目masterList,从而导致conccurentException.


要解决您的问题,只需复制您的列表,而不是:masterList = contains;
复制:masterList = new ArrayList<>(contains);

对于doesNotContains.


想到的另一个解决方案是重置两个列表containsdoesNotContains每个拆分。由于您只在此方法中使用它们,而没有在其他地方使用它们,因此请从您的类中删除这两个列表,并将它们定义为内部的私有变量splitFamilies

本文收集自互联网,转载请注明来源。

如有侵权,请联系 [email protected] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章

如何在迭代时从“ ArrayList”中删除元素时避免“ ConcurrentModificationException”?

在遍历和删除ArrayList中的元素时如何避免java.util.ConcurrentModificationException

ArrayList 迭代器 ConcurrentModificationException

在ArrayList中的foreach循环内添加时发生ConcurrentModificationException

尝试从 ArrayList 中删除项目时出现 ConcurrentModificationException

遍历 ArrayList 时出现 ConcurrentModificationException

如何避免ConcurrentModificationException Kotlin

即使使用迭代器从arraylist中删除元素时,java.util.ConcurrentModificationException

迭代地图和更改值时如何避免ConcurrentModificationException?

ArrayList的ConcurrentModificationException

我在ArrayList上进行迭代时出现ConcurrentModificationException

从ArrayList中删除随机项目,导致ConcurrentModificationException

从LinkedHashSet创建ArrayList时防止ConcurrentModificationException

从ArrayList删除元素时发生ConcurrentModificationException

为什么我没有收到ConcurrentModificationException的同时,迭代期间从ArrayList中移除元素

避免使用ArrayList和递归的java.util.ConcurrentModificationException

如何在从LinkedList进行基于递归迭代器的删除时避免ConcurrentModificationException?

如何在并发线程中处理`values()`和`put()`时如何避免HashMap“ ConcurrentModificationException”?

如何避免java.util.ConcurrentModificationException

如何在JPA和Hibernate中合并实体时避免java.util.ConcurrentModificationException

ArrayList.addAll()ConcurrentModificationException

ArrayList的尝试运行`.size时抛出`ConcurrentModificationException`()`方法

如何从到的ArrayLists移除对象时避免ConcurrentModificationException的”

如何在克隆的 ArrayList 上 joinToString 抛出 ConcurrentModificationException

遍历Collection,避免在循环中删除对象时避免ConcurrentModificationException

如何将元素添加到一个ArrayList中的java里面一个for循环不ConcurrentModificationException的

ConcurrentModificationException仅在Java 1.8.0_45中

避免TreeMap ConcurrentModificationException?

爪哇 - 同步的ArrayList仍然ConcurrentModificationException的