![](/img/trans.png)
[英]How to avoid java.util.ConcurrentModificationException when iterating through and removing elements from an ArrayList
[英]How do I avoid ConcurrentModificationException in ArrayList ONLY when iterating?
为了澄清-我不想从ArrayList中删除任何内容。 因此,我发现的所有答案中有90%实际上并不适用。 我在这里或其他地方找不到任何对我有很大帮助的东西!
我正在编写一个Java应用程序来玩Hangman,其中对手(计算机)实际上在作弊,在某种意义上说它没有“选择”一个单词,而是有一组单词,并确定玩家的猜测是正确的还是不正确的。 ,具体取决于哪一个留下较难猜测的单词。
简而言之,我的问题是这样的:
我有一个ArrayList, masterList
,其中有一组单词,一个字典(如果您愿意的话)以及各种方法来迭代执行此任务。 我的代码是单线程的,在第二次迭代中尝试访问ArrayList中的下一个对象时,这些方法之一抛出ConcurrentModificationException
。 但是,我找不到在迭代过程中实际更改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
。
也许我遗漏了一些非常简单的东西,但是我试图对此进行跟踪,却无法找出为什么我会得到这个异常!
我试图从代码中删除所有不相关的内容,但是如果有人真的想查看完整的内容,我想我可以在问题中转储所有代码!
这个问题源于一个事实,即masterList
是一个参考或者contains
或doesNotContain
第一分之后。 当您在masterList
进行迭代时,实际上您同时也在另一个列表上进行了迭代。
因此,然后将项目添加到列表中:
if(i.contains(guessString)){
contains.add(i);
}else{
doesNotContain.add(i);
}
在这里,您不仅可以将项目添加到contains
或doesNotContain
,而且还可以将其添加到masterList
,这会导致conccurentException
。
要解决您的问题,只需复制列表即可,而不是: masterList = contains;
使用以下方法进行复制: masterList = new ArrayList<>(contains);
与doesNotContains
相同。
想到的另一个解决方案是为每个拆分重置两个列表contains
和doesNotContains
。 由于您仅在此方法中使用它们,并且在其他地方都没有使用,因此请从类中删除这两个列表,并将它们定义为splitFamilies
私有变量
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.