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
из Optional
s это будет выглядеть так:
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;
}
}
Что ж...
- Проверьте наличие дополнительного списка.
- Сделайте "для каждого" для всех элементов (теперь присутствующих) списка.
- На каждом шаге проверяйте наличие необязательной строки.
- Если да, распечатайте его.
Однострочник может сделать это:
optionalList.ifPresent(list -> list.forEach(s -> s.ifPresent(System.out::println)));