Java8:Optional類的解析

Optional類的Javadoc描述如下:
Optional 類是一個可以爲null的容器對象。如果值存在則isPresent()方法會返回true,調用get()方法會返回該對象。

Optional 是個容器:它可以保存類型T的值,或者僅僅保存null。Optional提供很多有用的方法,這樣我們就不用顯式進行空值檢測。
Optional 類的引入很好的解決空指針異常。

Java 8 Optional 優點:

  • 不需要檢查對象是否爲空;
  • 在運行時不再有NullPointerException;
  • 我們可以開發乾淨整潔的API,減少代碼量。

Optional.of()
爲非null的值創建一個Optional。

Optional.ofNullable() ofNullable與of方法相似,唯一的區別是可以接受參數爲null的情況。

Optional.empty()
創建一個爲空的Optional

public static void main(String[] args) {
    Optional<String> gender = Optional.of("MALE");
    String answer1 = "Yes";
    String answer2 = null;

    System.out.println("Non-Empty Optional:" + gender);
    // Non-Empty Optional:Optional[MALE]

    System.out.println("Non-Empty Optional: Gender value : " + gender.get());
    //Non-Empty Optional: Gender value : MALE
    System.out.println("Empty Optional: " + Optional.empty());
    //Empty Optional: Optional.empty

    System.out.println("ofNullable on Non-Empty Optional: " + Optional.ofNullable(answer1));
    //ofNullable on Non-Empty Optional: Optional[Yes]
    System.out.println("ofNullable on Empty Optional: " + Optional.ofNullable(answer2));
    //ofNullable on Empty Optional: Optional.empty

    // java.lang.NullPointerException
    System.out.println("ofNullable on Non-Empty Optional: " + Optional.of(answer2));
}

Optional.map()
如果有值,則對其執行調用mapping函數得到返回值。如果返回值不爲null,則創建包含mapping返回值的Optional作爲map方法返回值,否則返回空Optional。
Optional.flatMap()
如果有值,爲其執行mapping函數返回Optional類型返回值,否則返回空Optional。flatMap與map(Funtion)方法類似,區別在於flatMap中的mapper返回值必須是Optional。調用結束時,flatMap不會對結果用Optional封裝。

public static void main(String[] args) {
    Optional<String> oGender = Optional.of("male");
    Optional<String> emptyGender = Optional.empty();

    System.out.println("Non-Empty Optional::" + oGender.map(String::toUpperCase));
    //Non-Empty Optional::Optional[MALE]
    System.out.println("Empty Optional::" + emptyGender.map(String::toUpperCase));
    //Empty Optional::Optional.empty

    Optional<Optional<String>> ooGender = Optional.of(Optional.of("male"));
    System.out.println("Optional value::" + ooGender);
    //Optional value::Optional[Optional[male]]
    System.out.println("Optional.map:: " + ooGender.map(gender -> gender.map(String::toUpperCase)));
    //Optional.map:: Optional[Optional[MALE]]
    System.out.println("Optional.flatMap::" + ooGender.flatMap(gender -> gender.map(String::toUpperCase)));
    //Optional.flatMap::Optional[MALE]
}

Optional.filter()
如果有值並且滿足斷言條件返回包含該值的Optional,否則返回空Optional。

public static void main(String[] args) {
    Optional<String> gender = Optional.of("male");
    Optional<String> emptyGender = Optional.empty();

    //Filter on Optional
    System.out.println(gender.filter(g -> g.equals("MALE")));
    //Optional.empty

    System.out.println(gender.filter(g -> g.equalsIgnoreCase("MALE")));
    //Optional[male]

    System.out.println(emptyGender.filter(g -> g.equalsIgnoreCase("MALE")));
    //Optional.empty

    // filter方法檢查給定的Option值是否滿足某些條件。
    // 如果滿足則返回同一個Option實例,否則返回空Optional。
    Optional<String> longName = Optional.of("123456789").filter((value) -> value.length() > 6);
    System.out.println(longName.orElse("The name is less than 6 characters"));//輸出Sanaulla
    //123456789

    //另一個例子是Optional值不滿足filter指定的條件。
    Optional<String> anotherName = Optional.of("1234");
    Optional<String> shortName = anotherName.filter((value) -> value.length() > 6);
    System.out.println(shortName.orElse("The name is less than 6 characters"));
    //The name is less than 6 characters
}

Optional.isPresent()
如果值存在返回true,否則返回false。

