Java лямбда - как пройти необязательный список / поток опционных

Наличие необязательного списка необязательных, таких как:

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

Как пройти optionalList распечатать строку ONE а также TWO?

Как насчет того, чтобы иметь опциональный поток опций?

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

Обновление: Спасибо за ответы, решение для AdditionalStream (не вложенное):

optionalStream
    .orElseGet(Stream::empty)
    .filter(Optional::isPresent)
    .map(Optional::get)
    .forEach(System.out::println);

4 ответа

Решение

Во-первых, проверьте, если Optional настоящее. Если да, то выполните потоковую передачу списка и отфильтруйте непустые и напечатайте каждый из них.

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

Почти одинаково для случая потока

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

Вы действительно можете течь Option<String> и фильтровать только непустые значения.

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

Вы также можете использовать Optional.ifPresent() как предложено в других ответах:

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

Лично я предпочитаю первый способ, потому что он удаляет вложенный уровень: он мне удобнее читать.

Если вы можете использовать Java 9, это можно сделать так:

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

Для потока опций было бы то же самое, без первого .stream() вызов.

С Java 8 у вас нет Optional::stream метод доступен, так что вы можете сделать это самостоятельно:

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

И для Stream из Optionals это будет выглядеть так:

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

Как я вижу, есть два способа, второй кажется мне немного красивее, взгляните:

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

Что ж...

  1. Проверьте наличие дополнительного списка.
  2. Сделайте "для каждого" для всех элементов (теперь присутствующих) списка.
  3. На каждом шаге проверяйте наличие необязательной строки.
  4. Если да, распечатайте его.

Однострочник может сделать это:

optionalList.ifPresent(list -> list.forEach(s -> s.ifPresent(System.out::println)));
Другие вопросы по тегам