目 录CONTENT

文章目录

不用if (obj != null),轻松解决空指针

在等晚風吹
2024-11-12 / 0 评论 / 0 点赞 / 13 阅读 / 0 字 / 正在检测是否收录...

不用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 的新方法进一步丰富了操作选择。

0

评论区