[英]Can't figure out what's triggering “java.util.ConcurrentModificationException”
My code is throwing an error that I've never seen before. 我的代码抛出了一个我从未见过的错误。 So hey!
嘿! I guess I'm learning ;) Anyway, I did some reading and generally this error is thrown when a list that is being iterated over is modified mid-iteration.
我想我正在学习;)无论如何,我做了一些阅读,并且通常在迭代过程中修改一个迭代列表时会抛出此错误。 However, I'm pretty sure I'm not modifying it.
但是,我很确定我没有对其进行修改。 While the error is being thrown on partition(), if I don't assign a new value for currentList in updateCurrentList() (by commenting out the code), the program no longer throws the error.
当错误被抛出在partition()上时,如果我没有在updateCurrentList()中为currentList分配新值(通过注释掉代码),则程序不再抛出错误。 These two functions are called one after the other in my play() method, however the list iteration should be complete by the time the change is made.
这两个函数在我的play()方法中一个接一个地调用,但是列表迭代应该在进行更改时完成。 What am I missing?
我想念什么? Do I have to close down the iterator somehow?
我是否必须以某种方式关闭迭代器?
package hangman;
import java.io.*;
import java.util.*;
import javax.swing.JOptionPane;
public class Hangman {
private Map<String, List<String>> wordPartitions; // groups words according to positions of guessed letter
private List<String> currentList; // remaining possible words that fit the information given so far
Set<Character> wrongGuesses; // holds all the "wrong" guesses so far
StringBuilder guessString; // current state of the word being guessed
String justHyphens; // for checking whether a guess was "wrong"
// initialize fields
// currentList should contain all (and only) words of length wordLength
// justHyphens and guessString should consist of wordLength hyphens
public Hangman(int wordLength) throws FileNotFoundException {
this.currentList = new ArrayList<String>();
addWords(wordLength);
wrongGuesses = new HashSet();
for(int i = 0; i < wordLength; i++) {
justHyphens += "-";
}
guessString = new StringBuilder();
wordPartitions = new HashMap();
}
private void addWords(int wordLength) throws FileNotFoundException {
Scanner words = new Scanner(new File("lexicon.txt"));
String word = "";
while(words.hasNext()) {
word = words.next();
if (word.length() == wordLength) {
currentList.add(word);
}
}
}
// main loop
public void play() {
char choice;
do {
choice = getUserChoice();
partition(choice);
updateCurrentList(choice);
} while (!gameOver());
endMessage();
}
// display the guessString and the missed guesses
// and get the next guess
private char getUserChoice() {
//generate a string from the incorrect choices char list
String wrong = "";
char letter;
if(!wrongGuesses.isEmpty()) {
Iterator<Character> letters = wrongGuesses.iterator();
letter = letters.next();
while(letters.hasNext()) {
letter = letters.next();
wrong += ", " + letter;
}
}
String letterStr = JOptionPane.showInputDialog("Incorrect choices: "+ wrong +"\n Tested letters: "+ guessString.toString() +"\nplease input a letter.");
return letterStr.charAt(0);
}
// use wordPartitions to partition currentList using
// keys returned by getPartitionKey()
private void partition(char choice) {
String word = "";
String key = "";
List<String> tempList = new ArrayList<String>();
Iterator<String> words = currentList.iterator();
//Generate a key for each word and add to appropriate arraylist within map.
while(words.hasNext()) {
word = words.next();
key = getPartitionKey(word, choice);
if(wordPartitions.containsKey(key)) {
tempList = wordPartitions.get(key);
tempList.add(word);
wordPartitions.put(key, tempList);
} else {
tempList.clear();
tempList.add(word);
wordPartitions.put(key, new ArrayList<String>());
}
}
}
// update currentList to be a copy of the longest partition
// if choice was "wrong", add choice to wrongGuesses
// if choice was "right", update guessString
private void updateCurrentList(char choice) {
String key = findLongestList();
currentList = wordPartitions.get(key);
if(key.equals(justHyphens)) {
wrongGuesses.add(choice);
} else {
addLetterToGuessString(guessString, choice, key);
}
}
private String findLongestList() {
Set<String> keySet = wordPartitions.keySet();
Iterator<String> keys = keySet.iterator();
String maxKey = "";
int maxKeyLength = 0;
List<String> tempList;
String tempKey = "";
while(keys.hasNext()) {
tempKey = keys.next();
tempList = wordPartitions.get(tempKey);
if(tempList.size() > maxKeyLength) {
maxKeyLength = tempList.size();
maxKey = tempKey;
}
}
return maxKey;
}
// checks for end of game
private boolean gameOver() {
return false;
}
// display the guessString and the missed guesses
// and print "Congratulations!"
private void endMessage() {
JOptionPane.showMessageDialog(null, "Congrats, yo!");
}
// returns string with '-' in place of each
// letter that is NOT the guessed letter
private String getPartitionKey(String s, char c) {
String word = "";
String letter = Character.toString(c);
for(int i = 0; i < s.length(); i++) {
if(s.charAt(i) == c) {
word += letter;
} else {
word += "-";
}
}
return word;
}
// update guessString with the guessed letter
private void addLetterToGuessString(StringBuilder guessString, char letter, String key) {
for(int i = 0; i < key.length(); i++) {
if(key.charAt(i) != '-') {
guessString.setCharAt(i, key.charAt(i));
}
}
}
} }
The problem is that you are modifying a collection while you are iterating over it. 问题是您在迭代一个集合时正在修改它。
The collection is currentList
, you are iterating over it in partition()
. 该集合是
currentList
,您正在partition()
对其进行迭代。 You modify it when you add a word to tempList
here: 当您在此处向
tempList
添加单词时,可以tempList
修改:
key = getPartitionKey(word, choice);
if(wordPartitions.containsKey(key)) {
tempList = wordPartitions.get(key);
tempList.add(word);
wordPartitions.put(key, tempList);
} else {
Why ? 为什么呢 Because previously you called
updateCurrentList()
from play()
: 因为以前您是从
play()
调用updateCurrentList()
play()
:
do {
choice = getUserChoice();
partition(choice);
updateCurrentList(choice);
} while (!gameOver());
And you updated currentList
: 然后您更新了
currentList
:
String key = findLongestList();
currentList = wordPartitions.get(key);
So, if the key
returned by getPartitionKey(word, choice)
is the same as the key previously returned by findLongestList()
, currentList
will be the same as tempList
, and so you will be modifying the collection you are iterating over. 因此,如果
key
由归国getPartitionKey(word, choice)
是与先前通过返回键findLongestList()
currentList
将是相同的tempList
,所以你会修改你迭代的集合。
The solution ? 解决方案 ? If
tempList
is the same as currentList
, don't add the word to it (it already have the word, by definition). 如果
tempList
与currentList
相同,则不要在其中添加单词(根据定义,该单词已经包含该单词)。 So, you can rewrite your if-else like that (I removed some useless code): 因此,您可以像这样重写if-else(我删除了一些无用的代码):
if(wordPartitions.containsKey(key)) {
tempList = wordPartitions.get(key);
} else {
wordPartitions.put(key, new ArrayList<String>());
}
if (tempList!=currentList) {
tempList.add(word);
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.