Java 8特性:null之殇与optional对象

null 之殇

写 Java 程序,NullPointerException 应该说是非常常见的。Java 语言一直都是希望屏蔽底层指针操作,唯一的例外就是 null 指针,也就是空指针。空指针最大的问题是它违背了类型系统的初衷,相当于在 Java 类型系统上开了一个口子。

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

2009年,在伦敦 QCon 会议上,快速排序的发明者 Tony Hoare 在演讲时对于发明了空指针进行了道歉

I call it my billion-dollar mistake. It was the invention of the null reference in 1965. At that time, I was designing the first comprehensive type system for references in an object oriented language (ALGOL W). My goal was to ensure that all use of references should be absolutely safe, with checking performed automatically by the compiler. But I couldn’t resist the temptation to put in a null reference, simply because it was so easy to implement. This has led to innumerable errors, vulnerabilities, and system crashes, which have probably caused a billion dollars of pain and damage in the last forty years.

在语言中引入空指针仅仅是因为它非常容易在编译器上实现,而不是有什么理论上的必要性。null 在之后困扰着整个软件行业,造成了无数的崩溃。同样,Java 语言不加思索地把 null 吸纳进了 Java 语言,它同样给 Java 程序员带来了不少的麻烦。

不少新兴语言都在语言层面上避免了 null,比如:Rust、Groovy、Scala等等。Java 8 也希望能有一定的补救措施,于是引入了 Optional 类型。

传统上应对 null 的防御式检查

接下来,给出一个示例代码,场景是一个人(Person)可能有汽车(Car),也可能没有汽车;汽车可能有保险(Insurance),也可能没有保险;但是,只要有保险,就一定有保险名字。

public class Person {
   
    private Car car;

    public Car getCar() {
   
        return car;
    }
}

public class Car {
   
    private Insurance insurance;

    public Insurance getInsurace() {
   
        return insurance;
    }
}

public class Insurance {
   
    private String name;

    public String getName() {
   
        return name;
    }
}

深层质疑

假设现在要获取保险的名字,理想状态下,代码是这样的:

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

由于中间可能出现 null,于是有一种很简单粗暴的检查方式:

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

由于刚才说了,保险一定有名字,所以不作检查。这是根据业务来建模。不难看到,上面这种检查方式不具备扩展性,同时还牺牲了代码的可读性。

于是,有人选择换一种检查方式。

过多的退出语句

    public String getCarInsuranceName(Person person) {
   
        if (person == null) {
   
            return "Unknown";
        }
        Car car = person.getCar();
        if (car == null) {
   
            return "Unknown";
        
  • 3
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值