如何正確的使用Java8中的Optional類來消除代碼中的null檢查

Optional類是Java 8新增的一個類,用以解決程序中常見的NullPointerException異常問題。本篇文章將詳細介紹Optional類,以及如何用它消除代碼中的null檢查。java

避免使用null檢查

做爲Java開發人員,幾乎全部人都遇到過NullPointerException異常,大多數人遇到NullPointerException異常時都會在異常出現的地方加上if代碼塊來判斷值不爲空,好比下面的代碼:面試

`public void bindUserToRole(User user) {
    if (user != null) {
        String roleId = user.getRoleId();
        if (roleId != null) {
            Role role = roleDao.findOne(roleId);
            if (role != null) {
                role.setUserId(user.getUserId());
                roleDao.save(role);
            }
        }
    }
}
`編程

這是比較廣泛的作法,爲了不出現NullPointerException異常,手動對可能爲null值進行了處理,不過代碼看起來很是糟糕,業務邏輯被淹沒在if邏輯判斷中,也許下面的代碼看起來可讀性稍好一些:後端

`public String bindUserToRole(User user) {
    if (user == null) {
        return;
    } 架構

    String roleId = user.getRoleId();
    if (roleId == null) {
        return;
    } 框架

    Role = roleDao.findOne(roleId);
    if (role != null) {
        role.setUserId(user.getUserId());
        roleDao.save(role);
    }
}
`函數式編程

上面的代碼避免了深層的if語句嵌套,但本質上是同樣的,方法內有三個不一樣的返回點,出錯後調試也不容易,由於你不知道是那個值致使了NullPointerException異常。函數

基於上面的緣由,Java 8中引入了一個新的類Optional,用以免使用null值引起的種種問題。擴展:如何更優雅的處理空值?阿里雲

Optional類

java.util.Optional<T>類是一個封裝了Optional值的容器對象,Optional值能夠爲null,若是值存在,調用isPresent()方法返回true,調用get()方法能夠獲取值。spa

建立Optional對象

Optional類提供類三個方法用於實例化一個Optional對象,它們分別爲empty()、of()、ofNullable(),這三個方法都是靜態方法,能夠直接調用。

empty()方法用於建立一個沒有值的Optional對象:

`Optional<String> emptyOpt = Optional.empty();
`

empty()方法建立的對象沒有值,若是對emptyOpt變量調用isPresent()方法會返回false,調用get()方法拋出NullPointerException異常。

of()方法使用一個非空的值建立Optional對象:

`String str = "Hello World";
Optional<String> notNullOpt = Optional.of(str);
`

ofNullable()方法接收一個能夠爲null的值:

`Optional<String> nullableOpt = Optional.ofNullable(str);
`

若是str的值爲null,獲得的nullableOpt是一個沒有值的Optional對象。

提取Optional對象中的值

若是咱們要獲取User對象中的roleId屬性值,常見的方式是直接獲取:

`String roleId = null;
if (user != null) {
    roleId = user.getRoleId();
}
`

使用Optional中提供的map()方法能夠以更簡單的方式實現:

`Optional<User> userOpt = Optional.ofNullable(user);
Optional<String> roleIdOpt = userOpt.map(User::getRoleId);
`

使用orElse()方法獲取值

Optional類還包含其餘方法用於獲取值,這些方法分別爲:

  • orElse():若是有值就返回,不然返回一個給定的值做爲默認值;
  • orElseGet():與orElse()方法做用相似,區別在於生成默認值的方式不一樣。該方法接受一個Supplier<? extends T>函數式接口參數,用於生成默認值;
  • orElseThrow():與前面介紹的get()方法相似,當值爲null時調用這兩個方法都會拋出NullPointerException異常,區別在於該方法能夠指定拋出的異常類型。

下面來看看這三個方法的具體用法:

`String str = "Hello World";
Optional<String> strOpt = Optional.of(str);
String orElseResult = strOpt.orElse("Hello Shanghai");
String orElseGet = strOpt.orElseGet(() -> "Hello Shanghai");
String orElseThrow = strOpt.orElseThrow(
        () -> new IllegalArgumentException("Argument 'str' cannot be null or blank."));
`

此外,Optional類還提供了一個ifPresent()方法,該方法接收一個Consumer<? super T>函數式接口,通常用於將信息打印到控制檯:

`Optional<String> strOpt = Optional.of("Hello World");
strOpt.ifPresent(System.out::println);
`

使用filter()方法過濾

filter()方法可用於判斷Optional對象是否知足給定條件,通常用於條件過濾:

`Optional<String> optional = Optional.of("lw900925@163.com");
optional = optional.filter(str -> str.contains("164"));
`

