“价值百万的重大失误”---NullPointerException,现在再也不怕了

简介: “价值百万的重大失误”---NullPointerException,现在再也不怕了

作为Java程序员曾经遭遇过NullPointerException,毫无疑问,对任何一位Java程序员来说,无论是初出茅庐的新人,还是久经江湖的专家,NullPointerException都是他心中的痛,可是我们又无能为力,因为这就是我们为了使用方便甚至不可避免的像null引用这样的构造所付出的代价。

历史解决NullPointerException的办法

举例说明

public class Person {
    private Car car;
    public Car getCar() { return car; }
}
public class Car {
    private Insurance insurance;
    public Insurance getInsurance() { return insurance; }
}
public class Insurance {
    private String name;
    public String getName() { return name; }
}

我们该怎么获取到保险公司名字呢?

public String getCarInsuranceName(Person person) {
    return person.getCar().getInsurance().getName();
}

这段代码看起来相当正常,但是现实生活中很多人没有车。所以调用getCar方法的结果会怎样呢?在实践中,一种比较常见的做法是返回一个null引用,表示该值的缺失,即用户没有车。而接下来,对getInsurance的调用会返回null引用的insurance,这会导致运行时出现一个NullPointerException,终止程序的运行。但这还不是全部。如果返回的person值为null会怎样?如果getInsurance的返回值也是null,结果又会怎样?

所以正确的写法应该是:

public String getCarInsuranceName(Person person) {
    if (person != null) {
        Car car = person.getCar();
        if (car != null) {
            Insurance insurance = car.getInsurance();
            if (insurance != null) {
                return insurance.getName();
            }
        }
    }
    return "Unknown";
}

......我为了得到一个名字写了这么多,如果你们公司是按代码行数发工资的话,其实这样也挺好的(哈哈)

null带来的种种问题

它是错误之源

NullPointerException是目前Java程序开发中最典型的异常。

它会使你的代码膨胀

它让你的代码充斥着深度嵌套的null检查,代码的可读性糟糕透顶。

它自身是毫无意义的

null自身没有任何的语义,尤其是,它代表的是在静态类型语言中以一种错误的方式对缺失变量值的建模。

它破坏了Java的哲学

Java一直试图避免让程序员意识到指针的存在,唯一的例外是:null指针。

它在Java的类型系统上开了个口子。

null并不属于任何类型,这意味着它可以被赋值给任意引用类型的变量。这会导致问题,原因是当这个变量被传递到系统中的另一个部分后,你将无法获知这个null变量最初的赋值到底是什么类型。

如何解决---Optional

举例说明

public class Person {
    private Optional<Car> car;
    public Optional<Car> getCar() { return car; }
}
public class Car {
    private Optional<Insurance> insurance;
    public Optional<Insurance> getInsurance() { return insurance; }
}
public class Insurance {
    private String name;
    public String getName() { return name; }
}

我们该怎么获取到保险公司名字呢?

public String getCarInsuranceName(Optional<Person> person) {
    return person.flatMap(Person::getCar)
                 .flatMap(Car::getInsurance)
                 .map(Insurance::getName)
                 .orElse("Unknown");
}

是不是很清晰很舒服
640.png

应用Optional的几种模式

声明一个空的Optional

通过静态工厂方法Optional.empty,创建一个空的Optional对象:

Optional<Car> optCar = Optional.empty();

据一个非空值创建Optional

使用静态工厂方法Optional.of,依据一个非空值创建一个Optional对象:

Optional<Car> optCar = Optional.of(car);

声明一个空的Optional

使用静态工厂方法Optional.ofNullable,可以创建一个允许null值的Optional对象:

Optional<Car> optCar = Optional.ofNullable(car);

默认行为及解引用Optional对象

get()

最简单但又最不安全的方法。如果变量存在,它直接返回封装的变量值,否则就抛出一个NoSuchElementException异常。

orElse(T other)

它允许你在Optional对象不包含值时提供一个默认值。

orElseGet(Supplier<? extends T> other)

orElse方法的延迟调用版,Supplier方法只有在Optional对象不含值时才执行调用。

