java.util.Optional是Java 8新增的類,做爲一個持有實例的容器類,能夠幫咱們把判空的代碼寫得更優雅,而且該類還提供了一些實用的api,官方文檔在這裏,接下來咱們經過實戰來學習吧:java
###三種Optional構造方法### 第一種. Optional.of(Object object):入參object不能爲空,不然會拋出空指針異常,查看Optional源碼發現會調用Objects.requireNonNull方法,裏面有判空:git
public static <T> T requireNonNull(T obj) { if (obj == null) throw new NullPointerException(); return obj; }
第二種. Optional.ofNullable(Object object):入參object能夠爲空,若是object不爲空,就建立一個Optional實例;若是object爲空就返回一個static fainal的Option對象,注意這裏不會新建Option實例,而是使用一個static final的實例EMPTY,這裏比較有意思的是泛型的問題,例如我須要兩個Optional對象,類型分別是String和Integer,代碼以下:github
Optional<String> optionalStr = Optional.ofNullable(null); Optional<Integer> optionalInt = Optional.ofNullable(null);
類型不一樣又如何保證返回同一個對象呢?直接看ofNullable的源碼,發現會調用empty方法:數據庫
public static<T> Optional<T> empty() { @SuppressWarnings("unchecked") Optional<T> t = (Optional<T>) EMPTY; return t; }
原來是經過強制轉換實現的,再看EMPTY對象:api
private static final Optional<?> EMPTY = new Optional<>();
是經過"?"聲明的;oracle
第三種. Optional.empty():就是上面分析Optional.ofNullable的時候用到的empty方法,直接返回一個static final的實例EMPTY;工具
Optional.of()方法的用法有點像斷言,對象爲空的時候表明着某種業務上不可接受的異常,須要儘早處理,而且業務拒絕執行,這種場景下可使用Optional.of;學習
接下來咱們開始實戰吧;ui
###例子中用到的對象:Student### Student是個普通的bean,有三個字段和對應的get&set方法this
package com.bolingcavalry; /** * @author willzhao * @version V1.0 * @Description: 一個普通的bean * @email zq2599@gmail.com * @Date 2017/8/26 下午11:23 */ public class Student { private int id; private String name; private int age; public int getId() { return id; } public void setId(int id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } public Student(int id, String name, int age) { this.id = id; this.name = name; this.age = age; } }
###Optional.ofNullable的用法### 下面舉例說明最經常使用的Optional.ofNullable,咱們打算根據名稱從其餘系統獲取student對象,若是對象爲空就返回默認對象,先看不用Optional的時候咱們日常是怎麼寫的,以下代碼所示,標準的if&else判斷:
private Student queryById(int id){ //TODO 這裏模擬從數據庫查詢 return null; } public Student getStudent(int id){ Student student = queryById(id)); //若是爲空就返回DEFAULT對象 return student==null ? DEFAULT : student; }
用Optional以後,以下所示,不須要經過判空來避免空指針異常了:
private Student queryById(int id){ //TODO 這裏模擬從數據庫查詢 return null; } public Student getStudent(int id){ Optional<Student> optional = Optional.ofNullable(queryById(id)); //若是爲空就返回DEFAULT對象 return optional.orElse(DEFAULT); }
orElse方法能夠指定一個value爲空時的返回對象,若是這個對象須要調用方法才能獲取(例如咱們拿不到DEFAULT對象,要經過getDefault()方法才能拿到),這是就須要orElseGet方法來達到目的,以下:
private Student queryById(int id){ //TODO 這裏模擬從數據庫查詢 return null; } private Student getDefault(){ return DEFAULT; } public Student getStudent(int id){ Optional<Student> optional = Optional.ofNullable(queryById(id)); //若是爲空就返回DEFAULT對象 return optional.orElseGet(() -> getDefault()); }
###Optional的map方法### 假如咱們的需求是student對象非空就返回name的大寫,若是student對象爲空就返回"invalid",在沒有Optional的時候寫法以下,除了檢查student變量是否爲空,還要檢查name是否爲空:
private Student queryById(int id){ //TODO 這裏模擬從數據庫查詢 return null; } public String getStudentUpperName(int id){ Student student = queryById(id); if(student!=null && student.getName()!=null){ return student.getName().toUpperCase(); } return "invalid"; }
用了Optional能夠這麼寫:
private Student queryById(int id){ //TODO 這裏模擬從數據庫查詢 return null; } public String getStudentUpperName(int id){ Optional<Student> optional = Optional.ofNullable(queryById(id)); return optional.map(student -> student.getName()) .map(name -> name.toUpperCase()) .orElse("invalid"); }
由以上代碼能夠看到,map能夠將一個Optional對象轉換成另外一個,第一次是將Optional<Student>轉換成了Optional<String>,第二次是將Optional<String>轉成了另外一個Optional<String>,只是此次將字符串換成了大寫;
本次實戰的源碼已經上傳到git上,地址是<font color="red">git@github.com:zq2599/blog_demos.git</font>,裏面有多個工程,本次用到的是optionaldemo,以下圖紅框所示:
以上就是Optional的基本用法,對Optional的使用是在習慣上對以前判空寫法的挑戰,但能夠試着去習慣這個簡單優雅的小工具;