Optional和ifPresent進行判空處理
JDK 1.8加入了 Optional 類。用於避免用if判空時出現空指針異常,它就是一個包裹着對象的容器。如果值存在則 isPresent()方法會返回 true,調用 get() 方法會返回該對象。
JDK 提供三個靜態方法來構造一個 Optional:
-
Optional.of(T value) 該方法通過一個非 null 的 value 來構造一個 Optional,返回的 Optional 包含了 value 這個值。對於該方法,傳入的參數一定不能為 null,否則便會拋出 NullPointerException。
-
Optional.ofNullable(T value) 該方法和 of 方法的區別在於,傳入的參數可以為 null,進行三目運算,判斷傳入的參數是否為 null,如果為 null 的話,返回的就是 Optional.empty()。
-
Optional.empty()該方法用來構造一個空的 Optional,即該 Optional 中不包含值 —— 其實底層實現還是 如果 Optional 中的 value 為 null 則該 Optional 為不包含值的狀態,然后在 API 層面將 Optional 表現的不能包含 null 值,使得 Optional 只存在 包含值 和 不包含值 兩種狀態。
Optional 提供的方法
1.ifPresent
@Component
@Slf4j
public class KafkaConsumer {
@KafkaListener(topics = {"luobo"})
public void listen(ConsumerRecord<?,?> record){
Optional.ofNullable(record.value())
.ifPresent(message -> {
log.info("------------------record = {}",record);
log.info("--------------message= {}",message);
});
}
}
如果 Optional 中有值,則對該值調用 consumer.accept,否則什么也不做。 所以對於上面的例子,我們可以修改為:
Optional<User> user = Optional.ofNullable(getUserById(id));
user.ifPresent(u -> System.out.println("Username is: " + u.getUsername()));
2.orElse
public T orElse(T other) {
return value != null ? value : other;
}
如果 Optional 中有值則將其返回,否則返回 orElse 方法傳入的參數。
User user = Optional
.ofNullable(getUserById(id))
.orElse(new User(0, "Unknown"));
System.out.println("Username is: " + user.getUsername());
3.orElseGet
public T orElseGet(Supplier<? extends T> ither) {
return value != null ? value : other.get();
}
orElseGet 與 orElse 方法的區別在於,orElseGet 方法傳入的參數為一個 Supplier 接口的實現 —— 當 Optional 中有值的時候,返回值;當 Optional 中沒有值的時候,返回從該 Supplier 獲得的值。
User user = Optional
.ofNullable(getUserById(id))
.orElseGet(() -> new User(0, "Unknown"));
System.out.println("Username is: " + user.getUsername());
4.orElseThrow
public <X extends Throwable> T orElseThrow(Supplier<? extends X> exceptionSupplier) throws X {
if (value != null) {
return value;
} else {
throw exceptionSupplier.get();
}
}
orElseThrow 與 orElse 方法的區別在於,orElseThrow 方法當 Optional 中有值的時候,返回值;沒有值的時候會拋出異常,拋出的異常由傳入的 exceptionSupplier 提供。
User user = Optional
.ofNullable(getUserById(id))
.orElseThrow(() -> new EntityNotFoundException("id 為 " + id + " 的用戶沒有找到"));
舉一個 orElseThrow 的用途:在 SpringMVC 的控制器中,我們可以配置統一處理各種異常。查詢某個實體時,如果數據庫中有對應的記錄便返回該記錄,否則就可以拋出 EntityNotFoundException ,處理 EntityNotFoundException 的方法中我們就給客戶端返回Http 狀態碼 404 和異常對應的信息 —— orElseThrow 完美的適用於這種場景。
@RequestMapping("/{id}")
public SysUser getSysUser(@PathVariable Integer id) {
Optional<SysUser> user = userService.getSysUserById(id);
return user.orElseThrow(() -> new EntityNotFoundException("id 為 " + id + " 的用戶不存在"));
}
@ExceptionHandler(EntityNotFoundException.class)
public ResponseEntity<String> handleException(EntityNotFoundException ex) {
return new ResponseEntity<>(ex.getMessage(), HttpStatus.NOT_FOUND);
}
5.map
public <U> Optional<U> map(Function<? super T, ? extends U> mapper) {
Objects.requireNonNull(mapper);
if (!isPresent()){
return empty();
} else {
return Optional.ofNullable(mapper.apply(value));
}
}
如果當前 Optional 為 Optional.empty,則依舊返回 Optional.empty;否則返回一個新的 Optional,該 Optional 包含的是:函數 mapper 在以 value 作為輸入時的輸出值。
Optional<String> username = Optional
.ofNullable(getUserById(id))
.map(user -> user.getUsername());
System.out.println("Username is: " + username.orElse("Unknown"));
而且我們可以多次使用 map 操作:
Optional<String> username = Optional
.ofNullable(getUserById(id))
.map(user -> user.getUsername())
.map(name -> name.toLowerCase())
.map(name -> name.replace('_', ' '));
System.out.println("Username is: " + username.orElse("Unknown"));
6.flatMap
public <U> Optional<U> flatMap(Function<? super T, Optional<U>> mapper) {
Objects.requireNonNull(mapper);
if (!isPresent()){
return empty();
} else {
return Objects.requireNonNull(mapper.apply(value));
}
}
flatMap 方法與 map 方法的區別在於,map 方法參數中的函數 mapper 輸出的是值,然后 map 方法會使用 Optional.ofNullable 將其包裝為 Optional;而 flatMap 要求參數中的函數 mapper 輸出的就是 Optional。
Optional<String> username = Optional
.ofNullable(getUserById(id))
.flatMap(user -> Optional.of(user.getUsername()))
.flatMap(name -> Optional.of(name.toLowerCase()));
System.out.println("Username is: " + username.orElse("Unknown"));
7.filter
public Optional<T> filter(Predicate<? super T> predicate) {
Objects.requireNonNull(predicate);
if(!isPresent()) {
return this;
} else {
return predicate.test(value) ? this : empty();
}
}
filter 方法接受一個 Predicate 來對 Optional 中包含的值進行過濾,如果包含的值滿足條件,那么還是返回這個 Optional;否則返回 Optional.empty。
Optional<String> username = Optional
.ofNullable(getUserById(id))
.filter(user -> user.getId() < 10)
.map(user -> user.getUsername());
System.out.println("Username is: " + username.orElse("Unknown"));