Java 8:使用嵌套的Optionals获取集合的默认值

时间:2016-09-25 09:02:57

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

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<Computer>

例如,如何使用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;
    }
}

2 个答案:

答案 0 :(得分:4)

只需对计算机列表进行流式处理,然后将适用于单个Optional<Computer>的映射应用于每个计算机:

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

答案 1 :(得分:0)

如果您想使用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"替换它们。无论如何,为“Soundcard的USB版”属性产生一个回落值"UNKNOWN"是值得怀疑的,这实际上可能意味着“不是USB设备”或“没有声卡存在”...

如果您想保留原始逻辑,则必须通过流管道携带Optional s,以便保留有关是否存在的信息:

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);
相关问题