Java 8新特性之Optional取代null

NullPointerException,大家应该都见过。这是Tony Hoare在设计ALGOL W语言时提出的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 p){
        return p.getCar().getInsurance().getName();
    }

这是一个获取保险公司名字的方法,但是在库里可能很多人没有车,所以会返回null引用。更没有车险,所以直接返回一个NullPointerException。

为了避免这种情况,我们一般会在需要的地方添加null的检查,并且添加的方式往往不同。

避免NullPointerException第一次尝试:

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

这个方法每次引用一个变量时,都会做一次null检查,如果任何一个返回值为null,则会返回Unknown。因为知道公司都必须有名字,所以最后一个保险公司的名字没有进行判断。这种方式不具备扩展性,同时还牺牲了代码的可读性。每一次都要嵌套一个if来进行检查。

避免NullPointerException第二次尝试:

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

第二种方式,避免了深层if语句块,采用了每次遇到null都直接返回Unknown字符串的方式。然后这个方案也并非理想,现在这个方法有了四个截然不同的退出点,使代码的维护更艰难。发生null时的默认值,在三个不同的地方出现,不知道具体是哪个返回null。

Optional类

  Java 8中引入了一个新的类java.util.Optional<T>。这是一个封装Optional值的类。当变量存在时,Optional类知识对类简单封装,变量不存在时,缺失的值被建模成一个空的Optional对象,由方法Optional.empty()返回。该方法是一个静态工厂方法,返回Optional类的特定单一实例。

  null和Optional.empty()从语义上,可以当做是一回事。实际上它们之间的差别非常大:如果你尝试访问一个null,一定会触发null引用。而Optional.empty()可以在任何地方访问。

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;
    }
}

公司的名字我们没有使用Optional<String> 而是保持了原类型String,那么它就必须设置一个值。

创建Optional对象

  1.声明一个空的Optional

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

  2.依据一个非空值创建Optional

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

  如果car是null,则直接会报错null引用,而不是等到你访问时。

  3.可接受null的Optional,这种方式与of不同,编译器运行时不会报错。

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

  

使用map从Optional对象中提取和转换值

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/45f2a80f5167657b9aabc74f53c43b42.html