簡體   English   中英

Java:遇到 ConcurrentModificationException。 我的迭代器和/或 HashMap 有問題,我不知道它是什么

[英]Java: Encountering ConcurrentModificationException. There's something wrong with my iterators and/or HashMaps, and I don't know what it is

我正在創建一個程序,它接受兩個 .txt 文件並打印出出現在兩個文本中的單詞以及每個共享單詞在每個文本中出現的次數。 我聲明了兩個具有有效路徑的文件對象。 但是,當我嘗試創建兩個使用這兩個 .txt 文件的 Scanner 對象時,對於聲明新 Scanner 對象的兩行代碼,我都會收到 FileNotFoundException 編譯器錯誤。

僅供參考,我在while循環中使用scannerObject.hasNext(),將scannerObject.Next()中的每個單詞添加為HashMap變量中的一個新鍵,值為1,或者,如果該單詞已經是HashMap中的一個鍵,則增加值(出現次數)減 1。

我嘗試使用兩個文件路徑運行以下命令,下面的簡單程序運行沒有錯誤並輸出“它工作了!呵呵”:

import java.io.*;
import java.util.*;

public class readingFilesPractice {
    public static void main(String[] args) {
        try{
            File x = new File("C:\\Users\\aravd.000\\Desktop\\Book1.txt");
            Scanner sc = new Scanner(x);
            while(sc.hasNext()){
                System.out.println(sc.next());
            }
            sc.close();
            System.out.println("It worked! Hehehe");
        }
        catch (Exception e){
            System.out.println("Error!");
        }
    }
}

順便說一下,.txt 文件有一些區域,其中有多個連續的空格和諸如“1.”之類的東西。

下面的代碼遇到兩個 FileNotFoundExceptions(沒有 try 和 catch 塊),並且在 Visual Studios 中, new Scanner(book1)new Scanner(book2)有一條紅色波浪線,當我懸停時指出“未處理的異常類型 FileNotFoundExceptionJava(16777384)”用我的鼠標覆蓋它。 我的完整代碼供參考如下。

import java.io.*;
import java.util.*;

