java.lang.NullPointerException 空指针异常估计是项目中出现频率最高的异常. Optional工具类很好的解决了这个问题,它有两个子类,Present和Absent,从字面意思就可以理解到,一个是不为空,一个为空.
也就是说Optional通过赋予null意义,来做到避免null的情形,及当使用Present时,那么久必须为保证引用不为空,而当程序需要使用null时,则使用 Absent子类去实现.
从Optional源码中我们看到.有四种生成Optional对象的方法:ansent,of,fromNullable,Optional
/**
* Returns an {@code Optional} instance with no contained reference.
*
* <p><b>Comparison to {@code java.util.Optional}:</b> this method is equivalent to Java 8's
* {@code Optional.empty}.
*/
public static <T> Optional<T> absent() {
return Absent.withType();
}
/**
* Returns an {@code Optional} instance containing the given non-null reference. To have {@code
* null} treated as {@link #absent}, use {@link #fromNullable} instead.
*
* <p><b>Comparison to {@code java.util.Optional}:</b> no differences.
*
* @throws NullPointerException if {@code reference} is null
*/
public static <T> Optional<T> of(T reference) {
return new Present<T>(checkNotNull(reference));
}
/**
* If {@code nullableReference} is non-null, returns an {@code Optional} instance containing that
* reference; otherwise returns {@link Optional#absent}.
*
* <p><b>Comparison to {@code java.util.Optional}:</b> this method is equivalent to Java 8's
* {@code Optional.ofNullable}.
*/
public static <T> Optional<T> fromNullable(@Nullable T nullableReference) {
return (nullableReference == null)
? Optional.<T>absent()
: new Present<T>(nullableReference);
}
Optional() {}
absent方法中创建引用缺失的Optional实例; of方法创建指定引用的Optional实例,若引用为null则快速失败; fromNullable方法会通过引用是否为空来 生成对应的对象.而Optional是一个空的构造函数.
同样看Optional的源码中,都是抽象方法
public abstract boolean isPresent(); //如果Optional包含非null的引用(引用存在),返回true
public abstract T get(); //返回Optional所包含的引用,若引用缺失,则抛出java.lang.IllegalStateException
public abstract T or(T defaultValue); //返回Optional所包含的引用,若引用缺失,返回指定的值
public abstract Optional<T> or(Optional<? extends T> secondChoice);
public abstract T or(Supplier<? extends T> supplier);
public abstract T orNull(); //返回Optional所包含的引用,若引用缺失,返回null
public abstract Set<T> asSet(); //返回Optional所包含引用的单例不可变集,如果引用存在,返回一个只有单一元素的集合,如果引用缺失,返回一个空集合。
Absent和Present子类中都有对应的实现.
Guava在Preconditions类中提供了若干前置条件判断的实用方法.
每个方法都有三个变种:
- 没有额外参数:抛出的异常中没有错误消息;
- 有一个Object对象作为额外参数:抛出的异常使用Object.toString() 作为错误消息;
- 有一个String对象作为额外参数,并且有一组任意数量的附加Object对象:这个变种处理异常消息的方式有点类似printf,但考虑GWT的兼容性和效率,只支持%s指示符。例如:
checkArgument(i >= 0, "Argument was %s but expected nonnegative", i);
checkArgument(i < j, "Expected i < j, but %s > %s", i, j);
在编码时,如果某个值有多重的前置条件,我们建议你把它们放到不同的行,这样有助于在调试时定位。 此外,把每个前置条件放到不同的行,也可以帮助你编写清晰和有用的错误消息。
下面只给出没有额外参数情况下的源码.
public static void checkArgument(boolean expression) {
if (!expression) {
throw new IllegalArgumentException();
}
}
public static void checkState(boolean expression) {
if (!expression) {
throw new IllegalStateException();
}
}
public static <T> T checkNotNull(T reference) {
if (reference == null) {
throw new NullPointerException();
}
return reference;
}
public static int checkElementIndex(int index, int size) {
return checkElementIndex(index, size, "index");
}
public static int checkPositionIndex(int index, int size) {
return checkPositionIndex(index, size, "index");
}
public static void checkPositionIndexes(int start, int end, int size) {
// Carefully optimized for execution by hotspot (explanatory comment above)
if (start < 0 || end < start || end > size) {
throw new IndexOutOfBoundsException(badPositionIndexes(start, end, size));
}
}