Java8 Optional使用

    xiaoxiao2025-03-30  17

    一.null引用引发的问题,以及为什么要避免null引用

    它是错误之源,NullPointerException是目前Java程序开发中最典型的异常它会使代码膨胀,代码充斥着深度嵌套的null检查,代码的可读性糟糕透顶它破坏了Java的哲学,Java一直试图避免让程序员意识到指针的存在,唯一的例外是:null指针它在Java的类型系统上开了个口子,null并不属于任何类型,这意味着它可以被赋值给任意引用类型的变量。这会导致问题,原因是当这个变量被传递到系统中的另一个部分后,你将无法获知这个null变量最初的赋值到底是什么类型避免NullPointerException的办法(Java8之前) /** * 避免NullPointerException的第一次尝试 * 防御式检查减少NullPointerException * 缺点:if嵌套太多 代码可读性差 不方便扩展 */ public String getCarInsuranceNameWithDefensiveInspection(Person person) { if (Objects.nonNull(person)) { Car car = person.getCar(); if (Objects.nonNull(car)) { Insurance insurance = car.getInsurance(); if (Objects.nonNull(insurance)) { return insurance.getName(); } } } return "Unkown"; } /** * 避免NullPointerException的第二次尝试 * return式检查减少NullPointerException * 缺点:方法有了四个截然不同的退出点,流程是极易出错 */ public String getCarInsuranceNameWithReturnInspection(Person person) { if (Objects.isNull(person)) { return "Unkown"; } Car car = person.getCar(); if (Objects.isNull(car)) { return "Unkown"; } Insurance insurance = car.getInsurance(); if (Objects.isNull(insurance)) { return "Unkown"; } return insurance.getName(); }

    二.Optional类入门 java.util.Optional

    null引用和Optional.empty()的区别 /** * Returns an empty {@code Optional} instance. No value is present for this * {@code Optional}. * * @apiNote * Though it may be tempting to do so, avoid testing if an object is empty * by comparing with {@code ==} against instances returned by * {@code Optional.empty()}. There is no guarantee that it is a singleton. * Instead, use {@link #isPresent()}. * * @param <T> The type of the non-existent value * @return an empty {@code Optional} */ public static<T> Optional<T> empty() { @SuppressWarnings("unchecked") Optional<T> t = (Optional<T>) EMPTY; return t; }

    从语义上,可以把它们当作一回事儿,但是实际中它们之间的差别非常大:如果你尝试引用一个null,一定会触发NullPointerException,不过使用 Optional.empty()就完全没事,它是Optional类的一个有效对象,多种场景都能调用,非常有用

    应用Optional的几种模式 声明一个空的:Optional Optional<Car> optCar = Optional.empty(); 依据一个非空值创建:Optional Optional<Car> optCar = Optional.of(car); 可接受null的Optional: Optional<Car> optCar = Optional.ofNullable(car); 用filter过滤满足条件的判断: //使用Optional前: //Insurance insurance = ...; if(insurance != null && "CambridgeInsurance".equals(insurance.getName())){ System.out.println("ok"); } //使用Optional后: //Optional<Insurance> optInsurance = ...; optInsurance.filter(insurance -> "CambridgeInsurance".equals(insurance.getName())) .ifPresent(x -> System.out.println("ok")); 使用map从Optional对象中提取和转换值: //使用Optional前: if(insurance != null){ name = insurance.getName(); } //使用Optional后: Optional<String> name = Optional.ofNullable(insurance).map(Insurance::getName) 使用flatmap从Optional对象中提取和转换值(多级嵌套对象)//使用Optional前: public String getCarInsuranceNameWithDefensiveInspection(Person person) { if (Objects.nonNull(person)) { Car car = person.getCar(); if (Objects.nonNull(car)) { Insurance insurance = car.getInsurance(); if (Objects.nonNull(insurance)) { return insurance.getName(); } } } return "Unkown"; } //使用Optional后: Optional.ofNullable(person) .flatMap(Person::getCar) .flatMap(Car::getInsurance) .map(Insurance::getName) .orElse("Unkown"); 获取Optional中引用的对象 //get()是这些方法中最简单但又最不安全的方法 public T get() { if (value == null) { throw new NoSuchElementException("No value present"); } return value; } //orElse(T other)它允许你在 Optional对象不包含值时提供一个默认值 public T orElse(T other) { return value != null ? value : other; } //orElseGet(Supplier<? extends T> other)是orElse方法的延迟调用版,Supplier 方法只有在Optional对象不含值时才执行调用 public T orElseGet(Supplier<? extends T> supplier) { return value != null ? value : supplier.get(); } //orElseThrow(Supplier<? extends X> exceptionSupplier)和get方法非常类似, 它们遭遇Optional对象为空时都会抛出一个异常,但是使用orElseThrow你可以定制希望抛出的异常类型 public T orElseThrow() { if (value == null) { throw new NoSuchElementException("No value present"); } return value; } //ifPresent(Consumer<? super T>)让你能在变量值存在时执行一个作为参数传入的 方法,否则就不进行任何操作 public void ifPresent(Consumer<? super T> action) { if (value != null) { action.accept(value); } } 在域模型中使用Optional,以及为什么它们无法序列化

    Optional的设计初衷仅仅是要支持能返回Optional对象的语法,由于Optional类设计时就没特别考虑将其作为类的字段使用,所以它也并未实现 Serializable接口,由于这个原因,如果应用使用了某些要求序列化的库或者框架,在 域模型中使用Optional,有可能引发应用程序故障

    //model中的替代方案 public class Person { private Car car; public Optional<Car> getCarAsOptional() { return Optional.ofNullable(car); } }

    完整代码地址:https://github.com/BoyQiang/personal-code-learning/blob/master/personal-code-learning-customer/src/main/java/com/personal/code/biz/CarBizIml.java

    最新回复(0)