Optional:判空新姿势
1、NPE 问题
NPE(Null Pointer Exception):空指针异常。
示例:对象 User 引用对象 Info
-
错误写法:无法保证非空,可能导致 NPE。
String infoId = user.getInfo().getId();
-
正确写法:进行 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(); } }
-