NPE問題
NPE 即(java.lang.NullPointException):空指針異常锣险,在日常編程中常常會遇到的問題喧务。通常需要使用者對傳入?yún)?shù)或者調(diào)用返回結(jié)果進(jìn)行空指針(null)判斷,java8之前一般的代碼如下:
public String getUserAddressArea(User user) {
if (user != null) {
if (user.getAddress() != null) {
return user.getAddress().getArea();
}
}
return null;
}
如果業(yè)務(wù)對象嵌套了多層對象,那么如果按照上面的寫法if也會嵌套多層。雖然可以使用衛(wèi)語句進(jìn)行優(yōu)化但是代碼依舊丑陋(多層嵌套會有多個if,如果還有其它判斷條件則會使得if更加復(fù)雜)
//衛(wèi)語句減少嵌套
public String getUserAddressArea(User user) {
if (user == null) {
return null;
}
if (user.getAddress() == null) {
return null;
}
return user.getAddress().getArea();
}
java8提供了Optional更優(yōu)雅的方式應(yīng)對上述問題
//使用Optional避免NPE
public String getUserAddressArea(User user) {
return Optional.ofNullable(user)
.map(u -> u.getAddress())
.map(address -> address.getArea())
.orElseGet(() -> null);
}
//附加其它條件
public static String getUserAddressArea(User user) {
return Optional.ofNullable(user)
.filter(u -> "yueming".equals(u.getName()))
.map(u -> u.getAddress())
.map(address -> address.getArea())
.orElseGet(() -> null);
}
上面就是Optional的基本用法再芋,下面簡單介紹一下里面用到的一些方法(具體請參照官方的API文檔)
常用方法
- Optional對象構(gòu)建方法(因為其構(gòu)造函數(shù)是private的因此提供了靜態(tài)方法來構(gòu)建Optional對象)
- public static <T> Optional<T> of(T value)
- public static <T> Optional<T> ofNullable(T value)
- public static<T> Optional<T> empty()
前兩個方法的區(qū)別在于第一個方法如果參數(shù)為value為null會拋出NPE,一般比較少使用坚冀,第二個方法則會返回一個空的Optional對象(調(diào)用的就是第三個方法)济赎。傳入的值可以使用get方法獲取。
- map和flatMap方法记某,兩者的作用一樣表示如果存在值則通過提供的映射函數(shù)返回一個Optional對象最終的值可由get()方法獲取司训。兩者的區(qū)別在于參數(shù)不一樣,flatMap需要傳入一個Optional的映射方法液南。
- public<U> Optional<U> map(Function<? super T, ? extends U> mapper)
- public<U> Optional<U> flatMap(Function<? super T, Optional<U>> mapper)
// 使用flatMap
public static String getUserAddressArea(User user) {
return Optional.ofNullable(user)
.filter(u -> "yueming".equals(u.getName()))
.flatMap(u -> u.getAddress())
.map(address -> address.getArea())
.orElseGet(() -> null);
}
//User 類中的getAddress方法
public Optional<Address> getAddress() {
return Optional.ofNullable(address);
}
//使用map
public static String getUserAddressArea(User user) {
return Optional.ofNullable(user)
.filter(u -> "yueming".equals(u.getName()))
.map(u -> u.getAddress())
.map(address -> address.getArea())
.orElseGet(() -> null);
}
// User 類中的getAddress方法
public Address getAddress() {
return address;
}
- isPresent 和 ifPresent
- public boolean isPresent() 判斷值是否為null返回true或false,map和flatMap方法調(diào)用了此方法來判斷值是否為空
- public void ifPresent(Consumer<? super T> consumer) 如果值不為null則執(zhí)行consumer傳入的操作
- orElse和orElseGet壳猜,orElseThrow三者的作用均是判斷值是否為空然后返回區(qū)別在于其參數(shù)類型不一樣,如果值不為空則返回值否則返回的結(jié)果由參數(shù)獲然埂(具體可參見源代碼)统扳。
- public T orElse(T other)
- public T orElseGet(Supplier<? extends T> other)
- public <X extends Throwable> T orElseThrow(Supplier<? extends X> exceptionSupplier)
- filter 謂詞匹配
Optional原理
原理其實很簡單就是把要處理的對象傳入Optional,本來應(yīng)該由用戶來判斷的是否為null的邏輯封裝起來了而已(將經(jīng)常用到的邏輯封裝起來復(fù)用代碼讓代碼更加優(yōu)雅)畅姊,可自行查看Optional源代碼了解咒钟。
public final class Optional<T> {
private static final Optional<?> EMPTY = new Optional<>();
private final T value;
// 構(gòu)造Optional
private Optional() {
this.value = null;
}
public static <T> Optional<T> of(T value) {
return new Optional<>(value);
}
public static <T> Optional<T> ofNullable(T value) {
return value == null ? empty() : of(value);
}
public static<T> Optional<T> empty() {
@SuppressWarnings("unchecked")
Optional<T> t = (Optional<T>) EMPTY;
return t;
}
//判斷是否為空 核心還是判斷是不是為null,filter若未,map朱嘴,flatMap方法均有調(diào)用isPresent
//其它orElse、orElseGet粗合、orElseThrow萍嬉、ifPresent、get方法也均是采用了value != null來做判斷隙疚。
public boolean isPresent() {
return value != null;
}
...
}