Java: Обнаружено исключение ConcurrentModificationException. Что-то не так с моими итераторами и / или HashMaps, и я не знаю, что это такое - PullRequest
0 голосов
/ 02 апреля 2020

Я создаю программу, которая берет два файла .txt и распечатывает слова, которые появляются в обоих текстах, и количество раз, когда каждое общее слово появляется в каждом тексте. Я объявил два файловых объекта, которые имеют допустимые пути. Однако, когда я пытаюсь создать два объекта Scanner, которые используют два файла .txt, я получаю ошибки компилятора FileNotFoundException для обеих строк кода, которые объявляют новые объекты Scanner.

К вашему сведению, я использую scannerObject.hasNext () через некоторое время l oop, который добавляет каждое слово из 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 Stud ios, new Scanner(book1) и new Scanner(book2) имеют красную волнистую линию, которая сообщает «Необработанный тип исключения FileNotFoundException Java (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)

Ссылка на описания ошибок на вкладке «ПРОБЛЕМЫ» в VisualStud ios

На рисунке выше может быть предоставлена ​​более подробная информация о проблемах с моими итераторами и HashMaps.

Ответы [ 2 ]

0 голосов
/ 06 мая 2020

Тот же ответ, что и у @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 с ресурсом (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 по соображениям производительности.

0 голосов
/ 06 мая 2020

Исключение ConcurrentModificationException связано с тем, что вы удаляете элементы из набора во время его итерации. Это происходит потому, что внутри итератора поддерживается набор, а не его копия.

Один из способов загнать его в угол, хотя и не слишком элегантно, - это перебирать копию набора.

Если вы замените

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

на

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

, у вас больше не будет одновременной модификации.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...