22

Having an Optional List of Optional's like:

Optional<List<Optional<String>>> optionalList = Optional.of(
    Arrays.asList(
        Optional.empty(),
        Optional.of("ONE"),
        Optional.of("TWO")));

How to traverse optionalList to print out the string's ONE and TWO ?

What about having an Optional Stream of Optionals?

Optional<Stream<Optional<String>>> optionalStream = Optional.of(
    Stream.of(
        Optional.empty(),
        Optional.of("ONE"),
        Optional.of("TWO")));

Update: Thanks for answers, solution for optionalStream (non nested):

optionalStream
    .orElseGet(Stream::empty)
    .filter(Optional::isPresent)
    .map(Optional::get)
    .forEach(System.out::println);
6
  • 1
    What have you tried so far? Commented Aug 3, 2018 at 8:22
  • You can also just map the Optional to a Stream instead of checking isPresent and getting the value yourself explicitly. Will be a bit more 'functional style'. Commented Aug 3, 2018 at 9:12
  • You should avoid storing Optional in collections, see Uses for Optional and Is it Worth it to Use 'Optional' in Collections? Commented Aug 3, 2018 at 14:04
  • @DidierL true, however this is still a valid exercise for the case of Stream<Optional<T>> which is much more common when the items in your collection are being mapped to an Optional<T> by some other function, so you end up with a Stream<Optional<T>>, which you then want to filter and convert to a Stream<T>. Commented Aug 3, 2018 at 15:33
  • Indeed, for me this was a valid case as well. Note that there is an Optional.stream() method introduced in Java 9 to avoid that (to combine with flatMap()). Finally, I would also avoid Optional<List> and Optional<Stream> as they are not very friendly to work with. Use empty lists/streams instead whenever possible as this makes far cleaner API's. Commented Aug 3, 2018 at 16:02

6 Answers 6

15

First, check if the Optional is present. If yes, then stream the list and filter the non-empty ones and print each of them.

optionalList.ifPresent(list -> list.stream()
            .filter(Optional::isPresent)
            .map(Optional::get)
            .forEach(System.out::println));

Almost similar for the stream case too

optionalStream.ifPresent(stream -> stream
            .filter(Optional::isPresent)
            .map(Optional::get)
            .forEach(System.out::println));
Sign up to request clarification or add additional context in comments.

1 Comment

adding a .map(Optional::get) will print the string
12

If you can use Java 9, it can be done like this:

optionalList.ifPresent(list -> list.stream()
  .flatMap(Optional::stream)
  .forEach(System.out::println));

For a stream of optionals it would be the same, without the first .stream() call.

With Java 8 you don't have the Optional::stream method available so you can do it yourself:

optionalList.ifPresent(list -> list.stream()
  .flatMap(opt -> opt.map(Stream::of).orElseGet(Stream::empty))
  .forEach(System.out::println));

And for a Stream of Optionals it would look like this:

optionalStream.ifPresent(stream -> stream
  .flatMap(opt -> opt.map(Stream::of).orElseGet(Stream::empty))
  .forEach(System.out::println));

2 Comments

tried for a stream of optionals omitting first .stream() call - but not working (java 8)
What do you mean doesn't work? Just tried the Java 8 version, with the first line replaced to: optionalStream.ifPresent(stream -> stream definitely works.
11

You can indeed stream the Option<String> and filter only non empty values.

Optional<List<Optional<String>>> optionalList = Optional.of(Arrays.asList(Optional.empty(), Optional.of("ONE"), Optional.of("TWO")));

optionalList.orElseGet(ArrayList::new)
            .stream()
            .filter(Optional::isPresent)
            .map(Optional::get)           
            .forEach(System.out::println);

You can also use Optional.ifPresent() as suggested in another answers :

optionalList.ifPresent(l -> l.stream()
                             .filter(Optional::isPresent)
                             .map(Optional::get)                               
                             .forEach(System.out::println));

Personally I prefer the first way because it removes a nested level : I find it more pleasant to read.

4 Comments

The first way will create an empty ArrayList for nothing if the list does not exist.
It is right. But creating an empty ArrayList living in the scope of a stream execution costs also nothing.
I don't have an IDE handy, but wouldn't a flatMap squash the need for all of the isPresent checks?
@chrylis Yes. All these answers are so bloated, when all one needs to do is convert the Optional items in the list to a Stream and flatMap to it.
8
optionalList.stream().flatMap(List::stream).filter(Objects::nonNull).forEach(...)

1 Comment

This version is nice because it avoids the creation of an empty list and skips right to the empty stream (but is only possible in Java 9+ when Optional.stream was introduced).
3

As I see there are two ways, second one look a bit more pretty to me, take a look:

class Scratch {
    public static void main(String[] args) {
        Optional<String> element1 = Optional.of("test1");
        Optional<String> element2 = Optional.empty();
        Optional<String> element3 = Optional.of("test2");
        Optional<String> element4 = Optional.of("test3");
        List<Optional<String>> list = Arrays.asList(element1, element2, element3, element4);

        System.out.println(extractStrings1(list));
        System.out.println(extractStrings2(list));
    }

    private static List<String> extractStrings1(List<Optional<String>> list) {
        return list.stream()
                .filter(Optional::isPresent)
                .map(Optional::get)
                .collect(Collectors.toList());
    }

    private static List<String> extractStrings2(List<Optional<String>> list) {
        List<String> result = new ArrayList<>();
        list.forEach(element -> element.ifPresent(result::add));
        return result;
    }
}

Comments

2

Well ...

  1. Check whether the optional list is present.
  2. Do a "for each" for all elements of the (now present) list.
  3. In each step check whether the optional string is present.
  4. If yes, print it.

A one-liner can do that:

optionalList.ifPresent(list -> list.forEach(s -> s.ifPresent(System.out::println)));

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.