【问题标题】:java lambda - how to traverse optional list/stream of optionalsjava lambda - 如何遍历可选列表/可选流
【发布时间】:2019-01-11 02:07:42
【问题描述】:

有一个 Optional 的可选列表:

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

如何遍历optionalList打印出字符串的ONETWO

如果有一个可选的可选流呢?

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

更新:感谢您的回答, optionalStream 的解决方案(非嵌套):

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

【问题讨论】:

  • 到目前为止你有什么尝试?
  • 您也可以只将Optional 映射到Stream,而不是检查isPresent 并自己明确获取值。会更“实用风格”。
  • 您应该避免将Optional 存储在集合中,请参阅Uses for OptionalIs it Worth it to Use 'Optional' in Collections?
  • @DidierL true,但是对于 Stream&lt;Optional&lt;T&gt;&gt; 的情况,这仍然是一个有效的练习,当您的集合中的项目通过其他一些函数映射到 Optional&lt;T&gt; 时,这种练习更为常见,所以你最终得到一个Stream&lt;Optional&lt;T&gt;&gt;,然后你想要过滤并转换为Stream&lt;T&gt;
  • 确实,对我来说这也是一个有效的案例。请注意,Java 9 中引入了 Optional.stream() 方法来避免这种情况(与 flatMap() 结合使用)。最后,我也会避免使用Optional&lt;List&gt;Optional&lt;Stream&gt;,因为它们不太友好。尽可能使用空列表/流,因为这会使 API 更加简洁。

标签: java lambda java-8 java-stream optional


【解决方案1】:

首先,检查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));

【讨论】:

  • 添加.map(Optional::get) 将打印字符串
【解决方案2】:

如果你可以使用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));

对于Optionals 中的Stream,它看起来像这样:

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

【讨论】:

  • 尝试了省略第一个 .stream() 调用的选项流 - 但不起作用(java 8)
  • 你是什么意思不起作用?刚试了Java 8版本,第一行替换为:optionalStream.ifPresent(stream -&gt; stream肯定可以。
【解决方案3】:

您确实可以流式传输Option&lt;String&gt; 并仅过滤非空值。

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

我个人更喜欢第一种方式,因为它消除了嵌套级别:我觉得阅读起来更愉快。

【讨论】:

  • 如果列表不存在,第一种方法将创建一个空的ArrayList
  • 没错。但是在流执行范围内创建一个空的ArrayList 也没有任何成本。
  • 我手边没有 IDE,但flatMap 不会满足所有isPresent 检查的需求吗?
  • @chrylis 是的。所有这些答案都太臃肿了,只要将列表中的Optional 项目转换为StreamflatMap 即可。
【解决方案4】:

我看到有两种方法,第二种对我来说看起来更漂亮,看看:

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】:

    嗯……

    1. 检查是否存在可选列表。
    2. 对(现在存在的)列表的所有元素执行“for each”。
    3. 在每个步骤中检查是否存在可选字符串。
    4. 如果是,请打印。

    单线可以做到这一点:

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

    【讨论】:

      【解决方案6】:
      optionalList.stream().flatMap(List::stream).filter(Objects::nonNull).forEach(...)
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2017-09-08
        • 1970-01-01
        • 1970-01-01
        • 2011-08-05
        • 2011-03-16
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多