2013-09-10 119 views
0

我正在寫一個解決Mastermind遊戲的程序。該計劃的要點是要列出所有可能的解決方案,並在每次猜測不正確之後,從列表中刪除任何至少不會提供該解決方案的內容。這個方法用來比較兩個字符串(guess和strFromArray),看它們是否得到相同的值。但是,我收到一個錯誤,我無法弄清楚爲什麼。任何幫助,將不勝感激。我不明白爲什麼我有這個錯誤:ConcurrentModificationException

Exception in thread "main" java.util.ConcurrentModificationException 
at java.util.ArrayList$Itr.checkForComodification(Unknown Source) 
at java.util.ArrayList$Itr.next(Unknown Source) 
at Game.shortenTheList(Game.java:88) 
at Game.guess(Game.java:76) 
at Game.play(Game.java:40) 
at Game.main(Game.java:23) 


/* 
* Compares the two strings. If they would get the same output, return false. If they would get a different output, return true. 
*/ 
public boolean compare(String guess, String strFromArray, int black, int white) 
{ 
    int white2 = 0; 
    int black2 = 0; 

    char[] arr1 = guess.toCharArray(); 
    char[] arr2 = strFromArray.toCharArray(); 

    for(int i=0; i<guess.length(); i++) 
    { 
     if(arr1[i] == arr2[i]) 
     { 
      black2 ++; 
      arr1[i] = '$'; 
      arr2[i] = '%'; 
     } 
    } 

    for(int i=0; i<guess.length(); i++) 
    { 
     for(int j=0; j<strFromArray.length(); j++) 
     { 
      if(arr1[i] == arr2[j]) 
      { 
       white2++; 
       arr1[i] = '!'; 
       arr2[j] = '@'; 
      } 
     } 
    } 

    if(black == black2 && white == white2) 
     return false; 

    else 
     return true; 
} 

/* 
* Shortens the list of possible solutions by eliminating everything that wouldn't get at least the given output. 
*/ 
public void shortenTheList(String guess, int black1, int white1) 
{ 
    for (String str : possibleSolutions) 
    { 
     if(compare(guess, str, black1, white1)) 
     { 
      possibleSolutions.remove(str); 
     } 
    } 
} 
+1

你能證明它來自這個代碼片斷? –

+2

Finny,沒有使用迭代器。你是通過多線程訪問它嗎?你能至少發佈stacktrace的前4行嗎? – hexafraction

+0

在詢問異常情況時,請務必發佈堆棧跟蹤。 – chrylis

回答

8

一旦你打開一個Iterator(使用for(String str: possibleSolutions),底層集合(possibleSolutions)任何修改時除外通過調用Iteratorremove你做隱含會造成ConcurrentModificationException,這是非常清楚地記錄在採集班

如果您需要從集合中刪除的項目,使用一個明確的Iterator

Iterator<String> it = possibleSolutions.iterator(); 
while(it.hasNext()) { 
    if(compare(guess, it.next(), black1, white1)) 
     it.remove(); 
} 

正如@allprog所指出的,當你有這樣一個明確的「過濾」問題時,功能性方法會更好。在選擇Java 8之前,使用Guava的Iterables#filterIterables#removeIf可能是一個不錯的選擇;你只需將你的compare方法包裝起來並將其傳入。

+1

如果remove()沒有被調用,它會更好。當列表被過濾而不是被修改時使用功能方法通常是更安全的解決方案。谷歌Guava的「Iterables」課程是這方面最佳實踐的「金礦」。 – allprog

2
/* 
* Shortens the list of possible solutions by eliminating everything that wouldn't get at least the given output. 
*/ 
public void shortenTheList(String guess, int black1, int white1) 
{ 
    for (String str : possibleSolutions) 
    { 
     if(compare(guess, str, black1, white1)) 
     { 
      possibleSolutions.remove(str); 
     } 
    } 
} 

這是你的問題。

相反,使用:

/* 
* Shortens the list of possible solutions by eliminating everything that wouldn't get at least the given output. 
*/ 
public void shortenTheList(String guess, int black1, int white1) 
{ 
    Iterator<String> it = possibleSolutions.iterator(); 
    while(it.hasNext()) 
    { 
     String str = it.next(); 
     if(compare(guess, str, black1, white1)) 
     { 
      it.remove(); 
     } 
    } 
} 

這是唯一干淨的方式從你目前遍歷集合中刪除的對象。另一種較不優雅的方式是創建一個單獨的String列表來刪除和迭代該列表。

1

當您使用foreach循環遍歷它時,您無法修改列表possibleSolutions

更改您的代碼是這樣的:

public void shortenTheList(String guess, int black1, int white1) 
{  
    for(Iterator<String> it = possibleSolutions.iterator(); it.hasNext()){ 
     String str = it.next(); 
     if(compare(guess, str, black1, white1)){ 
      it.remove(); 
     } 
    } 
} 
0

像chrylis說,你不能沒有使用迭代器中刪除從集合的元素。

例如:

public void shortenTheList(String guess, int black1, int white1) 
{ 
for (String str : possibleSolutions) 
{ 
if(compare(guess, str, black1, white1)) 
{ 
possibleSolutions.remove(str); 
} 
} 
} 

應該是:

public void shortenTheList(String guess, int black1, int white1) 
{ 
Iterator i = possibleSolutions.Iterator(); 
while(i.hasNext()) 
{ 
String str = (String) i.next(); 
if(compare(guess, str, black1, white1)) 
{ 
i.remove(); 
} 
} 
} 
相關問題