Skip to content

Latest commit

 

History

History
121 lines (98 loc) · 4.85 KB

基本工具.md

File metadata and controls

121 lines (98 loc) · 4.85 KB

使用和避免null

java.lang.NullPointerException 空指针异常估计是项目中出现频率最高的异常. Optional工具类很好的解决了这个问题,它有两个子类,Present和Absent,从字面意思就可以理解到,一个是不为空,一个为空.

也就是说Optional通过赋予null意义,来做到避免null的情形,及当使用Present时,那么久必须为保证引用不为空,而当程序需要使用null时,则使用 Absent子类去实现.

创建Optional实例

从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实例查询引用

同样看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));
    }
  }