背景
NPE问题,100%的Java程序员都碰到,并且曾经是心中的痛。
1965年英国TonyHoare引入了Null引用,后续的设计语言包括Java都保持了这种设计。
一个例子
业务模型
Person 有车一族, 有Car字段,
Car 车,每个车都有购买保险, 有Insurance字段;
Insurance 保险,每个保险都有名字 有name字段;
需求:获取某个Person对象的购买保险的名称;
常规编程
public String getCarInsuranceName(Person person) {
return person.getCar().getInsurance().getName();
}
检查式编程
public String getCarInsuranceName_check(Person person) {
if (Objects.nonNull(person)) {
final Car car = person.getCar();
if (Objects.nonNull(car)) {
final Insurance insurance = car.getInsurance();
if (Objects.nonNull(insurance)) {
return insurance.getName();
}
}
}
return "unkown";
}
防御式编程
public String getCarInsuranceName_protect(Person person) {
if (Objects.isNull(person)) {
return "unkown";
}
final Car car = person.getCar();
if (Objects.isNull(car)) {
return "unkown";
}
final Insurance insurance = car.getInsurance();
if (Objects.isNull(insurance)) {
return "unkown";
}
return insurance.getName();
}
对比一下缺点:
编程方法 | 缺点 |
---|---|
常规编程 | NPE问题 |
检查式编程 | 1.可读性不好,多层if嵌套; 2.扩展性不好,需要熟悉全流程,否则不知道应该在哪个if中扩展,极易出错; |
防御式编程 | 1. 维护困难,4个不同的退出点,极易出错,容易遗漏检查项目 |
NPE的痛点
- java程序中出现最多的Exception;没有之一;
- 使得代码量膨胀混乱,对象的空判断充斥在代码中,但是却没有实际的业务意义;
- 类型系统的一个后门,实际上不属于任何类型,也可以说是任何类型;
- 本身无意义,标识对缺失值的建模,也破坏了java中弱化指针的理念。
java8中对缺失值的建模对象是Optional,可以基于它解决NPE的痛点,设计更好的API
Optional
领域模型的建模进化
- Person , 含有一个Optional<Car> car字段,一个人可能有车,也可能没有车;
- Car, 包含有一个Optional<Insurance> insurance字段, 一台车可能买了保险,也可能没有买保险;
- Insurance , 保险公司必定有名字所有,他有一个字段 name;
构造方法
构造方法 | 说明 | 备注 |
---|---|---|
Optional.empty() | 一定是空的对象 | 跟null有区别,是一个单例对象 |
Optional.of(T t) | 一定是不空的对象 | 如果给了null值会立刻抛出NPE |
Optioanl.ofNullable(T t) | 允许为空的对象放在里面 | 使用值之前需要做检查 |
map方法-对象中提取和转换值
原创不易,转载请注明出处。