![](/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.