Java Collections.sort () отсутствует исключение ConcurrentModificationException

Я наткнулся на эту странную ошибку. Похоже, что Collections.sort() не изменяет отсортированный список таким образом, который позволяет обнаруживать одновременные изменения при выполнении итерации по тому же списку. Пример кода:

    List<Integer> my_list = new ArrayList<Integer>();

    my_list.add(2);
    my_list.add(1);

    for (Integer num : my_list) {

        /*
         * print list
         */
        StringBuilder sb = new StringBuilder();
        for (Integer i : my_list)
            sb.append(i).append(",");
        System.out.println("List: " + sb.toString());

        /*
         * sort list
         */
        System.out.println("CurrentElement: " + num);
        Collections.sort(my_list);
    }

выходы

List: 2,1,
CurrentElement: 2
List: 1,2,
CurrentElement: 2

Можно ожидать ConcurrentModificationException, но он не вызывается, и код работает, хотя и не должен.

7 голосов | спросил Daniel 12 WedEurope/Moscow2012-12-12T03:34:20+04:00Europe/Moscow12bEurope/MoscowWed, 12 Dec 2012 03:34:20 +0400 2012, 03:34:20

2 ответа


0

Почему он генерирует исключение ConcurrentModificationException , когда вы не добавляете /удаляете элементы из своей коллекции во время итерации?

Обратите внимание, что ConcurrentModificationException происходит только в том случае, если новый элемент добавляется в вашу коллекцию или удаляется из вашей коллекции во время итерации. т.е. когда ваша Коллекция структурно модифицирована.

  

(Структурные изменения - это те, которые изменяют размер этого списка,   или иным образом нарушить его таким образом, что итерации в процессе   может дать неверные результаты.)

Сортировка

не приведет к структурному изменению вашей коллекции, все, что она делает, это изменяет порядок. Приведенный ниже код будет вызывать ConcurrentModificationException , так как он добавляет дополнительный элемент в коллекцию во время итерации.

for(Integer num : my_list) {
    my_list.add(12);
    }

Если вы посмотрите на источник метода сортировки в класс Collections , исключение ConcurrentModificationException .

  

Эта реализация сбрасывает указанный список в массив, сортирует   массив и перебирает список, сбрасывая каждый элемент из   соответствующая позиция в массиве. Это позволяет избежать n2 log (n)   производительность, которая может возникнуть в результате сортировки связанного списка в   место.

public static <T extends Comparable<? super T>> void sort(List<T> list) {
        Object[] a = list.toArray();
        Arrays.sort(a);
        ListIterator<T> i = list.listIterator();
        for (int j=0; j<a.length; j++) {
            i.next();
            i.set((T)a[j]);
        }
    }

Извлечение из книги Общие сведения о java и коллекции :

  

Политика итераторов для коллекций Java 2 не работает   быстро, как описано в разделе 11.1: каждый раз, когда они получают доступ к поддержке   коллекции, они проверяют его на структурную модификацию (которая, в   общее означает, что элементы были добавлены или удалены из   коллекция). Если они обнаруживают структурную модификацию, они терпят неудачу   немедленно, выбрасывая ConcurrentModificationException, а не   продолжая пытаться перебрать измененную коллекцию с   непредсказуемые результаты.

ответил PermGenError 12 WedEurope/Moscow2012-12-12T03:37:07+04:00Europe/Moscow12bEurope/MoscowWed, 12 Dec 2012 03:37:07 +0400 2012, 03:37:07
0

Говоря о функциональности, я не понимаю, почему он не должен выдавать ConcurrentModificationException. Но согласно документации итератор выдает исключение, когда он замечает структурную модификацию, а структурная модификация определено как:

  

Структурные изменения - это изменения, которые изменяют размер списка,   или иным образом нарушить его таким образом, что итерации в процессе   может дать неверные результаты.

Я думаю, что есть аргумент для утверждения, что перестановка элементов в sort приводит к тому, что итератор дает неправильные результаты, но я не проверил, каковы правильные результаты для итератора, определенного как.

Говоря о реализации, легко понять, почему это не так: см. источник для ArrayList и коллекции :

  • ArrayList.modCount изменяется с помощью так называемых структурных изменений
  • Методы ListItr копируют его значение в init и убедитесь, что он не изменился в своих методах
  • Collections.sort вызывает ListItr.set который вызывает ArratList.set. Этот последний метод не увеличивает modCount

Итак, ListItr.next() видит то же самое modCount И никаких исключений не выбрасывается.

ответил Miserable Variable 12 WedEurope/Moscow2012-12-12T04:10:16+04:00Europe/Moscow12bEurope/MoscowWed, 12 Dec 2012 04:10:16 +0400 2012, 04:10:16

Похожие вопросы

Популярные теги

security × 330linux × 316macos × 2827 × 268performance × 244command-line × 241sql-server × 235joomla-3.x × 222java × 189c++ × 186windows × 180cisco × 168bash × 158c# × 142gmail × 139arduino-uno × 139javascript × 134ssh × 133seo × 132mysql × 132