- List, метод remove() баг в языке Java или миф? [закрыт]
- 2 ответа 2
- Всё ещё ищете ответ? Посмотрите другие вопросы с метками java list коллекции arraylist или задайте свой вопрос.
- Похожие
- Удаление элемента списка в цикле foreach не бросает ConcurrentModificationException, почему?
- 2 ответа 2
- Реализовать метод add, remove и другие в своем списке
- Решение
- Удаление элементов из коллекций Java
- 1. Обзор
- 2. Определение Нашей Коллекции
- 3. Удаление Элементов С Помощью Итератора
- 4. Java 8 и Collection.removeIf()
- 5. Java 8 и введение потока
- 5.1. Удаление Элементов С Потоком
- 5.2. Коллекторы.
- 6. Заключение
- Коллекции в Java: о чём многие забывают
- Содержание:
- List.subList
- PriorityQueue
- EnumSet и EnumMap
- Set.add(E) и Set.remove(E) возвращают булево значение
- Map.put(K, V), Map.remove(K), List.set(idx, E), List.remove(idx) возвращают предыдущий элемент
- Map.keySet() и Map.values()
- Arrays.asList может быть ключом
- Collections.min/max
- Stack, Vector, Hashtable, LinkedList
List, метод remove() баг в языке Java или миф? [закрыт]
Хотите улучшить этот вопрос? Обновите вопрос так, чтобы он вписывался в тематику Stack Overflow на русском.
Закрыт 2 года назад .
У нас 4 элемента:
Подсчёт по индексу: 0 1 2 3 (4 элемента)
А мне выдает ошибку:
Неправильно походу работает что ли?))
2 ответа 2
У вас был лист с индексами от 0 до 3. Вы удалили элемент( remove(1) ), их стало на 1 меньше, лист перестроился в лист с индексами от 0 до 2. После этого вы хотите удалить элемент с индексом 3( remove(3) ), а у вас уже нет такого индекса.
Напишите list.remove(2); и посмотрите, что выйдет. В ArrayList при вызове remove() ячейка удаляется из массива со смещением всех элементов к началу. Чтобы оставить по индексу пустое значение, нужно использовать list.set(2, null);
Всё ещё ищете ответ? Посмотрите другие вопросы с метками java list коллекции arraylist или задайте свой вопрос.
Похожие
дизайн сайта / логотип © 2021 Stack Exchange Inc; материалы пользователей предоставляются на условиях лицензии cc by-sa. rev 2021.10.18.40487
Нажимая «Принять все файлы cookie» вы соглашаетесь, что Stack Exchange может хранить файлы cookie на вашем устройстве и раскрывать информацию в соответствии с нашей Политикой в отношении файлов cookie.
Источник
Удаление элемента списка в цикле foreach не бросает ConcurrentModificationException, почему?
Допустим, у меня есть некий ArrayList .
И я хочу из него удалить все числа больше 10.
«Правильно» сделать это можно через итератор, получив гарантированный результат.
Но на мое удивление, корректно работает и вариант:
Несмотря на то, что везде говорится, что любая попытка удаления из коллекции в цикле без использования итератора приводит к ConcurrentModificationException .
И, действительно, если будем удалять безусловно, получим как раз ConcurrentModificationException
Собственно, может кто-нибудь объяснить магию или дать наводку, где можно почитать на эту тему?
2 ответа 2
Видимо вам сказочно повезло:
- у вас не было элементов, значение которых было больше 10
- у вас был элемент, значение которого было больше 10, но он был только один и располагался на предпоследнем месте в списке
Давайте рассмотрим работу на более коротком примере.
Мы добавили три числа. Итак, как работает foreach
- Он получает итератор.
Проверяет на наличие следующего элемента hasNext() .
Если возвращается true , то берет следующий элемент с помощью next() .
Далее повторяются шаги 2 и 3 пока hasNext() не вернет false .
Если удалить элемент из списка, то его размер уменьшится и modCount увеличится.
Если удалить элемент во время итерации, то будет выброшено ConcurrentModificationException исключение на строке modCount != expectedModCount .
Но что происходит, если удаляется предпоследний элемент?
Когда мы удалим значение 22, то размер уменьшится до 2.
В других же случаях будет выброшено ConcurrentModificationException из-за modCount != expectedModCount .
А в этом единичном случае проверка пройдет на ура..
Источник
Реализовать метод add, remove и другие в своем списке
Помощь в написании контрольных, курсовых и дипломных работ здесь.
Реализовать методы add и remove по индексу для самодельного списка
Есть самописный список, нужно реализовать функции add(value, index) и remove(index). Добавление и.
Groovy Метод remove на списке и на диапазоне
Здравствуйте, всем доброго времени суток . Q = println «Q = $Q» N = Q.remove(1) println «N.
Реализовать аппликативный оператор MY-REMOVE-IF с интерфейсом и семантикой, аналогично стандартному REMOVE-IF
Реализовать аппликативный оператор MY-REMOVE-IF с интерфейсом и семантикой, аналогично стандартному.
Решение
Ну у тебя же на схеме написано: #content: ConcurentLinkedDeque .
Реализация методов Add, Remove в классе ColectionBase
Добрый день, Изучаю С#, появился такой вопрос: Класс ColectionBase не содержит реализацию к.
Ошибка при явной реализации методов Add и Remove
Добрый день. Есть два класса событий MyEvent и MyEvent2, код ниже. С первым классов все в порядке.
Какой интерфейс идентичен ICollection но без методов Add(), Remove(), Clear()
Добрый вечер! Не подскажите интерфейс, который идентичен ICollection , за исключением того, что.
Как реализовать поиск в списке List, если отсутствует метод Find
Здравствуйте уважаемые форумчане, возникла очередная проблема. У меня есть public.
Источник
Удаление элементов из коллекций Java
Краткое руководство по удалению элементов из коллекции Java с использованием различных методов.
Автор: Daniel Barrigas
Дата записи
1. Обзор
В этом кратком руководстве мы поговорим о четырех различных способах удаления элементов из Java Коллекций , которые соответствуют определенным предикатам.
Естественно, мы также рассмотрим некоторые предостережения.
2. Определение Нашей Коллекции
Во-первых, мы проиллюстрируем два подхода, которые изменяют исходную структуру данных. Затем мы поговорим о двух других вариантах, которые вместо удаления элементов создадут копию оригинальной Коллекции без них.
Давайте используем следующую коллекцию в наших примерах, чтобы продемонстрировать, как мы можем достичь одного и того же результата, используя различные методы:
3. Удаление Элементов С Помощью Итератора
Java Итератор позволяет нам как ходить, так и удалять каждый отдельный элемент в пределах Коллекция .
Для этого нам сначала нужно получить итератор по его элементам с помощью метода iterator . После этого мы можем посетить каждый элемент с помощью next и удалить их с помощью remove :
Несмотря на его простоту, есть некоторые предостережения, которые мы должны учитывать:
- В зависимости от коллекции, с которой мы можем столкнутьсяConcurrentModificationExceptionисключения
- Нам нужно перебрать элементы, прежде чем мы сможем их удалить
- В зависимости от коллекцииremoveможет вести себя иначе, чем ожидалось. Например: ArrayList.Итератор удаляет элемент из коллекции и сдвигает последующие данные влево, в то время как, LinkedList.Итератор просто настраивает указатель на следующий элемент. Таким образом, LinkedList.Итератор работает намного лучше, чем ArrayList.Итератор при удалении элементов
4. Java 8 и Collection.removeIf()
Java 8 представила новый метод для интерфейса Collection , который обеспечивает более краткий способ удаления элементов с помощью Предиката :
Важно отметить, что в отличие от подхода Iterator , removeIf одинаково хорошо работает как в LinkedList , так и в |/ArrayList .
В Java 8 ArrayList переопределяет реализацию по умолчанию, которая опирается на Итератор – и реализует другую стратегию: сначала он повторяет элементы и помечает те, которые соответствуют нашему предикату ; затем он повторяет второй раз, чтобы удалить (и сдвинуть) элементы, которые были отмечены в первой итерации.
5. Java 8 и введение потока
Одной из новых основных функций в Java 8 стало добавление Stream (и Collectors ). Существует множество способов создания потока из источника. Однако большинство операций, влияющих на экземпляр Stream , не изменяют его источник, скорее, API фокусируется на создании копий источника и выполнении любых операций, которые нам могут понадобиться в них.
Давайте посмотрим, как мы можем использовать Stream и Collectors для поиска/фильтрующих элементов, которые соответствуют и не соответствуют нашему Предикату .
5.1. Удаление Элементов С Потоком
Удаление, а точнее, фильтрующих элементов с помощью Stream довольно просто , нам просто нужно создать экземпляр Stream с помощью нашей Коллекции , вызвать фильтр с помощью нашего предиката , а затем собрать результат с помощью Коллекторов:
Потоковая передача менее инвазивна, чем предыдущие подходы, она способствует изоляции и позволяет создавать несколько копий из одного и того же источника. Однако мы должны иметь в виду, что это также увеличивает объем памяти, используемой нашим приложением.
5.2. Коллекторы.
Комбинирование Stream.filter и Collectors довольно удобно, хотя мы можем столкнуться со сценариями, в которых нам нужны как совпадающие, так и не совпадающие элементы. В таких случаях мы можем воспользоваться Collectors.partitioningBy :
Этот метод возвращает Map , который содержит только два ключа, true и false , каждый из которых указывает на список, содержащий соответствующие и несоответствующие элементы соответственно.
6. Заключение
В этой статье мы рассмотрели некоторые методы удаления элементов из Коллекций и некоторые из их предостережений.
Вы можете найти полный исходный код и все фрагменты кода для этой статьи на GitHub .
Источник
Коллекции в Java: о чём многие забывают
Из опыта code-review и ответов на StackOverflow набралось немало моментов, касающихся Java Collections API, которые мне казались очевидными, но другие разработчики о них почему-то не знали или знали, но не чувствовали уверенности их применять. В этой статье я собираю в общую кучу всё, что накопилось.
Содержание:
List.subList
Про это уже писали, но стоит повторить. Наверно, самый недооценённый метод из Collections API. Бывает, что надо каким-то образом обработать часть списка (например, в алгоритмах семейства «разделяй и властвуй» или при распараллеливании задачи). Многие создают метод или класс, который завязывается на три параметра: List, from и to:
Так незачем делать. Реализации алгоритма должно быть плевать, что она обрабатывает часть списка. Пишите:
Даже если у вас всё в одном методе, удобнее воспользоваться расширенным циклом for, чем возиться с индексами:
Кроме того, subList — полнофункциональный список, он работает и на запись, внося соответствующие изменения в родительский список. Нужно удалить много элементов из середины списка? Ничего нет проще:
У популярных реализаций вроде ArrayList это выполняется очень быстро.
Надо выяснить, начинается ли список с определённых элементов? И тут subList в руки!
Надо добавить в один список все элементы другого списка за исключением первого? И тут subList придёт на помощь:
Не забывайте, что можно писать Arrays.asList(array).subList(from, to) , поэтому вышесказанное применимо и для непримитивных массивов. Структурно менять вы их не сможете, но передавать кусок массива в метод, принимающий список для чтения — легко.
PriorityQueue
Если subList — самый недооценённый метод, то PriorityQueue — это, на мой взгляд, самый недооценённый класс. Многие сталкиваются с задачей отыскать, скажем, 10 минимальных значений большого несортированного списка. Чаще всего список сортируют и потом берут первые 10 значений. Если исходный список менять нельзя, придётся его ещё скопировать для сортировки. А ведь очередь с приоритетом легко справится с этой задачей:
Такой код в зависимости от данных может работать гораздо быстрее, чем сортировка. Например, для n = 10 и случайно заполненного списка из миллиона элементов очередь с приоритетом почти в сто раз обгоняет подход с сортировкой. При этом дополнительной памяти требуется O(n) и входные элементы можно обрабатывать в потоковом режиме (например, выбрать 10 наименьших чисел из входного файла).
Вообще людям свойственно изучить пару-тройку структур данных и пользоваться ими везде. Не ленитесь, познакомьтесь с разными структурами.
EnumSet и EnumMap
До сих пор встречается код, где значения типа enum используют в качестве ключей в HashSet и HashMap. Хотя это работает, но оно неоправданно расточительно. Существующие специальные классы EnumSet и EnumMap значительно производительнее. Так если в enum не больше 64 разных значений, EnumSet хранит всё в одном поле типа long в битовой маске. EnumMap содержит все значения в обычном массиве той же длины, сколько элементов в enum, а ключи не хранит вовсе. Так как у каждого значения в enum есть порядковый номер ordinal(), можно легко перейти от enum-ключа к элементу массива. Также никогда не нужно менять размер массива.
Set.add(E) и Set.remove(E) возвращают булево значение
Часто вижу подобный код:
Не надо забывать, что операция добавления в Set возвращает true, если добавление успешно (то есть элемента не было) и false, если такой элемент уже был. Незачем усложнять код и два раза пробивать элемент по хэш-таблице или двоичному дереву, ведь можно написать:
Аналогично с удалением. Цепочка if(set.contains(item)) < set.remove(item); . >заменяется на if(set.remove(item)) < . >.
Map.put(K, V), Map.remove(K), List.set(idx, E), List.remove(idx) возвращают предыдущий элемент
Из той же оперы ситуация. Методы, изменяющие или удаляющие элемент в коллекции возвращают предыдущее значение, и этим надо пользоваться. Не надо писать, например, так:
Написать просто Item item = myMap.put(key, newItem); . Хотите поменять местами две записи в Map с ключами key1, key2? Временная переменная не нужна:
Map.keySet() и Map.values()
Многие почему-то забывают, что Map.keySet() и Map.values() возвращают отображения исходного Map, которые позволяют удалять элементы (если Map модифицируемый). Надо оставить в Map только записи с определёнными значениями (и любыми ключами)? Пожалуйста:
Также работает removeAll , а с Java-8 ещё и removeIf :
Arrays.asList может быть ключом
Бывает, что вам нужно сформировать Map или Set, используя кортеж значений. Например, у вас есть PoJo-объекты Item , у которых имеются поля name, type, version . У них уже написан equals и hashCode , их можно складывать в HashSet , всё нормально. Но вы хотите выбрать из коллекции уникальные объекты только по полям name и type , игнорируя version. Менять существующие equals и hashCode нельзя. В таких ситуациях люди часто создают отдельный класс только с полями name и type и используют его в качестве ключа. Однако для одноразовой операции проще использовать Arrays.asList() :
Arrays.asList() создаёт список из нужного числа элементов и у него как раз подходящие реализации equals и hashCode : никакой boilerplate не нужен. Так можно создать ключ любой длины, причём корректно обработаются null-значения и примитивы (брагодаря боксингу). Не сработает только, если вы хотите в составе ключа иметь массив.
Collections.min/max
Удивительно, насколько часто можно встретить написанный вручную код, который находит максимальный или минимальный элемент чего-то по какому-нибудь критерию. Казалось бы, такая тривиальная задача должна быть давно решена. На самом деле она и так давно решена: есть методы Collections.min и Collections.max . Раньше было не очень удобно писать компараторы, но в Java-8 всё стало легче.
К примеру, вам нужно найти ключ в Map, соответствующий максимальному значению. Пишите так:
Можно и через Stream API, но Collections.max() несколько быстрее. Если вы не можете использовать Java-8 и компараторы вроде Entry.comparingByValue() вам недоступны, их нетрудно написать.
Stack, Vector, Hashtable, LinkedList
Просто не используйте эти классы. Пользы от них никакой нет. Вместо Stack пользуйтесь ArrayDeque, вместо Vector — ArrayList, вместо Hashtable — HashMap. Если вам нужна потокобезопасность, они вам всё равно не помогут. Возможно, в девятке их всё-таки пометят @Deprecated (смотрите JEP 277).
С LinkedList случай особый. Вроде бы лучшего аналога связного списка нет и ходят легенды, что он на самом деле полезен. В действительности ситуаций, когда LinkedList лучше, чем ArrayList, в реальной жизни исключительно мало. До Java-8 LinkedList ещё мог пригодиться, если вы часто удаляете элементы, идущие не последовательно, по какому-то условию. В Java-8 для этих целей появился List.removeIf , который в ArrayList, конечно, реализован оптимальнее (элементы передвигаются только один раз). Если вам надо сделать много вставок в разные места (задача сама по себе экзотическая), скорее всего быстрее будет создать новый ArrayList, чем вставлять в существующий LinkedList. Ну и помните, что LinkedList кушает в несколько раз больше памяти, так как каждый элемент — это отдельный объект в куче со ссылками на следующий и предыдущий. LinkedList можно использовать только в качестве учебного примера.
На сегодня всё. Программируйте с удовольствием!
Источник