1

What is the difference between Optional.flatMap() and Stream.flatMap().

Correct flatMap on Stream:

    List<ObjectDTO> collect = types.stream()
            .flatMap(a -> client.getSthById(new URI(a)).stream())
            .collect(Collectors.toList());

Exception while using flatMap on Optional:

        List<ObjectDTO> collect2 = client.getSthByObj(obje.get(), null).getBrowse()
                .flatMap(uri -> client.getSthById(uri).stream())
                .collect(Collectors.toList());

Why can't I use it in the same way?

Jakub
  • 69
  • 7
  • 2
    what are you asking? this is really unclear, and did you read the docs and numerous other posts here about one and the other? – Eugene Jun 26 '18 at 10:47
  • 2
    They perform very similar operations, hence the same name. The main difference is that one requires an `Optional` and a method that returns an `Optional` while the other requires a `Stream` and a method that returns a `Stream`. – Ole V.V. Jun 26 '18 at 11:12
  • 1
    Could you elaborate your examples into [MCVE](https://stackoverflow.com/help/mcve)? That would help. – Ole V.V. Jun 26 '18 at 11:14
  • Also the stacktrace from the exception that you say that you get would be helpful. – Ole V.V. Jun 27 '18 at 10:56
  • 1
    It would be good that you clarify your question to indicate exactly what you are trying to do, and give self-sufficient code snippets that show your problem ([mcve]). Even if you already got your answer, that will be helpful for future readers. – Didier L Jun 27 '18 at 12:26

3 Answers3

2

Optional and Stream are two different beasts intended for separated purposes.

Optional is a wrapper that holds a result that can be or not be "present" (null) and provided methods to deal which these two conditions (present, or Not Present).

The flatMap() operation is an operation applied to the value held in your Optional wrapper. That operation must return an Optional as a result:

Optional<String> s = Optional.of("test input");
s.flatMap( input -> Optional.of(input));

Stream's flatMap() helps you to get and process nested elements of list elements.


Additional reading

informatik01
  • 16,038
  • 10
  • 74
  • 104
arthur
  • 3,245
  • 4
  • 25
  • 34
1

It’s hard to be sure from your code snippets where we don’t know the types of the variables you use nor the return types of the methods. But I think that the source of your error is that you are trying to pass a lambda that returns a Stream to Optional.flatMap().

Let’s look at Stream first. Stream.flatMap() takes a function that returns a Stream. This seems to be exactly what you are giving it in your first code snippet.

Optional on the other hand: Optional.flatMap() requires a function that returns an Optional. If getBrowse() returns an Optional, then what you pass to Optional.flatMap is uri -> physicalInventoryClient.getSublocationsByIds(uri).stream(). This looks like your lambda returns a stream, not an Optional. When I try the same in my Eclipse, I get a compile error like the following:

The method flatMap(Function<? super String,? extends Optional<? extends U>>) in the type Optional<String> is not applicable for the arguments ((Object x) -> {})

The solution? From Java 9 Optional has a stream method that will probably let you achieve what you are trying. Again, without knowing your code it’s hard to suggest, but probably something like:

    List<SublocationBrowseDTO> collect2 = physicalInventoryClient.getSublocationsByLocation(masterLocation.get(), null)
            .getBrowse()
            .stream()
            .flatMap(uri -> physicalInventoryClient.getSublocationsByIds(uri).stream())
            .collect(Collectors.toList());

Edit: Alternative without stream:

    List<SublocationBrowseDTO> collect2 = physicalInventoryClient.getSublocationsByLocation(masterLocation.get(), null)
            .getBrowse()
            .map(uri -> physicalInventoryClient.getSublocationsByIds(uri))
            .orElse(Collections.emptyList());

The latter version requires that getSublocationsById() returns a list, but can probably be modified to work if the return type is something else. IMHO it’s a bit simpler.

Ole V.V.
  • 81,772
  • 15
  • 137
  • 161
  • Excuse me, that was my first question in stackoverflow. This answer fulfills my expectations. Thank you so much! – Jakub Jun 27 '18 at 11:49
  • We’re all learning. And yes, it takes a bit to learn how to use this site. Welcome! BTW I thought of a different solution and added it to the answer. – Ole V.V. Jun 27 '18 at 13:51
0

From the javadoc: Optional.flatMap:

flatMap(Function<? super T,Optional<U>> mapper)

If a value is present, apply the provided Optional-bearing mapping function to it, return that result, otherwise return an empty Optional.

Stream.flatMap:

flatMap(Function<? super T,? extends Stream<? extends R>> mapper)

Returns a stream consisting of the results of replacing each element of this stream with the contents of a mapped stream produced by applying the provided mapping function to each element.

So the main difference is, that one returns a Stream, the other an Optional

keuleJ
  • 3,418
  • 4
  • 30
  • 51