3.6 KiB
3.6 KiB
如何为缺失的值建模
采用防御式检查减少 Null-PointerException
在需要的地方添加 null 的检查, 每一次不确定一个变量是否为 null 时,都需要添加一个进一步的 if 块
每次遭遇 null 变量,返回一个字符串常量"Unknown"
null 带来的种种问题
- 它是错误之源
- 它会使你的代码膨胀
- 它自身是毫无意义的
- 它破坏了 java 的哲学
- 它在 Java 的类型系统上开了个口子
其他语言中 null 的替代品
Groovy 使用安全导航符, Haskell 包含一个 Maybe 类型,本质时对 optional 值的封装, Scala 有类似的结构,叫 Opeion[T]
Optional 类入门
java. util. Optional<T>,这是一个封装 opeional 值的类
应用Optional的几种模式
创建Optional对象
- 声明一个空的 Optional
Optional<Car> optCar = Optional.empty();
- 依据一个非空值创建 Optional
Optional<Car> optCar = Optional.of(car);
// 如果car为null,会立即抛出NullPointerException
- 可接受 null 值的 Optional
Optional<Car> optCar = Optional.ofNullable(car);
使用map从Optional对象中提取和转换值
Optional<Insurance> optInsurance=Optional.ofNullable(insurance);
Optional<String> name=optInsurance.map(Insurance::getName);
- 使用 flatMap 链接 Optional 对象
public String getCarInsuranceName (Optional<Person> person
return person.flatMap(Person::getCar)
.flatMap(Car::getInsurance)
.map(Insurance::getName)
.orElse ( "Unknown" );
}
- 使用 Optional 解引用串接的 Person/Car/Insurance 对象
flatMap(Person::getCar) 获取 Optional<Car>类型对象, 再将 Optional<Car>转换为 Optional<Insurance>。 最后则会将 Optional<Insurance>转化为 Optional<String>对象
Optional 无法序列化
默认行为及解引用Optional对象
- get () 是最简单最不安全的方法,没有对象时抛出 NoSuchElementException 异常
- orElse(T other)允许在 Optional 对象不包含值是提供一个默认方法
- orElseGet(Supplier<? extends T> other)是 orElse 方法的延迟调用版, Supplier 方法只有在 Optional 对象不含值时才执行调用
- orElseThrow(Supplier<? extends X>exceptionSupplier)可以制定希望抛出的异常类型
- ifPresent(Consumer<? super T>)能让你在变量值存在时执行一个作为参数传入的方法,否则就不进行操作
两个 Optional 对象的组合
以不解包的方式组合两个 Optional 对象
public Optional<Insurance> nullSafeFindCheapestInsurance(Optional<Person> person, Optional<Car> car) {
return person.flatMap(p-> car.map(c-> findCheapestInsurance(p, c)));
}
使用 filter 剔除特定的值
查看保险公司名称是否为"CambridgeInsurance"
Optional<Insurance> optInsurance=...;
optInsurance.filter(insurance->"CambridgeInsurance".equals(insurance.getName()))
.ifPresent(x-> System.out.println("ok"));
使用Optional的实战示例
用 Optional 封装可能为 null 的值
Optional<Object> value=Optional.ofNullable(map.get("key"));
异常与 Optional 的对比
public static Optional<Integer> stringToInt(String s) {
try{
return Optional.of(Integer.parseInt(s));
} catch (NulberFormatException e) {
return Optional.empty();
}
}
把所有内容整合起来
public int readDuration(Properties props, String name) {
return Optional.ofNullable(props.getProperty(name))
.flatMap(OptionalUtility::stringToInt)
.filter(i-> i > 0)
.orElse(0);
}