Say that we have a 3-dimensional List of Objects.
class Custom {
int id;
List<String> list;
Custom(int id, List<String> list) { /* Constructor */ }
// Getters and Setters
}
class CustomContainer {
int id;
List<Custom> list;
CustomContainer(int id, List<Custom> list) { /* Constructor */ }
// Getters and Setters
}
var l1 = List.of("abc", "def", "acd");
var l2 = List.of("bed", "fed", "aed");
var c1 = new Custom(1, l1);
var c2 = new Custom(2, l2);
var l3 = List.of(c1, c2);
var l4 = List.of(c2);
var cc1 = new CustomContainer(3, l3);
var cc2 = new CustomContainer(4, l4);
var containers = List.of(cc1, cc2);
Say that I want to filter "containers" such that I want to remove all elements from the inner most list that start with "a".
So, the output should be (considering that the toString()
prints only the strings in the list):
[[["def"],["bed", "fed"]], [["bed", "fed"]]]
How can I get this using streams in Java?
Since you have to work on the innermost collection, while needing to collect the outermost elements, you could stream the List
of CustomContainer
and then invoke the methods forEach
and removeIf
on each element of the list.
In my original answer, I used the intermediate operation peek
. However, this method should mostly be used for debugging purposes.
This method exists mainly to support debugging
List<CustomContainer> res = containers.stream()
.peek(container -> container.getList().forEach(custom -> custom.getList().removeIf(str -> str.startsWith("a"))))
.collect(Collectors.toList());
An alternative and more viable solution could employ the map
method.
List<CustomContainer> res = containers.stream()
.map(container -> {
container.getList().forEach(custom -> custom.getList().removeIf(str -> str.startsWith("a")));
return container;
})
.collect(Collectors.toList());
I assume that in your snippet you've used List.of()
for brevity. However, the method returns an immutable list and any attempt of modification will throw an UnsupportedOperationException
. You might want to write your code as follows, relying on the conversion constructor of the ArrayList
class:
var l1 = new ArrayList(List.of("abc", "def", "acd")); //Conversion constructor
var l2 = new ArrayList(List.of("bed", "fed", "aed")); //Conversion constructor
var c1 = new Custom(1, l1);
var c2 = new Custom(2, l2);
var l3 = new ArrayList(List.of(c1, c2)); //Conversion constructor
var l4 = new ArrayList(List.of(c2)); //Conversion constructor
var cc1 = new CustomContainer(3, l3);
var cc2 = new CustomContainer(4, l4);
var containers = new ArrayList<>(List.of(cc1, cc2)); //Conversion constructor