不用if (obj != null)
,轻松解决空指针
1. 前言
Java 的空指针异常(Null Pointer Exception,简称 NPE)困扰了无数开发者。正如有大佬所言,防止 NPE 是程序员的基本修养。然而,即便有这份修养,NPE 依旧是我们最头疼的问题之一。
本文将介绍如何使用 Java 8 的 Optional
类来简化代码并高效处理 NPE 问题。
2. 认识 Optional 类
2.1 Optional 的作用
Optional
类提供了一种优雅的方式来避免传统的 if (obj != null)
判断。通过使用 Optional
,不仅可以提高代码可读性,还能有效减少空指针异常的风险。
2.2 Optional 用法示例
传统判断:
Person person = new Person();
if (person == null) {
return "person为null";
}
return person;
使用 Optional:
Person person = new Person();
return Optional.ofNullable(person).orElse("person为null");
3. Optional 的创建
3.1 Optional 的静态方法
public final class Optional<T> {
private static final Optional<?> EMPTY = new Optional<>();
private final T value;
private Optional() {
this.value = null;
}
private Optional(T value) {
this.value = Objects.requireNonNull(value);
}
public static<T> Optional<T> empty() {
@SuppressWarnings("unchecked")
Optional<T> t = (Optional<T>) EMPTY;
return t;
}
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);
}
}
示例:
Optional<String> optEmpty = Optional.empty(); // 空 Optional 对象
Optional<String> optOf = Optional.of("optional"); // 非空 Optional 对象
Optional<String> optOfNullable1 = Optional.ofNullable(null); // 可以为空的 Optional 对象
Optional<String> optOfNullable2 = Optional.ofNullable("optional");
4. Optional 常用方法详解
4.1 get()
方法
如果 Optional
对象包含值则返回,否则抛出 NoSuchElementException
:
public T get() {
if (value == null) {
throw new NoSuchElementException("No value present");
}
return value;
}
示例:
Person person = new Person();
person.setAge(2);
Optional.ofNullable(person).get();
4.2 isPresent()
方法
用于检查值是否存在:
public Boolean isPresent() {
return value != null;
}
示例:
Person person = new Person();
person.setAge(2);
if (Optional.ofNullable(person).isPresent()) {
System.out.println("不为空");
} else {
System.out.println("为空");
}
4.3 ifPresent()
方法
当值存在时执行指定的代码:
public void ifPresent(Consumer<? super T> consumer) {
if (value != null) consumer.accept(value);
}
示例:
Person person = new Person();
person.setAge(2);
Optional.ofNullable(person).ifPresent(p -> System.out.println("年龄" + p.getAge()));
4.4 filter()
方法
接受一个对象,并根据条件过滤:
public Optional<T> filter(Predicate<? super T> predicate) {
Objects.requireNonNull(predicate);
return !isPresent() ? this : (predicate.test(value) ? this : empty());
}
示例:
Person person = new Person();
person.setAge(2);
Optional.ofNullable(person).filter(p -> p.getAge() > 50);
4.5 map()
方法
对对象进行二次运算并返回封装的 Optional
:
public<U> Optional<U> map(Function<? super T, ? extends U> mapper) {
Objects.requireNonNull(mapper);
return !isPresent() ? empty() : Optional.ofNullable(mapper.apply(value));
}
示例:
Person person = new Person();
String optName = Optional.ofNullable(person).map(p -> person.getName()).orElse("name为空");
4.6 orElse()
和 orElseGet()
方法
如果值为空则返回指定的值:
public T orElse(T other) {
return value != null ? value : other;
}
public T orElseGet(Supplier<? extends T> other) {
return value != null ? value : other.get();
}
示例:
Optional<Supplier<Person>> sup = Optional.ofNullable(Person::new);
Optional.ofNullable(person).orElseGet(sup.get());
4.7 orElseThrow()
方法
当值为空时抛出异常:
public <X extends Throwable> T orElseThrow(Supplier<? extends X> exceptionSupplier) throws X {
if (value != null) {
return value;
} else {
throw exceptionSupplier.get();
}
}
示例:
Member member = memberService.selectByPhone(request.getPhone());
Optional.ofNullable(member).orElseThrow(() -> new ServiceException("没有查询的相关数据"));
5. 实战场景
场景 1:判断查询对象是否存在
Member member = memberService.selectByIdNo(request.getCertificateNo());
Optional.ofNullable(member).orElseThrow(() -> new ServiceException("没有查询的相关数据"));
场景 2:在 DAO 层使用 Optional
public interface LocationRepository extends JpaRepository<Location, String> {
Optional<Location> findLocationById(String id);
}
6. Optional 的使用注意事项
尽管 Optional
非常方便,但它并不能完全替代 if
判断,尤其在以下场景中:
例子:判断对象的某一变量是否为空
Person person = new Person();
person.setName("");
person.setAge(2);
if (StringUtils.isNotBlank(person.getName())) {
// 名称不为空时执行代码块
}
Optional.ofNullable(person).map(p -> p.getName()).orElse("name为空");
对于简单的空值判断,直接使用 if
语句可能更加清晰和直观。
7. JDK 1.9 对 Optional 的优化
JDK 1.9 新增了三个方法:or()
、ifPresentOrElse()
和 stream()
:
- or():如果对象不为空则返回对象,否则返回预设的值。
- ifPresentOrElse():如果对象不为空则执行 Consumer,否则执行 Runnable。
- stream():将 Optional 转换为流,包含值时返回包含值的流,否则返回空流。
Optional 的新方法进一步丰富了操作选择。
评论区