【问题标题】:Java 8 : getting default values for a collection with nested OptionalsJava 8:使用嵌套的 Optionals 获取集合的默认值
【发布时间】:2017-02-02 18:02:36
【问题描述】:

here,有一种方法可以获取嵌套Optional 的值或默认值:

Optional<Computer> maybeComputer = Optional.of(computer);
String version = maybeComputer.flatMap(Computer::getSoundcard).flatMap(Soundcard::getUsb).map(USB::getVersion).orElse("UNKNOWN");

Computer computer = ...;
String version = computer.getSoundcard().flatMap(Soundcard::getUsb).map(USB::getVersion).orElse("UNKNOWN");

但是,我如何获得所有收藏计算机的所有版本? - List&lt;Computer&gt;

例如,如何使用stream API 打印所有USB 版本,包括unknown

如何将所有计算机映射到其声卡的 USB 版本,包括 unknown 的?

谢谢。

计算机类:

public static class Computer {
    private Optional<Soundcard> soundcard;

    public Computer(Optional<Soundcard> soundcard) {
        this.soundcard = soundcard;
    }

    public Optional<Soundcard> getSoundcard() {
        return soundcard;
    }
}

public static class Soundcard {
    private Optional<USB> usb;

    public Soundcard(Optional<USB> usb) {
        this.usb = usb;
    }

    public Optional<USB> getUsb() {
        return usb;
    }
}

public static class USB {
    private String version;

    public String getVersion() {
        return version;
    }
}

【问题讨论】:

  • List&lt;Computer&gt; 中没有 Optional。你到底想做什么?
  • @Tunaki - 添加了Computer 类定义。

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


【解决方案1】:

只需流式传输计算机列表,然后将与您应用于单个 Optional&lt;Computer&gt; 的映射相同的映射应用于每台计算机:

List<String> versions =
    computers.stream()
             .map(c -> Optional.ofNullable(c) // takes care of null elements in your List
                               .flatMap(Computer::getSoundcard)
                               .flatMap(Soundcard::getUsb)
                               .map(USB::getVersion)
                               .orElse("UNKNOWN"))
             .collect(Collectors.toList());

【讨论】:

  • 出于可读性目的,我建议将该 lambda 移动到一个单独的方法中。
  • @eran,有没有办法处理主管道中的子值?当前解决方案处理与主管道断开连接的子值。您创建了一个子管道。
  • @AlikElzin-kilaka 这段代码中只有一个 Stream 管道。传递给 map 方法的 lambda 表达式不是 Stream 管道。它只对 Stream 的单个元素进行操作,因此不能合并到 Stream 管道中。
【解决方案2】:

如果您想使用 Stream API 而不是 Optional API 执行这些步骤,您可以使用

computers.stream()
         .filter(Objects::nonNull)
         // Java 9: .flatMap(c -> c.getSoundcard().stream())
         .flatMap(c -> c.getSoundcard().map(Stream::of).orElseGet(Stream::empty))
         // Java 9: .flatMap(s -> s.getUSB().stream())
         .flatMap(s -> s.getUsb().map(Stream::of).orElseGet(Stream::empty))
         .map(USB::getVersion)
         .forEach(System.out::println);

不同之处在于它将跳过缺少的值,而不是用默认值 ala "UNKNOWN" 替换它们。无论如何,为属性“声卡的 USB 版本”生成一个备用值 "UNKNOWN" 是有问题的,这实际上可能意味着“不是 USB 设备”或“没有声卡存在”......

如果要保持原有逻辑,则必须通过流管道携带Optionals,以便保留有关存在或不存在的信息:

computers.stream()
         .map(Optional::ofNullable)
         .map(oc -> oc.flatMap(Computer::getSoundcard))
         .map(os -> os.flatMap(Soundcard::getUsb))
         .map(os -> os.map(USB::getVersion))
         .map(ou -> ou.orElse("UNKNOWN"))
         .forEach(System.out::println);

这只是Eran’s answer 的分解版本。请注意,这不一定比只使用null 更简单:

computers.stream()
         .map(c -> c==null? null: c.getSoundcard().orElse(null))
         .map(s -> s==null? null: s.getUsb().orElse(null))
         .map(u -> u==null? "UNKNOWN": u.getVersion())
         .forEach(System.out::println);

【讨论】:

    猜你喜欢
    • 2019-03-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-08-20
    • 1970-01-01
    相关资源
    最近更新 更多