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

£可爱£侵袭症+ 提交于 2019-12-22 10:34:18

问题


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

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



回答2:


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.




回答3:


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



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



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


来源:https://stackoverflow.com/questions/51668246/java-lambda-how-to-traverse-optional-list-stream-of-optionals

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!