I have two methods: funca()
and funcb()
which return a value of type X
or a List<X>
respectively like shown below:
X funca(Event e) { ... }
List<X> funcb(Event e) { ... }
I want to use them in the Stream and collect the result into a list.
These method methods should be called under different conditions, like shown below in pseudocode:
List<Event> input = // initializing the input
List<X> resultList = input.values().stream()
.(event -> event.status=="active" ? funca(event) : funcb(event))
.collect(Collectors.toList());
Can someone please tell me how I can achieve this so that whether the function returns a list of values or values?
CodePudding user response:
Since one of your functions produces a Collection as a result, you need a stream operation that allows performing one-to-many transformation. For now, Stream IPA offers two possibilities: flatMap()
and mapMulti()
.
To approach the problem, you need to take a closer look at them and think in terms of these operations.
flatMap()
This operation requires a function producing a Stream
, and elements of this new stream become a replacement for the initial element.
Therefore, you need to wrap the result returned by the funca()
with Singleton-Stream using Stream.of()
(there's no need for wrapping the element with a List
, like shown in another answer flatMap()
is not capable to consume Collections).
List<X> = input.values().stream()
.flatMap(event -> "active".equals(event.getStatus()) ?
Stream.of(funca(event)) : funcb(event).stream()
)
.toList(); // for Java 16 or collect(Collectors.toList())
mapMulti()
This operation was introduced with Java 16 and is similar to flatMap()
but acts differently.
Contrary to flatMap
it doesn't consume a new Stream. As an argument it expects a BiConsumer
. Which in turn takes a stream element and a Consumer
of the resulting type. Every element offered to the Consumer
becomes a part of the resulting stream.
mapMulti()
might be handy if funcb()
produces a list which is very moderate in size (refer to documentation linked above for more details), otherwise flatMap()
would be the right tool.
List<X> = input.values().stream()
.<X>mapMulti((event, consumer) -> {
if ("active".equals(event.getStatus())) consumer.accept(funca(event));
else funcb(event).forEach(consumer);
})
.toList(); // for Java 16 or collect(Collectors.toList())
Sidenote: don't use ==
to compare reference types (like String
) unless you need to make sure that both references are pointing to the same object, use equals()
method instead.
CodePudding user response:
Embed the result of funcA
into a list and flatMap
the lists:
List<X> result = input.stream()
.flatMap(e -> e.status.equals("active") ? List.of(funcA(e)) : funcB(e))
.collect(Collectors.toList());