Рубрики
Без рубрики

Удаление элементов из коллекций Java

Краткое руководство по удалению элементов из коллекции Java с использованием различных методов.

Автор оригинала: Daniel Barrigas.

1. Обзор

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

Естественно, мы также рассмотрим некоторые предостережения.

2. Определение Нашей Коллекции

Во-первых, мы проиллюстрируем два подхода, которые изменяют исходную структуру данных. Затем мы поговорим о двух других вариантах, которые вместо удаления элементов создадут копию оригинальной Коллекции без них.

Давайте используем следующую коллекцию в наших примерах, чтобы продемонстрировать, как мы можем достичь одного и того же результата, используя различные методы:

Collection names = new ArrayList<>();
names.add("John");
names.add("Ana");
names.add("Mary");
names.add("Anthony");
names.add("Mark");

3. Удаление Элементов С Помощью Итератора

Java Итератор позволяет нам как ходить, так и удалять каждый отдельный элемент в пределах Коллекция .

Для этого нам сначала нужно получить итератор по его элементам с помощью метода iterator . После этого мы можем посетить каждый элемент с помощью next и удалить их с помощью remove :

Iterator i = 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 с помощью нашей Коллекции , вызвать фильтр с помощью нашего предиката , а затем собрать результат с помощью Коллекторов:

Collection filteredCollection = 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 .