gpt4 book ai didi

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

转载 作者:行者123 更新时间:2023-11-30 02:29:05 24 4
gpt4 key购买 nike

澄清一下 - 我不想从 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第一次 split 后。当您迭代masterList时,您实际上还同时在另一个列表上进行迭代。

那么,您可以将项目添加到列表中:

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

在这里,您不仅可以将项目添加到 containsdoesNotContain ,但也有可能 masterList ,这导致 conccurentException .

<小时/>

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

doesNotContains 也是如此.

<小时/>

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

关于java - 仅在迭代时如何避免 ArrayList 中的 ConcurrentModificationException?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44731290/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com