Optional.get()
如果Optional有值則將其返回,否則拋出NoSuchElementException。

Optional.ifPresent()
如果Optional實例有值則爲其調用consumer,否則不做處理。

Optional.orElse()
如果有值則將其返回,否則返回指定的其它值。

Optional.orElseGet()
orElseGet與orElse方法類似,區別在於得到的默認值。orElse方法將傳入的字符串作爲默認值,orElseGet方法可以接受Supplier接口的實現用來生成默認值。

Optional.orElseThrow()
如果有值則將其返回,否則拋出supplier接口創建的異常。

public static void main(String[] args) {
    Optional<String> gender = Optional.of("MALE");
    Optional<String> emptyGender = Optional.empty();

    if (gender.isPresent()) {
      System.out.println("Value available.");
    } else {
      System.out.println("Value not available.");
    }

    try {
      //在空的Optional實例上調用get(),拋出NoSuchElementException
      System.out.println(emptyGender.get());
    } catch (NoSuchElementException ex) {
      System.out.println(ex.getMessage());
      //No value present
    }

    gender.ifPresent(g -> System.out.println("In gender Option, value is " + g));
    //In gender Option, value is MALE

    //condition failed, no output print
    emptyGender.ifPresent(g -> System.out.println("In emptyGender Option, value available."));

    System.out.println(gender.orElse("<N/A>"));
    //MALE
    System.out.println(emptyGender.orElse("<N/A>"));
    //<N/A>

    System.out.println(gender.orElseGet(() -> "<N/A>"));
    //MALE
    System.out.println(emptyGender.orElseGet(() -> "<N/A>"));
    //<N/A>
    try {
      //orElseThrow與orElse方法類似。與返回默認值不同,
      //orElseThrow會拋出lambda表達式或方法生成的異常
      emptyGender.orElseThrow(ValueAbsentException::new);
    } catch (Throwable ex) {
      System.out.println(ex.getMessage());
      //No value present in the Optional instance
    }
}

public static class ValueAbsentException extends Throwable {
    public ValueAbsentException() {
      super();
    }

    public ValueAbsentException(String msg) {
      super(msg);
    }

    @Override
    public String getMessage() {
      return "No value present in the Optional instance";
    }
}

例:Without Java 8 Optional

//分辨率
public class ScreenResolution {
  private int width;
  private int height;
  //...
}
//顯示屏
public class DisplayFeatures {
  private String size; // In inches
  private ScreenResolution resolution;
  //...
}
//手機
public class Mobile {
  private long id;
  private String brand;
  private String name;
  private DisplayFeatures displayFeatures;
  //...
}
public static void main(String[] args) {
    ScreenResolution resolution = new ScreenResolution(750, 1334);
    DisplayFeatures dfeatures = new DisplayFeatures("4.7", resolution);
    Mobile mobile = new Mobile(2015001, "Apple", "iPhone 6s", dfeatures);

    int mobileWidth = 0;
    if (mobile != null) {
      DisplayFeatures df = mobile.getDisplayFeatures();
      if (df != null) {
        ScreenResolution sr = df.getResolution();
        if (sr != null) {
          return sr.getWidth();
        }
      }
    }
    System.out.println("Apple iPhone 6s Screen Width = " + mobileWidth);
    //Apple iPhone 6s Screen Width = 750
}

例:With Java 8 Optional

//分辨率
public class ScreenResolution {
  private int width;
  private int height;
  //...
}
//顯示屏
public class DisplayFeaturesOptional {
  private String size; // In inches
  private Optional<ScreenResolution> resolution;
  //...
}
//手機
public class MobileOptional {
  private long id;
  private String brand;
  private String name;
  private Optional<DisplayFeaturesOptional> displayFeatures;
  //...
}
public static void main(String[] args) {
    ScreenResolution resolution = new ScreenResolution(750, 1334);
    DisplayFeaturesOptional dfeatures = new DisplayFeaturesOptional("4.7", Optional.of(resolution));
    MobileOptional mobile = new MobileOptional(2015001, "Apple", "iPhone 6s", Optional.of(dfeatures));

    int width = mobile.flatMap(MobileOptional::getDisplayFeatures)
        .flatMap(DisplayFeaturesOptional::getResolution)
        .map(ScreenResolution::getWidth)
        .orElse(0);
    System.out.println("Apple iPhone 6s Screen Width = " + width);
    //Apple iPhone 6s Screen Width = 750
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章