orElseThrow(Supplier<? extends X> exceptionSupplier)

和get方法非常类似,它们遭遇Optional对象为空时都会抛出一个异常,但是使用orElseThrow你可以定制希望抛出的异常类型。

ifPresent(Consumer<? super T>)

能在变量值存在时执行一个作为参数传入的方法,否则就不进行任何操作。

默认行为及解引用Optional对象

640.png

640.jpg

总结

  1. null引用在历史上被引入到程序设计语言中,目的是为了表示变量值的缺失。
  2. Java 8中引入了一个新的类java.util.Optional,对存在或缺失的变量值进行建模。
  3. 你可以使用静态工厂方法Optional.empty、Optional.of以及Optional.ofNullable创建Optional对象。
  4. 使用Optional会迫使你更积极地解引用Optional对象,以应对变量值缺失的问题,最终,你能更有效地防止代码中出现不期而至的空指针异常。
  5. 使用Optional能帮助你设计更好的API,用户只需要阅读方法签名,就能了解该方法是否接受一个Optional类型的值。
相关文章
|
4月前
|
数据采集 人工智能 自然语言处理
数据应用如何避免无效?瓴羊董芳英:门槛降低和效率提升是关键!
数据应用如何避免无效?瓴羊董芳英:门槛降低和效率提升是关键!
|
5月前
|
存储 监控 安全
当心成本陷阱,这可能会给宝贵的网络安全预算带来压力
当心成本陷阱,这可能会给宝贵的网络安全预算带来压力
|
6月前
|
程序员 开发者
开发者面对焦虑的缓解方式
焦虑是我们每个人在面对未来的不确定性和对自己的不满意时常常遇到的情绪,而且作为技术人员,我们往往面临着工作的挑战和高强度的压力,这可能导致焦虑情绪的出现。但是,作为一个正确的解决方式,一个正确的循环,我们可以通过一些有效方法来对抗焦虑,保持良好的心态和专注力。那么本文就来简单分享一下技术人对抗焦虑的有效方法有哪些,如何变焦虑为动力。
160 3
开发者面对焦虑的缓解方式
|
缓存 前端开发 Java
支付宝二面:使用 try-catch 捕获异常会影响性能吗?大部分人都会答错!
支付宝二面:使用 try-catch 捕获异常会影响性能吗?大部分人都会答错!
156 0
支付宝二面:使用 try-catch 捕获异常会影响性能吗?大部分人都会答错!
|
NoSQL JavaScript 前端开发
P0级事故,项目组慌的一批! 上
P0级事故,项目组慌的一批! 上
|
消息中间件 安全 JavaScript
20k招的工程师刚加入团队,4行代码写3个NPE异常,服了!
20k招的工程师刚加入团队,4行代码写3个NPE异常,服了!
|
缓存 负载均衡 算法
一对一源码开发,减少用户焦虑的三大优化要点
一对一源码开发,减少用户焦虑的三大优化要点
|
SQL 运维 监控
重视失败是让公司成长的几条规则
重视失败是让公司成长的几条规则
223 0
|
缓存 监控 前端开发
惊魂48小时,阿里工程师如何紧急定位线上内存泄露?
云计算场景下的大规模分布式系统中,网络异常、磁盘IO异常、时钟跳变、操作系统异常乃至软件本身可能存在bugs等,均给分布式系统正确运行带来了挑战。持续的监控报警完善是打造稳定高可用分布式系统过程中非常重要的工作,这个也就要求我们研发同学从细节处入手,本文将介绍的场景是针对线上报警的一丝异常,抽丝剥茧找到内存泄露的root cause,全程48小时,跟进修复了潜在风险隐患,并进一步丰富完善监控报警体系的过程。
475 0
惊魂48小时,阿里工程师如何紧急定位线上内存泄露?
|
算法 区块链
区块链电力消耗问题怎么解决?攻城狮们作出了这些努力
如果说区块链技术将彻底改变我们的交易方式,那么,目前摆在许多计算机科学家面前的一大难题还在于——如何解决区块链技术带来的电力消耗问题?
1119 0
下一篇
无影云桌面