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"));
上一篇:Java 8 新增的 Optional


下一篇:Java到底如何更优雅的处理空值?