Optional和ifPresent進行判空處理


Optional和ifPresent進行判空處理

JDK 1.8加入了 Optional 類。用於避免用if判空時出現空指針異常,它就是一個包裹着對象的容器。如果值存在則 isPresent()方法會返回 true,調用 get() 方法會返回該對象。

JDK 提供三個靜態方法來構造一個 Optional:

  1. Optional.of(T value) 該方法通過一個非 null 的 value 來構造一個 Optional,返回的 Optional 包含了 value 這個值。對於該方法,傳入的參數一定不能為 null,否則便會拋出 NullPointerException。

  2. Optional.ofNullable(T value) 該方法和 of 方法的區別在於,傳入的參數可以為 null,進行三目運算,判斷傳入的參數是否為 null,如果為 null 的話,返回的就是 Optional.empty()。

  3. 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"));


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM