Google Guava之Preconditions

文中所述Guava版本基于29.0-jre,文中涉及到的代码完整示例请移步Github查看。

如何编写参数条件判定语句

在我们编写一些方法的时候,都需要对方法传入的参数进行一些条件限定,比如

/**
 * 以自然顺序比较两个字符串并返回较大的字符串
 */
public String compare(String firstString, String secondString) {
    if (firstString == null) {
        throw new NullPointerException("Argument 'firstString' expected non-null");
    }
    if (secondString == null) {
        throw new NullPointerException("Argument 'secondString' expected non-null");
    }
    if (firstString.compareTo(secondString) >= 0) {
        return firstString;
    }
    return secondString;
}

这样当条件不满足的时候,就会打印出对应的异常,能够帮助我们快速定位错误原因,但是如果每个参数都需要编写类似这样if判断的语句,就让代码很臃肿。Guava提供一个工具类,帮助我们方便的值进行条件判定。

/**
 * 以自然顺序比较两个字符串并返回较大的字符串
 */
public String compareSimple(String firstString, String secondString) {
    Preconditions.checkNotNull(firstString, "Argument 'firstString' expected non-null");
    Preconditions.checkNotNull(secondString, "Argument 'secondString' expected non-null");
    if (firstString.compareTo(secondString) >= 0) {
        return firstString;
    }
    return secondString;
}

这样将原本需要if判断的代码语句简化为单条Preconditions语句,其实Preconditions也就是替我们做了if的判断,checkNotNull的源代码如下

@CanIgnoreReturnValue
public static <T> T checkNotNull(T reference, @Nullable Object errorMessage) {
    if (reference == null) {
        throw new NullPointerException(String.valueOf(errorMessage));
    } else {
        return reference;
    }
}

java.util包中也有实现类似功能的工具类,就是java.util.Objects,我们来看下java.util.Objects的用法

Objects.requireNonNull(secondString, "Argument 'secondString' expected non-null");

既然已经有了类似的方法,为什么Guava还要重复造轮子呢?原因在于java.util.Objects提供的条件判定方案太少,另外Guava提供更方便的异常信息打印(Preconditions提供可变参数列表,可供我们打印多余信息,比如可以在条件不满足时打印上下文变量值,下文可看到在条件不满足时打印出方法所有参数值)。

但是我仍认为Preconditions提供的功能不是很完美,首先Preconditions.checkNotNull(firstString)只有单个参数时,如果firstString为null,则打印的时没有异常信息的空指针异常,这导致我们想要获取异常详细信息都需要自己来编写异常提示信息

java.lang.NullPointerException
	at com.google.common.base.Preconditions.checkNotNull(Preconditions.java:878)

我希望Preconditions提供的条件判定语句在只提供单个参数时,能够自己组织一条有意义的异常提示信息。

另外如果对于某个参数需要多重条件判断,比如我们判定参数firstString既要不为null,也要长度大于5,这时候就需要写两条Preconditions语句

/**
 * 以自然顺序比较两个字符串并返回较大的字符串
 */
public String compareSimple(String firstString, String secondString) {
    Preconditions.checkNotNull(firstString, "Argument 'firstString' expected non-null", firstString, secondString);
    Preconditions.checkArgument(firstString.length() > 5, "Argument 'firstString' expected length > 5", firstString, secondString);
    Preconditions.checkNotNull(secondString, "Argument 'secondString' expected non-null");
    if (firstString.compareTo(secondString) >= 0) {
        return firstString;
    }
    return secondString;
}


// caller
compareSimple("test", "test");


// output
java.lang.IllegalArgumentException: Argument 'firstString' expected length > 5 [test, test]

我们也可以把两条Preconditions语句合为单条

Preconditions.checkArgument(firstString != null && firstString.length() > 5, "Argument 'firstString' expected non-null and length > 5", firstString, secondString);

但是这种情况下当参数为null或者长度小于5时,打印相同的信息,不利于我们对失败原因的判定,建议Guava在以后能够提供满足多条件判定的Preconditions语句

Preconditions提供的方法

方法签名 描述 失败时抛出的异常
checkArgument(boolean) 检查条件判定的布尔值是否是true,用来判定方法的参数。 IllegalArgumentException
checkNotNull(T) 检查值是否为null,不为null则返回该值。 NullPointerException
checkState(boolean) 检查对象的某些状态,不依赖于方法参数。例如,一个Iterator可能会使用它来检查在调用remove之前是否已调用next。 IllegalStateException
checkElementIndex(int index, int size) 检查索引是否为列表,字符串或数组的有效元素索引。元素索引可能是[0, size),不需要把列表,字符串或数组作为参数传递,直接传递它的size。返该方法返回值为index。 IndexOutOfBoundsException
checkPositionIndex(int index, int size) 检查索引是否为列表,字符串或数组的有效元素索引。元素索引可能是[0, size],不需要把列表,字符串或数组作为参数传递,直接传递它的size。返该方法返回值为index。 IndexOutOfBoundsException
checkPositionIndexes(int start, int end, int size) 检查[start, end)是否是列表,字符串或数组的有效子范围。返回代码自组织的错误信息。 IndexOutOfBoundsException

参考

posted @ 2020-05-25 09:52  weegee  阅读(490)  评论(0编辑  收藏  举报