在上面的代碼中,若是filter()方法中的Lambda表達式成立,filter()方法會返回當前Optional對象值,不然,返回一個值爲空的Optional對象。Java知音公衆號內回覆「後端面試」,送你一份Java面試題寶典。

如何正確使用Optional

經過上面的例子能夠看出,Optional類能夠優雅的避免NullPointerException帶來的各類問題,不過,你是否真正掌握了Optional的用法?

假設你試圖使用Optional來避免可能出現的NullPointerException異常,編寫了以下代碼:

`Optional<User> userOpt = Optional.ofNullable(user);
if (userOpt.isPresent()) {
    User user = userOpt.get();
    // do something...
} else {
    // do something...
}
`

坦白說,上面的代碼與咱們以前的使用if語句判斷空值沒有任何區別,沒有起到Optional的正真做用:

`if (user != null) {
    // do something...
} else {
    // do something...
}
`

當咱們從以前版本切換到Java 8的時候,不該該還按照以前的思惟方式處理null值,Java 8提倡函數式編程,新增的許多API均可以用函數式編程表示,Optional類也是其中之一。這裏有幾條關於Optional使用的建議:

  • 儘可能避免在程序中直接調用Optional對象的get()和isPresent()方法;
  • 避免使用Optional類型聲明實體類的屬性;

第一條建議中直接調用get()方法是很危險的作法,若是Optional的值爲空,那麼毫無疑問會拋出NullPointerException異常,而爲了調用get()方法而使用isPresent()方法做爲空值檢查,這種作法與傳統的用if語句塊作空值檢查沒有任何區別。

第二條建議避免使用Optional做爲實體類的屬性,它在設計的時候就沒有考慮過用來做爲類的屬性,若是你查看Optional的源代碼,你會發現它沒有實現java.io.Serializable接口,這在某些狀況下是很重要的(好比你的項目中使用了某些序列化框架),使用了Optional做爲實體類的屬性,意味着他們不能被序列化。

下面咱們經過一些例子講解Optional的正確用法:

正確建立Optional對象

上面提到建立Optional對象有三個方法,empty()方法比較簡單,沒什麼特別要說明的。主要是of()和ofNullable()方法。當你很肯定一個對象不可能爲null的時候,應該使用of()方法,不然,儘量使用ofNullable()方法,好比:

`public static void method(Role role) {
    // 當Optional的值經過常量得到或者經過關鍵字new初始化,能夠直接使用of()方法
    Optional<String> strOpt = Optional.of("Hello World");
    Optional<User> userOpt = Optional.of(new User());

    // 方法參數中role值不肯定是否爲null,使用ofNullable()方法建立
    Optional<Role> roleOpt = Optional.ofNullable(role);
}
`

orElse()方法的使用

`return str != null ? str : "Hello World"
`

上面的代碼表示判斷字符串str是否爲空,不爲空就返回,不然,返回一個常量。使用Optional類能夠表示爲:

`return strOpt.orElse("Hello World")
`

簡化if-else

`User user = ...
if (user != null) {
    String userName = user.getUserName();
    if (userName != null) {
        return userName.toUpperCase();
    } else {
        return null;
    }
} else {
    return null;
}
`

上面的代碼能夠簡化成:

`User user = ...
Optional<User> userOpt = Optional.ofNullable(user);

return userOpt.map(User::getUserName)
            .map(String::toUpperCase)
            .orElse(null);
`

總結一下,新的Optional類讓咱們能夠以函數式編程的方式處理null值,拋棄了Java 8以前須要嵌套大量if-else代碼塊,使代碼可讀性有了很大的提升。

講到這裏,給你們推薦小編經過一些大廠的朋友要到了他們內部的Java面試題,資料可貴,並且仍是近一年的真實面試題;

分別有:螞蟻金服、拼多多、阿里雲、百度、惟品會、攜程、豐巢科技、樂信、軟通動力、OPPO、銀盛支付、中國平安等初,中級,高級Java面試題集合,附帶超詳細答案,但願能幫助到你們。

朋友作的秒殺系統被面試官嘲笑!大專畢業,天天都CRUD很難受

小編網盤也經過這些年的積累,把Java電子書也分享給你們,大概有20G左右的資源

朋友作的秒殺系統被面試官嘲笑!大專畢業,天天都CRUD很難受

珍藏多年的230個高端簡歷模板,也一塊兒送給你們

朋友作的秒殺系統被面試官嘲笑!大專畢業,天天都CRUD很難受

資料免費領取步驟

1.備註:思否
2.點點這個連接免費獲取:30G架構進階資料
相關文章
相關標籤/搜索