Optional:判空新姿势

1、NPE 问题

NPE(Null Pointer Exception):空指针异常。

示例:对象 User 引用对象 Info

  1. 错误写法:无法保证非空,可能导致 NPE。

    String infoId = user.getInfo().getId();
    
  2. 正确写法:进行 if 判断,但代码臃肿。

    if (user != null) {
        Info info = user.getInfo();
        if (info != null) {
            String InfoId = info.getId();
        }
    }
    

2、Optional API

Optional:一个存储 value 的容器(package java.util)

value 代表真实值(可能空/非空),一旦设置无法修改。

2.1、成员变量

final 修饰

  • EMPTY:代表空对象实例。

  • value:代表 Optional 中的真实值。

    private static final Optional<?> EMPTY = new Optional<>();
    
    private final T value;
    

2.2、创建 Optional

2.2.1、构造方法

private 权限,无法直接访问。

  • Optional():创建空值实例。

  • Optional(T value):创建非空值实例(空则 NPE)。

    private Optional() {
        this.value = null;
    }
    
    private Optional(T value) {
        this.value = Objects.requireNonNull(value);
    }
    
    // 相关代码:空值则抛 NPE
    public static <T> T requireNonNull(T obj) {
        if (obj == null)
            throw new NullPointerException();
        return obj;
    }
    

2.2.2、创建方法

public 权限,提供对构造器的访问。

  • of(T value):value 必须非空,否则 NPE。

  • ofNullable(T value):允许 value 为空。

  • empty():返回 EMPTY 实例。

    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;
    }
    

2.3、取值

2.3.1、纯取值

get():若 value 空则抛异常

public T get() {
    if (value == null) {
        throw new NoSuchElementException("No value present");
    }
    return value;
}

2.3.2、默认值

若 value 空则给定默认值

类似 map.getOrDefault(key, defaultVal)

  • orElse(T other):给定 value 类型值。

  • orElseGet(Supplier):给定 Supplier 的输出结果。

    public T orElse(T other) {
        return value != null ? value : other;
    }
    
    public T orElseGet(Supplier<? extends T> supplier) {
        return value != null ? value : supplier.get();
    }
    

2.3.3、异常

  • orElseThrow():同 get(),抛 NoSuchElementException 类型。

  • orElseThrow(Supplier):指定异常类型。

    public T orElseThrow() {
        if (value == null) {
            throw new NoSuchElementException("No value present");
        }
        return value;
    }
    
    public <X extends Throwable> T orElseThrow(Supplier<? extends X> exceptionSupplier) throws X {
        if (value != null) {
            return value;
        } else {
            throw exceptionSupplier.get();
        }
    }
    

case

  • 示例

    User user = ?;
    Optional<User> u = Optional.ofNullable(user);
    
  • 执行不同方法

    User 非空 User 空
    u.get() 返回 user 实例 抛 NoSuchElementException 类型
    u.orElse(createUser()) 同上 返回 createUser() 方法结果
    u.orElseGet(() -> createUser()) 同上 返回 Supplier 执行结果,即 createUser() 方法
    u.orElseThrow() 同上 抛 NoSuchElementException 类型
    u.orElseThrow(() -> new RuntimeException("用户不存在")) 同上 抛指定异常类型

2.4、流式编程

2.4.1、流

stream()

public Stream<T> stream() {
    if (!isPresent()) {
        return Stream.empty();
    } else {
        return Stream.of(value);
    }
}

2.4.2、映射

xxxMap(Function):将当前 Optional 实例转换成另一个 Optional。

流程:先校验 Function 非空,再根据 value 不同情况进行操作。

  • :返回 EMPTY 实例。
  • 非空:返回 Function 的执行结果。

相关 API

  • map(Function):允许 Function 结果为空。

  • flatMap(Function):不允许 Function 结果为空。

    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));
        }
    }
    
    public <U> Optional<U> flatMap(Function<? super T, ? extends Optional<? extends U>> mapper) {
        Objects.requireNonNull(mapper);
        if (!isPresent()) {
            return empty();
        } else {
            // 不允许空
            @SuppressWarnings("unchecked")
            Optional<U> r = (Optional<U>) mapper.apply(value);
            return Objects.requireNonNull(r);
        }
    }
    

2.4.3、过滤

filter(Predicate):检验当前 Optional 是否满足条件,是则保留,否则过滤。

流程:先校验 Predicate 非空,再根据 value 不同情况进行操作。

  • :返回 Optional 半身。
  • 非空:执行 Predicate,当前 Optional 满足条件则返回,否则返回 EMPTY 实例。

API

public Optional<T> filter(Predicate<? super T> predicate) {
    Objects.requireNonNull(predicate);
    if (!isPresent()) {
        return this;
    } else {
        return predicate.test(value) ? this : empty();
    }
}

示例

// 参数表示年龄
User user1 = new User(17);
User user2 = new User(19);

Optional<User> u1 = Optional.of(user1);
Optional<User> u2 = Optional.of(user2);

// 返回 u1
Optional<User> res1 = u1.filter(u -> u.getAge() < 18);
// 返回 EMPTY
Optional<User> res2 = u2.filter(u -> u.getAge() < 18);

2.5、判空

  • 判空:isPresent(),isEmpty()

    public boolean isPresent() {
        return value != null;
    }
    
    public boolean isEmpty() {
        return value == null;
    }
    
  • 判断并操作

    • ifPresent(Consumer):判断 value 非空时执行 Consumer 动作。

    • ifPresentOrElse(Consumer):value 非空时同上,value 空时执行 Runnable 方法。

      public void ifPresent(Consumer<? super T> action) {
          if (value != null) {
              action.accept(value);
          }
      }
      
      public void ifPresentOrElse(Consumer<? super T> action, Runnable emptyAction) {
          if (value != null) {
              action.accept(value);
          } else {
              emptyAction.run();
          }
      }
      
posted @ 2022-10-11 10:47  Jaywee  阅读(287)  评论(0编辑  收藏  举报

👇