public class program1 {
    public static void main(String[] args) {
        try {
            File book1 = new File("C:\\Users\\aravd.000\\Desktop\\Book1.txt");
            File book2 = new File("C:\\Users\\aravd.000\\Desktop\\Book2.txt");


            // Counting the number of occurences of each word in book1
            Scanner readBook1 = new Scanner(book1);
            HashMap<String, Integer> wordsInBook1 = new HashMap<String, Integer>();
            while (readBook1.hasNext()) {
                String word = readBook1.next();
                if (wordsInBook1.containsKey(word)) {
                    int occurences = wordsInBook1.get(word) + 1;
                    wordsInBook1.put(word, occurences);
                } else {
                    wordsInBook1.put(word, 1);
                }
            }
            readBook1.close();

            // Counting the number of occurences of each word in book2
            Scanner readBook2 = new Scanner(book2);
            HashMap<String, Integer> wordsInBook2 = new HashMap<String, Integer>();
            while (readBook2.hasNext()) {
                String word = readBook2.next();
                if (wordsInBook2.containsKey(word)) {
                    int occurences = wordsInBook2.get(word) + 1;
                    wordsInBook2.put(word, occurences);
                } else {
                    wordsInBook2.put(word, 1);
                }
            }
            readBook2.close();

            // Creating two iterators for each HashMap
            Iterator wordsInB1Iter = wordsInBook1.entrySet().iterator();
            Iterator wordsInB2Iter = wordsInBook2.entrySet().iterator();

            // Running the wordsInB1Iter iterator to find and delete unique keys in
            // wordsInBook1
            while (wordsInB1Iter.hasNext()) {
                Map.Entry pair = (Map.Entry) wordsInB1Iter.next();
                if (!wordsInBook2.containsKey(pair.getKey())) {
                    wordsInBook1.remove(pair.getKey());
                }
            }

            // Running the wordsInB2Iter iterator to find and delete unique keys
            while (wordsInB2Iter.hasNext()) {
                Map.Entry pair = (Map.Entry) wordsInB2Iter.next();
                if (!wordsInBook1.containsKey(pair.getKey())) {
                    wordsInBook2.remove(pair.getKey());
                }
            }
            System.out.println(wordsInBook1);
            System.out.println(wordsInBook2);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

如果代碼的其他部分壞了,我不知道,因為我還沒有調試過。 如果您在其他地方發現錯誤,請告訴我。 感謝您的努力,如果有什么需要進一步澄清的,請告訴我!

更新:當我將 catch 塊更改為 Exception e 並使用 e.printStackTrace 時,我的代碼輸出以下內容:

java.util.ConcurrentModificationException
        at java.base/java.util.HashMap$HashIterator.nextNode(HashMap.java:1493)
        at java.base/java.util.HashMap$EntryIterator.next(HashMap.java:1526)
        at java.base/java.util.HashMap$EntryIterator.next(HashMap.java:1524)
        at prorgam1.main(program1.java:50)

鏈接到 VisualStudios 中“問題”選項卡中的錯誤描述

上圖可能會提供有關我的迭代器和 HashMap 問題的更多詳細信息。

與@Pedro Borges 相同的答案,但

  • 請使用泛型! 你的代碼充滿了演員表,而它不應該。
  • 使用Iterator.remove()刪除當前值而不是使用源集合。 這就是您收到ConcurrentModificationException的原因。
  • 如果您不需要Map.Entry ,則可以使用keySet()代替。
  • 您正在使用 Java > 8。如果這是 Java 11,您也可以使用var

您的代碼:

        Iterator<Map.Entry<String, Integer>>> wordsInB1Iter = wordsInBook1.entrySet().iterator();
        Iterator<Map.Entry<String, Integer>>> wordsInB2Iter = wordsInBook2.entrySet().iterator();

        // Running the wordsInB1Iter iterator to find and delete unique keys in
        // wordsInBook1
        while (wordsInB1Iter.hasNext()) {
            Map.Entry<String,Integer> pair = wordsInB1Iter.next();
            if (!wordsInBook2.containsKey(pair.getKey())) {
                wordsInB1Iter.remove();
            }
        }

        // Running the wordsInB2Iter iterator to find and delete unique keys
        while (wordsInB2Iter.hasNext()) {
            Map.Entry<String,Integer> pair = wordsInB2Iter.next();
            if (!wordsInBook1.containsKey(pair.getKey())) {
                wordsInB2Iter.remove();
            }
        }

當我在做的時候,你也可以考慮重構你的閱讀方式:

  • 通過使用方法而不是復制代碼
  • 通過使用 try with resource (Java 7++)
  • 通過使用 Map.merge (Java 8++)

如:

void words(File file) {
  try (Scanner scanner = new Scanner(file)) {
    var result = new HashMap<String,Integer>();
    while (scanner.hasNext()) {
      var word = scanner.next();
      result.merge(word, 1, Integer::sum); // or (a, b) -> a + b
    }
    return result;
  }
}

出於性能原因,您可以(應該?)使用MutableInteger (來自 common-lang3)來避免從Integer拆箱到int

ConcurrentModificationException 來自您在迭代時從 Set 中刪除元素的事實。 發生這種情況是因為在幕后迭代器由集合支持,它不是它的副本。

一種解決方法,雖然不是非常優雅,但迭代 Set 的副本。

如果你更換

Iterator wordsInB1Iter = wordsInBook1.entrySet().iterator();
Iterator wordsInB2Iter = wordsInBook2.entrySet().iterator();

Iterator wordsInB1Iter = new HashSet<>(wordsInBook1.entrySet()).iterator();
Iterator wordsInB2Iter = new HashSet<>(wordsInBook2.entrySet()).iterator();

您將不再有並發修改。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM