Home > Mobile >  Java-Stream - Combine results of two methods producing a Value and a List invoked conditionaly insid
Java-Stream - Combine results of two methods producing a Value and a List invoked conditionaly insid

Time:11-21

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());
  • Related