在编码过程中相信很多人都曾经被null困扰,在整洁代码之道中建议函数不要返回null也不要传入null作为参数。null代表一种不确定性等同于你需要特定的分支if来进行处理。很多代码充斥着if(null == xxObj) 或if(null != xxObj)着实让人生厌。google开源工具包Guava通过Optional来处理null。Optional认为对象只存在absent和present两种状态.
Present类引用类非null对象,你可以通过Optional.of()来创建Present对象,调用来Preconditions的checkNotNull方法保证Present对象应用的对象非null。
public static <T> Optional<T> of(T reference) {
return new Present<T>(checkNotNull(reference));
}
final class Present<T> extends Optional<T> {
private final T reference;
Present(T reference) {
this.reference = reference;
}
...
}
public static <T> Optional<T> absent() {
return Absent.withType();
}
Optional通过将含义模糊带有不确定性的null让调用方明确转换为Absent和Present两个更加清晰明确的方案。在实际应用中可以考虑以下的方式来处理null:
- 使用特例对象,为常用类建立对应的特例类来处理null,实现相同的接口,通过多态来处理出现null的逻辑。
- 包装null,如Guava的方式,对于明确为null的对象可以转化为Absent对象,Absent类提供了几个基本点操作。Present对象含有一个非null对象的引用。调用Optional的静态方法of时,就直接使用了Preconditions类的静态方法checkNotNull来校验用于包装的对象不为空。Absent和Present就是明确的告诉调用者“不存在null对象,如果你打算调用其中的某些方法,也会明确告诉你非法”,如“Optional.get() cannot be called on an absent value”。
- 对于返回null,可以直接抛出NullPointerException或者其它自定义检查类异常。对于参数中可能存在的null,在函数一开始加入checkNull的逻辑,也可以转化为固定异常或者通过if else来分开处理null和非null。这是有违代码整洁之道,但是在实际开发中出现频率最高的方式。我认为对于null如果接口提供者很清楚null的含义并能够准确清晰的告知调用者,那么将不会出现大的问题。