java lambda - how to traverse optional list/stream of optionals

27,106

Solution 1

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));

Solution 2

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));

Solution 3

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.

Solution 4

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;
    }
}

Solution 5

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)));
Share:
27,106
Sara Vino
Author by

Sara Vino

Updated on July 09, 2022

Comments

  • Sara Vino
    Sara Vino almost 2 years

    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);
    
  • Sara Vino
    Sara Vino over 5 years
    adding a .map(Optional::get) will print the string
  • jbx
    jbx over 5 years
    The first way will create an empty ArrayList for nothing if the list does not exist.
  • davidxxx
    davidxxx over 5 years
    It is right. But creating an empty ArrayList living in the scope of a stream execution costs also nothing.
  • Sara Vino
    Sara Vino over 5 years
    tried for a stream of optionals omitting first .stream() call - but not working (java 8)
  • chrylis -cautiouslyoptimistic-
    chrylis -cautiouslyoptimistic- over 5 years
    I don't have an IDE handy, but wouldn't a flatMap squash the need for all of the isPresent checks?
  • jbx
    jbx over 5 years
    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.
  • jbx
    jbx over 5 years
    @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.