Skip to content

Instantly share code, notes, and snippets.

@simonwoo
Last active January 6, 2016 09:54
Show Gist options
  • Select an option

  • Save simonwoo/00ecc984b4b50c14a52f to your computer and use it in GitHub Desktop.

Select an option

Save simonwoo/00ecc984b4b50c14a52f to your computer and use it in GitHub Desktop.

背景

------------------------
|       computer       |
| -------------------- |
| |     soundcard    | |
| | ---------------- | |
| | |     USB      | | |
| | | ------------ | | |
| | | | version  | | | |
| | | ------------ | | |
| | ---------------- | |
| -------------------- |
------------------------

让我们以电脑的结构为例,说明Optional的使用。电脑通常情况下包含声卡,声卡里包含USB,每个USB有对应的版本号。 如果想获得声卡中USB的版本号,我们通常使用以下方法:

String version = computer.getSoundcard().getUSB().getVersion();

这段代码有潜在的风险。某些情况下,电脑也不一定具备声卡,如Raspberry Pi(树莓派)。所以getSoundcard()有可能返回一个null值。getUSB()则返回一个null值得USB,这会导致运行期抛出NullPointerException。为了阻止这种情况的发生,我们经常会进行null值检查:

String version = UNKNOWN;
if(computer != null){
  Soundcard soundcard = computer.getSoundcard();
  if(soundcard != null){
    USB usb = soundcard.getUSB();
    if(usb != null){
      version = usb.getVersion();
    }
  }
}

由于多重嵌套进行null坚持,这段代码非常丑陋。让我们看看Optional是怎么完成相同的功能:

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

Optional使用

创建Optional对象

Optional<Soundcard> sc = Optional.empty(); //an empty Optional object

SoundCard soundcard = new Soundcard();
Optional<Soundcard> sc = Optional.of(soundcard); //an non-null Optional object

Optional<Soundcard> sc = Optional.ofNullable(soundcard); // an Optional object that may hold a null value

操作对象

Optional<Soundcard> soundcard = ...;
soundcard.ifPresent(System.out::println);

Soundcard soundcard = maybeSoundcard.orElse(new Soundcard("defaut"));

Soundcard soundcard = maybeSoundCard.orElseThrow(IllegalStateException::new);

/**
* The filter method takes a predicate as an argument. 
* If a value is present in the Optional object and it matches the predicate, the filter method returns that value;
* otherwise, it returns an empty Optional object.
*/
Optional<USB> maybeUSB = ...;
maybeUSB.filter(usb -> "3.0".equals(usb.getVersion())
                    .ifPresent(() -> System.out.println("ok"));

// extracting and transforming values using map, nothing happens if Optional object is empty                  
Optional<USB> usb = maybeSoundcard.map(Soundcard::getUSB);      

/**
* Optional also supports a flatMap method. 
* Its purpose is to apply the transformation function on the value of an Optional (just like the map operation does) and then flatten the * resulting two-level Optional into a single one
*/
String version = computer.flatMap(Computer::getSoundcard)
                   .flatMap(Soundcard::getUSB)
                   .map(USB::getVersion)
                   .orElse("UNKNOWN");
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment