Автор оригинала: Daniel Barrigas.
1. Обзор
В этом кратком руководстве мы поговорим о четырех различных способах удаления элементов из Java Коллекций , которые соответствуют определенным предикатам.
Естественно, мы также рассмотрим некоторые предостережения.
2. Определение Нашей Коллекции
Во-первых, мы проиллюстрируем два подхода, которые изменяют исходную структуру данных. Затем мы поговорим о двух других вариантах, которые вместо удаления элементов создадут копию оригинальной Коллекции без них.
Давайте используем следующую коллекцию в наших примерах, чтобы продемонстрировать, как мы можем достичь одного и того же результата, используя различные методы:
Collectionnames = new ArrayList<>(); names.add("John"); names.add("Ana"); names.add("Mary"); names.add("Anthony"); names.add("Mark");
3. Удаление Элементов С Помощью Итератора
Java Итератор позволяет нам как ходить, так и удалять каждый отдельный элемент в пределах Коллекция .
Для этого нам сначала нужно получить итератор по его элементам с помощью метода iterator . После этого мы можем посетить каждый элемент с помощью next и удалить их с помощью remove :
Iteratori = names.iterator(); while(i.hasNext()) { String e = i.next(); if (e.startsWith("A")) { i.remove(); } }
Несмотря на его простоту, есть некоторые предостережения, которые мы должны учитывать:
- В зависимости от коллекции, с которой мы можем столкнуться ConcurrentModificationException исключения
- Нам нужно перебрать элементы, прежде чем мы сможем их удалить
- В зависимости от коллекции remove может вести себя иначе, чем ожидалось. Например: ArrayList.Итератор удаляет элемент из коллекции и сдвигает последующие данные влево, в то время как, LinkedList.Итератор просто настраивает указатель на следующий элемент. Таким образом, LinkedList.Итератор работает намного лучше, чем ArrayList.Итератор при удалении элементов
4. Java 8 и Collection.removeIf()
Java 8 представила новый метод для интерфейса Collection , который обеспечивает более краткий способ удаления элементов с помощью Предиката :
names.removeIf(e -> e.startsWith("A"));
Важно отметить, что в отличие от подхода Iterator , removeIf одинаково хорошо работает как в LinkedList , так и в |/ArrayList .
В Java 8 ArrayList переопределяет реализацию по умолчанию, которая опирается на Итератор – и реализует другую стратегию: сначала он повторяет элементы и помечает те, которые соответствуют нашему предикату ; затем он повторяет второй раз, чтобы удалить (и сдвинуть) элементы, которые были отмечены в первой итерации.
5. Java 8 и введение потока
Одной из новых основных функций в Java 8 стало добавление Stream (и Collectors ). Существует множество способов создания потока из источника. Однако большинство операций, влияющих на экземпляр Stream , не изменяют его источник, скорее, API фокусируется на создании копий источника и выполнении любых операций, которые нам могут понадобиться в них.
Давайте посмотрим, как мы можем использовать Stream и Collectors для поиска/фильтрующих элементов, которые соответствуют и не соответствуют нашему Предикату .
5.1. Удаление Элементов С Потоком
Удаление, а точнее, фильтрующих элементов с помощью Stream довольно просто , нам просто нужно создать экземпляр Stream с помощью нашей Коллекции , вызвать фильтр с помощью нашего предиката , а затем собрать результат с помощью Коллекторов:
CollectionfilteredCollection = names .stream() .filter(e -> !e.startsWith("A")) .collect(Collectors.toList());
Потоковая передача менее инвазивна, чем предыдущие подходы, она способствует изоляции и позволяет создавать несколько копий из одного и того же источника. Однако мы должны иметь в виду, что это также увеличивает объем памяти, используемой нашим приложением.
5.2. Коллекторы.
Комбинирование Stream.filter и Collectors довольно удобно, хотя мы можем столкнуться со сценариями, в которых нам нужны как совпадающие, так и не совпадающие элементы. В таких случаях мы можем воспользоваться Collectors.partitioningBy :
Map> classifiedElements = names .stream() .collect(Collectors.partitioningBy((String e) -> !e.startsWith("A"))); String matching = String.join(",", classifiedElements.get(true)); String nonMatching = String.join(",", classifiedElements.get(false));
Этот метод возвращает Map , который содержит только два ключа, true и false , каждый из которых указывает на список, содержащий соответствующие и несоответствующие элементы соответственно.
6. Заключение
В этой статье мы рассмотрели некоторые методы удаления элементов из Коллекций и некоторые из их предостережений.
Вы можете найти полный исходный код и все фрагменты кода для этой статьи на GitHub .