Может ли Java 8 Streams работать с элементом в коллекции, а затем удалить его?
как и почти все, я все еще изучаю тонкости (и люблю их) нового API Java 8 Streams. У меня есть вопрос относительно использования потоков. Я приведу упрощенный пример.
Java Streams позволяет нам взять Collection
, и использовать stream()
метод на нем, чтобы получить поток всех его элементов. В нем есть ряд полезных методов, таких как filter()
,map()
и forEach()
, которые позволяют нам использовать лямбда-операции на содержание.
у меня есть код, который выглядит примерно так (упрощенно):
set.stream().filter(item -> item.qualify())
.map(item -> (Qualifier)item).forEach(item -> item.operate());
set.removeIf(item -> item.qualify());
идея состоит в том, чтобы получить отображение всех элементов в наборе, которые соответствуют определенному квалификатору, а затем работать через них. После операции они больше не служат никакой цели и должны быть удалены из исходного набора. Код работает хорошо, но я не могу избавиться от ощущения, что есть операция в Stream
это может сделать это для меня, в одной строке.
если он находится в Документации, я может быть с видом на него.
кто - нибудь более знаком с API видит что-то подобное?
8 ответов:
вы можете сделать это так:
set.removeIf(item -> { if (!item.qualify()) return false; item.operate(); return true; });
если
item.operate()
всегда возвращаетtrue
вы можете сделать это очень емко.set.removeIf(item -> item.qualify() && item.operate());
однако мне не нравятся эти подходы, так как не сразу понятно, что происходит. Лично я бы продолжал использовать
for
петли иIterator
для этого.for (Iterator<Item> i = set.iterator(); i.hasNext();) { Item item = i.next(); if (item.qualify()) { item.operate(); i.remove(); } }
в одной строке нет, но, возможно, вы могли бы использовать
partitioningBy
взыскатель:Map<Boolean, Set<Item>> map = set.stream() .collect(partitioningBy(Item::qualify, toSet())); map.get(true).forEach(i -> ((Qualifier)i).operate()); set = map.get(false);
это может быть более эффективным, поскольку он позволяет избежать повторения набора два раза, один для фильтрации потока, а затем один для удаления соответствующих элементов.
в противном случае я думаю, что ваш подход относительно хорош.
то, что вы действительно хотите сделать, это разделить свой набор. К сожалению, в Java 8 разделение возможно только с помощью терминального метода "collect". Вы в конечном итоге с чем-то вроде этого:
// test data set Set<Integer> set = ImmutableSet.of(1, 2, 3, 4, 5); // predicate separating even and odd numbers Predicate<Integer> evenNumber = n -> n % 2 == 0; // initial set partitioned by the predicate Map<Boolean, List<Integer>> partitioned = set.stream().collect(Collectors.partitioningBy(evenNumber)); // print even numbers partitioned.get(true).forEach(System.out::println); // do something else with the rest of the set (odd numbers) doSomethingElse(partitioned.get(false))
обновление:
Scala версия кода выше
val set = Set(1, 2, 3, 4, 5) val partitioned = set.partition(_ % 2 == 0) partitioned._1.foreach(println) doSomethingElse(partitioned._2)`
существует множество подходов. Если использовать myList.удалить (элемент) должен переопределить equals (). Второе, что я предпочитаю:
allList.removeIf(item -> item.getId().equals(elementToDelete.getId()));
удачи и счастливого кодинга :)
нет, ваша реализация, вероятно, самая простая. Вы можете сделать что-то глубоко злое, изменив состояние в
removeIf
сказуемое, но, пожалуйста, не. С другой стороны, это может быть разумнее вообще переключиться на итератор на основе императива реализации, который может быть более подходящей и эффективной для данного варианта использования.
если я правильно понял ваш вопрос:
set = set.stream().filter(item -> { if (item.qualify()) { ((Qualifier) item).operate(); return false; } return true; }).collect(Collectors.toSet());
после операции они больше не служат никакой цели и должны быть удалены из исходного набора. Код работает хорошо, но я не могу избавиться от ощущения, что есть операция в потоке, которая может сделать это для меня, в одной строке.
вы не можете удалить элементы из исходного потока с потоком. Из документация:
большинство операций потока принимают параметры, описывающие поведение, заданное пользователем..... Чтобы сохранить правильное поведение, эти поведенческие параметры:
- должны быть без помех (они не изменяют источник потока); и
- в большинстве случаев должны быть без гражданства (их результат не должен зависеть от любого государства, которое может измениться во время выполнения потока).