1. Введение
Коллекция операций представляет собойJavaТо, что программисты повторяют чуть ли не каждый день. Сегодня мы будем учиться сJava Collectionметод удаления элементов в . Я создал простую коллекцию в качестве примера для изучения.
List<String> servers = new ArrayList<>();
servers.add("Felordcn");
servers.add("Tomcat");
servers.add("Jetty");
servers.add("Undertow");
servers.add("Resin");
2. Цикл for не обязательно удаляет элементы из коллекции
Давайте воспользуемся традиционнымforeach
удаление петлиF
Поддельный сервер в начале, но вы обнаружите, что эта операция запускаетConcurrentModificationException
аномальный.
// 错误的示范 千万不要使用
for (String server : servers) {
if (server.startsWith("F")) {
servers.remove(server);
}
}
Не может ли цикл for удалить элементы? конечно, нет! Ничего страшного, если мы сможем определить индекс элемента, который нужно удалить.
// 这种方式是可行
for (int i = 0; i < servers.size(); i++) {
if (servers.get(i).startsWith("F")) {
servers.remove(i);
}
}
Но таким образом я только продемонстрировалArrayList
, другие типы строго не тестируются и оставляются на ваше усмотрение.
3. Итератор Итератор может удалять элементы в коллекции
Традиционно мы используемIterator
гарантированно удаляет элементы:
Iterator<String> iterator = servers.iterator();
while (iterator.hasNext()) {
String next = iterator.next();
if (next.startsWith("F")) {
iterator.remove();
}
}
4. Недостатки обхода и удаления элементов
- Нам нужно перебрать каждый элемент коллекции и утвердить их, даже если вы удалите элемент.
- Хотя мы можем итеративно удалять определенные элементы, операция громоздка и имеет потенциал в зависимости от типа коллекции.
ConcurrentModificationException
аномальный. - В зависимости от структуры данных временная сложность удаления элемента сильно различается. такие как структуры массива
ArrayList
Не так быстро, как структура связанного списка при удалении элементовLinkedList
.
5. Операция удаления нового элемента коллекции
Java 8Предоставляет новые операции сбораAPIа такжеStreamчтобы помочь нам решить эту проблему. Я описал в предыдущих статьяхJava 8 Stream API, если вам интересно, то можете пойти и посмотреть.
5.1 Collection.removeIf()
новыйCollection
Api removeIf(Predicate filter)
. ДолженApiобеспечивает более лаконичное использованиеPredicate
(Утверждать) метод для удаления элемента, поэтому мы можем более кратко реализовать начальные требования:
servers.removeIf(s-> s.startsWith("F"));
В то же время, согласно тесту,ArrayList
а такжеLinkedList
исполнение близко. Этот метод обычно рекомендуется для работы.
5.2 Потоковая реализация удаляет элементы
В отличие от всех вышеперечисленных операций по удалению, по сути, ни одна из операций не изменитStream
источник, мы просто используемStream
ApiРаботает с копией источника данных. последовал数据源 -> 中间操作 -> 归纳终止
жизненный цикл. Давайте посмотрим на использованиеStream
Как достичь нашего намерения.
5.2.1 Реализуется утверждением фильтра
мы можем использоватьStream
изfilter
утверждение.filter
Утверждение объединит элементы потока, соответствующие утверждению, в новый поток, а затем суммирует его, поэтому мы можем написать:
// 跟以上不同的是 该方式中的断言是取反的操作。
List<String> newServers = servers.stream().filter(s -> !s.startsWith("F")).collect(Collectors.toList());
Это преимущество было упомянуто выше, не затрагивая исходные данные, и создается копия. Недостатком является то, что могут быть проблемы с использованием памяти.
5.2.2 Индукция через Collectors.partitioningBy
Хотя этого метода достаточно, я чувствую себя немного оппортунистическим.Collectors.partitioningBy()
Метод предполагается дихотомическим. Этот метод суммирует элементы в потоке, которые соответствуют утверждению, и те, которые не соответствуют утверждению, в два элемента.key
соответственноtrue
а такжеfalse
изMap
, мы можем классифицировать набор совпадающих и не совпадающих элементов. Реализация выглядит следующим образом:
Map<Boolean, List<String>> f = servers.stream().collect(Collectors.partitioningBy(s -> !s.startsWith("F")));
List<String> trues = f.get(Boolean.TRUE);
System.out.println("不以 F 开头的: " + trues);
List<String> falses = f.get(Boolean.FALSE);
System.out.println("以 F 开头的: " + falses);
Как правило, этот метод не рекомендуется для использования в этом сценарии и не соответствуетApiдизайнерский замысел.
6. Резюме
Сегодня мы изучили некоторыеCollections
Способы удаления элементов в , и их рассмотрение. Я не знаю, есть ли у вас какие-либо другие способы реализовать это, вы также можете передать общедоступную учетную запись:Felordcnскажите мне.
关注公众号:Felordcn获取更多资讯