「Java8實戰」使用Optional取代null

在Java中對一個空物件進行操作時,便會丟擲最常見的異常

NullPointerException

。為了改善這個問題,Java 8中提供了一個

java。util。Optional

型別。Optional類的Javadoc描述如下:這是一個可以為null的容器物件。如果值存在則

isPresent()

方法會返回true,呼叫

get()

方法會返回該物件。下面介紹Optional類的使用方法。 假如有一個像下面這樣的類層次結構:

class Department { private Employee employee; public Department(Employee employee) { this。employee = employee; } Employee getEmployee() { return employee; } } class Employee { private Girl girlFriend; public Employee(Girl girlFriend) { this。girlFriend = girlFriend; } Girl getGirlFriend() { return girlFriend; } } class Girl { private String name; public Girl(String name) { this。name = name; } String getName() { return name; } }

部門

Department

類包含一個員工

employee

屬性,型別為

Employee

,員工

Employee

類包含

girlFriend

屬性,型別為

Girl

。假如現在要獲取部門某個員工的女朋友,我們通常是這樣獲取的:

static String getGirlFriendName(Department department) { if (department != null) { Employee employee = department。getEmployee(); if (employee != null) { Girl girl = employee。getGirlFriend(); if (girl != null) { return girl。getName(); } return “單身汪”; } return “沒有員工”; } return “部門為空”; }

可以看到,在每次引用變數的屬性時,都要先判斷變數是否為空,如果不做該檢查將可能導致

NullPointerException

。下面我們將使用Optional來改善這種層層巢狀,囉嗦的程式碼。

建立Optional

建立一個Optional物件有好幾種方式:

建立一個空的Optional

我們可以使用靜態工廠方法

Optional。empty

,建立一個空的Optional物件:

Optional department = Optional。empty();

根據非空值建立Optional

我們也可以使用靜態工廠方法

Optional。of

來建立一個非空物件的Optional物件:

Optional optEmployee = Optional。of(employee);

如果employee為空,這段程式碼會立即丟擲一個

NullPointerException

建立可以為null的Optional

使用靜態工廠方法

Optional。ofNullable

,我們可以建立一個允許null值的Optional物件:

Optional optEmployee = Optional。ofNullable(employee);

如果employee為空,對其呼叫

get

方法將丟擲

NoSuchElementException

Optional方法

Optional類包含了許多方法,下面介紹這些方法的使用。

isPresent

顧名思義,如果值存在返回true,否則返回false。如:

Optional opt = Optional。ofNullable(department); if(opt。isPresent()){ System。out。println(opt。get()。getEmployee()); }

get

如果Optional有值則將其返回,否則丟擲

NoSuchElementException

。下面舉個丟擲

NoSuchElementException

的例子:

try { Optional。empty()。get(); } catch (Exception e) { e。printStackTrace(); }

程式碼將捕獲到 java。util。NoSuchElementException: No value present 異常。

ifPresent

如果Optional例項有值則為其呼叫

Consumer

(函式描述符為

T -> void

),否則不做處理。如:

girl。ifPresent(g -> System。out。println(“我有女朋友,名字是:” + g。getName()));

orElse

如果Optional例項有值則將其返回,否則返回

orElse

方法傳入的引數。如:

System。out。println(Optional。empty()。orElse(“There is no value present!”));

程式將輸出

There is no value present!

orElseGet

orElseGet

orElse

方法類似,

orElse

方法將傳入的字串作為預設值,而

orElseGet

方法可以接受

Supplier

(函式描述符為

() -> T

)來生成預設值。如:

System。out。println(Optional。empty()。orElseGet(() -> “There is no value present!”));

程式同樣輸出

There is no value present!

orElseThrow

如果有值則將其返回,否則丟擲

Supplier

介面建立的異常。如:

try { Optional。empty()。orElseThrow(NoSuchElementException::new);} catch (Exception e) { e。printStackTrace();}

程式碼將捕獲到 java。util。NoSuchElementException: No value present 異常。

map

如果Optional有值,則對其執行呼叫

Function

函式描述符為(

T -> R

)得到返回值。如果返回值不為null,則建立包含

Function

回值的Optional作為map方法返回值,否則返回空Optional。

Optional upperName = name。map(String::toUpperCase);System。out。println(upperName。orElse(“No value found”));

flatMap

如果有值,為其執行

Function

函式返回Optional型別返回值,否則返回空Optional。

flatMap

map

方法類似,區別在於

flatMap

中的

Function

函式返回值必須是Optional。呼叫結束時,

flatMap

不會對結果用Optional封裝。如:

upperName = name。flatMap((value) -> Optional。of(value。toUpperCase()));System。out。println(upperName。orElse(“No value found”));

filter

filter個方法透過傳入

Predicate

(函式描述符為

T -> Boolean

)對Optional例項的值進行過濾。如:

Optional name = Optional。of(“Jane”);Optional LongName = name。filter((value) -> value。length() >= 3);System。out。println(LongName。orElse(“名字長度小於3個字元”));

方法輸出

Jane

實戰

介紹完Optional類的方法後,我們使用Optional改善一開始的程式碼:

static String getGirlFriendName(Department department) { Optional opt = Optional。ofNullable(department); return opt。map(Department::getEmployee) 。map(Employee::getGirlFriend) 。map(Girl::getName) 。orElseThrow(NoSuchElementException::new);}

整潔而又不失逼格。