2017-06-23 14 views
1

説明のために - 私はArrayListから何も削除したくありません。したがって、私が見つけたすべての回答の90%は実際には適用されません。私はここで何かを見つけることができない、または他の場所で私を助けてくれます!ArrayListでConcurrentModificationExceptionを回避するにはどうすればよいですか?

私は、対戦相手(コンピュータ)が本質的に不正行為を行っているハングマンをプレイするJavaアプリケーションを作成しています。単語を「選択」しないという意味で、単語群を持ち、プレイヤーの推測が正しい、または間違っているかどうかを判断することができます。一言で言えば

、私の問題はこれです:

必要になります場合、私は、私は言葉のセットを持ってArrayListを、masterList、辞書を持っており、様々な方法がさまざまなタスクを実行するには、このを反復。私のコードはシングルスレッドであり、2番目の反復でArrayList内の次のオブジェクトにアクセスしようとすると、これらのメソッドの1つが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です。

私は本当にシンプルなものを見逃しているかもしれませんが、私はこれをトレースしようとしましたが、なぜこの例外が出ているのか分かりません!

私はコードとは無関係にすべてを削除しようとしましたが、本当に誰かが完全なものを見たいと思えば、私はすべてのコードを質問にダンプすることができますね!

+0

'masterList'を反復しながら' contains'と 'doesNotContain'に追加します。これは同じものを参照している可能性があります。 – shmosel

+1

'masterList = contains'や' masterList = doesNotContain'を行います。次に、 'contains'または' doesNotContain'に追加しようとします。 shmoselが言ったように、 'masterList'はあなたが変更しようとしているのと同じリストを参照します。あなたは反復処理中にリストを修正しようとしているので、 'ConcurrentModificationException'がスローされているので、それらの答えの90%が**適用されます**リストを反復しながら**変更**しようとしました。 –

+0

NB 'while(br.readLine()!= null)'および次の 'readLine()'呼び出しが正しくありません。偶数行のみが表示されます。 'while((line = br.readLine())!= null)'に 'readLine()'を入れないでください。 – EJP

答えて

2

masterListは、最初の分割後にcontainsまたはdoesNotContainのいずれかへの参照であるという事実に由来します。 masterListを反復処理すると、実際には同じ時間に他のリストも反復処理されます。

だから、あなたはリストに項目を追加します。ここでは

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

あなただけconccurentExceptionにつながる、containsまたはdoesNotContainに、だけでなく、潜在的にmasterListに項目を追加しないでください。 masterList = contains;
でコピーを実行します:doesNotContainsためmasterList = new ArrayList<>(contains);

と同じ、あなたの問題を解決するだけで、あなたのリストのコピーを作成し、代わりにするには


。頭に浮かぶ


別の解決策は、各分割のための二つのリストcontainsdoesNotContainsをリセットすることです。このメソッドでのみ使用するので、これらの2つのリストをクラスから取り除き、それらを内部変数として定義します。splitFamilies

+1

答えをありがとう!あなたの提案のために上記のコード行を入れ替えて、すべてがうまくいくように見えます!これは私に多くのトラブルを救った、ありがとう! – whiteside0013

関連する問題