Optional類是Java 8新增的一個類,用以解決程序中常見的NullPointerException異常問題。本篇文章將詳細介紹Optional類,以及如何用它消除代碼中的null檢查。java
做爲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值引起的種種問題。擴展:如何更優雅的處理空值?阿里雲
java.util.Optional<T>
類是一個封裝了Optional值的容器對象,Optional值能夠爲null,若是值存在,調用isPresent()方法返回true,調用get()方法能夠獲取值。spa
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對象。
若是咱們要獲取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);
`
Optional類還包含其餘方法用於獲取值,這些方法分別爲:
下面來看看這三個方法的具體用法:
`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()方法可用於判斷Optional對象是否知足給定條件,通常用於條件過濾:
`Optional<String> optional = Optional.of("lw900925@163.com");
optional = optional.filter(str -> str.contains("164"));
`
在上面的代碼中,若是filter()方法中的Lambda表達式成立,filter()方法會返回當前Optional對象值,不然,返回一個值爲空的Optional對象。Java知音公衆號內回覆「後端面試」,送你一份Java面試題寶典。
經過上面的例子能夠看出,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使用的建議:
第一條建議中直接調用get()方法是很危險的作法,若是Optional的值爲空,那麼毫無疑問會拋出NullPointerException異常,而爲了調用get()方法而使用isPresent()方法做爲空值檢查,這種作法與傳統的用if語句塊作空值檢查沒有任何區別。
第二條建議避免使用Optional做爲實體類的屬性,它在設計的時候就沒有考慮過用來做爲類的屬性,若是你查看Optional的源代碼,你會發現它沒有實現java.io.Serializable接口,這在某些狀況下是很重要的(好比你的項目中使用了某些序列化框架),使用了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);
}
`
`return str != null ? str : "Hello World"
`
上面的代碼表示判斷字符串str是否爲空,不爲空就返回,不然,返回一個常量。使用Optional類能夠表示爲:
`return strOpt.orElse("Hello World")
`
`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面試題集合,附帶超詳細答案,但願能幫助到你們。
小編網盤也經過這些年的積累,把Java電子書也分享給你們,大概有20G左右的資源
珍藏多年的230個高端簡歷模板,也一塊兒送給你們