- Работа с и удаление элемента из потока
- 2. Настроить
- 3. Фильтрация предметов
- 4. Управление и удаление предмета
- 4.1. Collection.removeIfс
- 4.2. Collection.removeAllс
- 5. Заключение
- Работа с элементом и его удаление из потока
- 2. Настройка
- 3. Фильтрация элементов
- 4. Управление и удаление элемента
- 4.1. Collection.removeIf
- 4.2. Коллекция.removeAll
- 5. Вывод
- Java – Remove/Update Elements From List using Stream
- how to remove object from stream in foreach method?
- 5 Answers 5
Работа с и удаление элемента из потока
В этом кратком руководстве мы узнаем о различных способах, которыми мы можем работать с элементом в потоке Java 8, а затем удалить его после завершения операции.
2. Настроить
Давайте сначала определим наш объектItem. Это простой объект с единственным полемint.
У него есть метод, который определяет, подходит ли объект для работы, на основе внутреннего значения:
class Item < private int value; // constructors public boolean isQualified() < return value % 2 == 0; >public void operate() < System.out.println("Even Number"); >>
Теперь мы можем создать источник для нашегоStream, который может быть коллекциейItems:
List itemList = new ArrayList<>(); for (int i = 0; i
3. Фильтрация предметов
Во многих случаях, если мы хотим что-то сделать с подмножеством элементов, мы можем использовать методStream#filter, и нам не нужно сначала ничего удалять:
itemList.stream() .filter(item -> item.isQualified()) .
4. Управление и удаление предмета
4.1. Collection.removeIfс
Мы можем использоватьStreams для итерации и работы с коллекциейItems.
ИспользуяStreams, мы можем применять лямбда-функции, известные какPredicates. Чтобы узнать больше оStreams иPredicates, у нас есть еще одна статьяhere.
Мы можем создатьPredicate, который будет определять, подходит лиItem для работы:
Predicate isQualified = item -> item.isQualified();
НашPredicate отфильтруетItems, с которыми мы хотим работать:
itemList.stream() .filter(isQualified) .forEach(item -> item.operate());
Когда мы закончим работу с элементами в потоке, мы можем удалить их, используя тот жеPredicate, который мы использовали ранее для фильтрации:
itemList.removeIf(isQualified);
Internally, removeIf uses an Iterator to iterate over the list and match the elements using the predicate. Теперь мы можем удалить любые совпадающие элементы из списка.
4.2. Collection.removeAllс
Мы также можем использовать другой список для хранения элементов, с которыми были оперированы, а затем удалить их из исходного списка:
List operatedList = new ArrayList<>(); itemList.stream() .filter(item -> item.isQualified()) .forEach(item -> < item.operate(); operatedList.add(item); >); itemList.removeAll(operatedList);
В отличие отremoveIf, который использует итератор,removeAll uses a simple for-loop to remove all the matching elements in the list.
5. Заключение
В этой статье мы рассмотрели способ работы с элементом в Java 8 Streams, а затем его удаление. Мы также нашли способ сделать это, используя дополнительный список и удалив все соответствующие элементы.
Исходный код этого руководства и соответствующие тестовые примеры доступныover on GitHub.
Работа с элементом и его удаление из потока
В этом кратком руководстве мы узнаем о различных способах работы с элементом в потоке Java 8, а затем удаляем его после завершения операции.
2. Настройка
Давайте сначала определим наш объект Item . Это простой объект с одним полем типа int .
У него есть метод, который определяет, подходит ли объект для работы, на основе внутреннего значения:
class Item private int value; // constructors public boolean isQualified() return value % 2 == 0; > public void operate() System.out.println("Even Number"); > >
Теперь мы можем создать источник для нашего потока , который может быть набором элементов:
ListItem> itemList = new ArrayList>(); for (int i = 0; i 10; i++) itemList.add(new Item(i)); >
3. Фильтрация элементов
Во многих случаях, если мы хотим что-то сделать с подмножеством элементов, мы можем использовать метод Stream#filter , и нам не нужно предварительно ничего удалять:
itemList.stream() .filter(item -> item.isQualified()) ...
4. Управление и удаление элемента
4.1. Collection.removeIf
Мы можем использовать Streams для итерации и работы с коллекцией Items .
Используя потоки , мы можем применять лямбда-функции, известные как предикаты . Чтобы узнать больше о потоках и предикатах , у нас есть другая статья здесь .
Мы можем создать предикат , который будет определять, подходит ли элемент для работы:
PredicateItem> isQualified = item -> item.isQualified();
Наш предикат будет фильтровать элементы , с которыми мы хотим работать:
itemList.stream() .filter(isQualified) .forEach(item -> item.operate());
После того, как мы закончили работу с элементами в потоке, мы можем удалить их, используя тот же предикат , который мы использовали ранее для фильтрации:
itemList.removeIf(isQualified);
Внутренне removeIf использует итератор для перебора списка и сопоставления элементов с помощью предиката. Теперь мы можем удалить любые соответствующие элементы из списка.
4.2. Коллекция.removeAll
Мы также можем использовать другой список для хранения элементов, над которыми мы работали, а затем удалить их из исходного списка:
ListItem> operatedList = new ArrayList>(); itemList.stream() .filter(item -> item.isQualified()) .forEach(item -> item.operate(); operatedList.add(item); >); itemList.removeAll(operatedList);
В отличие от removeIf , использующего итератор, removeAll использует простой цикл for для удаления всех совпадающих элементов в списке.
5. Вывод
В этой статье мы рассмотрели способ работы с элементом в Java 8 Streams и последующего его удаления. Мы также видели способ сделать это, используя дополнительный список и удаляя все соответствующие элементы.
Исходный код этого руководства и соответствующие тестовые примеры доступны на GitHub .
Java – Remove/Update Elements From List using Stream
Learn to remove and update elements of a Collection using Stream API in Java with examples. It is worth noting that each method shown below creates a new List, the original List is not modified after the processing.
1. Removing Elements using Stream
Removing the elements is very simple. We iterate over the Stream elements and filter out the elements that match a given Predicate passed to the Stream.filter() method.
In the following example, we are only selecting the employees whose names start with the character “A“. All other elements are removed from the stream.
List list = List.of( new Employee(1, "Alex", LocalDate.of(1990, 1, 2), 100d), new Employee(2, "Alok", LocalDate.of(1992, 1, 2), 200d), new Employee(3, "Brian", LocalDate.of(1994, 1, 2), 300d), new Employee(4, "Charles", LocalDate.of(1996, 1, 2), 400d)); List modifiedList = list.stream() .filter(e -> e.getName().startsWith("A")) .collect(Collectors.toList()); //Employees whose names start with "A" System.out.println(modifiedList);
[ Employee [id=1, name=Alex, dateOfBirth=1990-01-02, salary=100.0], Employee [id=2, name=Alok, dateOfBirth=1992-01-02, salary=200.0] ]
2. Updating Elements using Stream
To update all elements or the matching elements from the Stream, we use the Stream.map() method and return a new Employee instance. All modified instances are collected into a new List.
In the following example, we are updating the salary for all employees by 100. The modified elements are collected into newList.
List list = List.of( new Employee(1, "Alex", LocalDate.of(1990, 1, 2), 100d), new Employee(2, "Alok", LocalDate.of(1992, 1, 2), 200d), new Employee(3, "Brian", LocalDate.of(1994, 1, 2), 300d), new Employee(4, "Charles", LocalDate.of(1996, 1, 2), 400d)); List newList = list.stream() .map(e -> < e.setSalary(e.getSalary() + 100); return e; >) .collect(Collectors.toList()); System.out.println(newList);
[ Employee [id=1, name=Alex, dateOfBirth=1990-01-02, salary=200.0], Employee [id=2, name=Alok, dateOfBirth=1992-01-02, salary=300.0], Employee [id=3, name=Brian, dateOfBirth=1994-01-02, salary=400.0], Employee [id=4, name=Charles, dateOfBirth=1996-01-02, salary=500.0] ]
In this quick Java tutorial, we learned to remove the elements from List using Java 8 Stream.filter(). We also learned to update the elements of a Stream using Stream.map() method.
how to remove object from stream in foreach method?
i have to arrays: arrA and arrB . arrA and arrB are Lists of objectss of diffrent types and add function converts objects A to objects B . I want to add each object from arrA to arrB and remove that object from arrA. Im trying to do this by stream:
- not all objects are passed from arrA to arrB.
- after few iterations null pointer exception is thrown.
i gues it’s because length of array is decreased after each remove() call and the counter of iterations is increased (only objects under odd indexes are passed to arrB )
Now i could solve this by copying array in one stream call and then remove objects in second stream call but this doesnt seem correct for me.
What would be proper solution to this problem?
EDIT. Additional information: in real implementation this list if previously filtered
arrA.stream().filter(some condition).foreach(c -> );
and its called few times to add elements meeting diffrent conditions to diffrent lists ( arrC, arrD etc.) but each object can be only on one list
Is it necessary you add and remove the objects one by one? You can clone the whole list and clear the other with only one method call, you know?
Short and dirty: listA.removeIf(c -> someCondition && listB.add(c)); , works, because List.add always returns true .
5 Answers 5
Streams are designed to be used in a more functional way, preferably treating your collections as immutable.
The non-streams way would be:
However you might be using Streams so you can filter the input so it’s more like:
arrB.addAll(arrA.stream().filter(x -> whatever).toList())
then remove from arrA (thanks to @Holgar for the comment).
If your predicate is expensive, then you could partition:
Map lists = arrA.stream() .collect(Collectors.partitioningBy(x -> whatever)); arrA = lists.get(false); arrB = lists.get(true);
or make a list of the changes:
List toMove = arrA.stream().filter(x->whatever).toList(); arrA.removeAll(toMove); arrB.addAll(toMove);
+1 for your last «list of changes». This seems to get closest to what OP wants. Everything else seems to not directly do what OP wants or seems less efficient.
@Martin Nyolt: actually, there is nothing worse than the “list of changes” approach. The time complexity of the removeAll will be n×m, up to quadratic if all elements match the filter.
The partitioningBy approach deserves my +1. As an addendum, if arrA is mutable (as the initial remove approach suggests), arrA = arrA.stream().filter(x -> whatever).toList() can be replaced with arrA.removeIf(x -> !whatever); …
removeAll being n×m: good point, didn’t thought about that. Making it linear is surely possible, as the order is the same in both toMove and arrA — but that’s probably not worth the effort compared to other approaches.
As the others have mentioned, this is not possible with foreach — as it is impossible with the for (A a: arrA) loop to remove elements.
In my opinion, the cleanest solution is to use a plain for while with iterators — iterators allow you to remove elements while iterating (as long as the collection supports that).
This also saves you from copying/cloning arrA .
I prefer this solution. I believe streams are good as long as I don’t need to fight them to achieve what I need.
I don’t think you can remove from arrA while you iterate over it.
You can get around this by wrapping it in a new ArrayList<>();
i guess it’s because length of array is decreased after each remove() call and the counter of iterations is increased
Right. the for-each-loop is just like a normal for-loop, but easier to write and read. You can think of it as syntactic sugar. Internally it will either use an Iterator or array indices. The forEach method of streams is a more fancy version of it that allows parallel execution and functional coding style, but has its own drawbacks.
As with any indexed loop, removing an element while looping breaks the loop. Consider having three elements with indices 0, 1, and 2. When you remove element 0 in the first iteration, the list items will shift one up and the next iteration you’ll have elements 0 (previously 1) and 1 (previously 2). Your loop variable now points to 1, so it skips the actually next item. When it gets to index 2 the loop you’re working on only has one item left (you removed two), which throws an error because the index is out of bounds.
- Use the List methods for cloning and clearing lists.
- Do it with two loops if you really need to call the methods on each single item.