Preconditions优雅的检验参数

在日常开发中,我们经常会对方法的输入参数做一些数据格式上的验证,以便保证方法能够按照正常流程执行下去。对于可预知的一些数据上的错误,我们一定要做事前检测和判断,来避免程序流程出错,而不是完全通过错误处理来保证流程正确执行,毕竟错误处理是比较消耗资源的方式。在平常情况下我们对参数的判断都需要自己来逐个写方法判断,代码量不少并且复用性不高,如下所示:

public class GuavaTest {
    @Test
    public void Preconditions() throws Exception {

        getPerson(28, "zhangsan");

        getPerson(-28, "zhangsan");

        getPerson(28, "");

        getPerson(28, null);
    }

    public static void getPerson(int age, String name) throws Exception {
        if (age > 0 && StringUtils.isNoneBlank(name)) {
            System.out.println("a person age:" + age + ",neme:" + name);
        } else {
            System.out.println("参数输入有误!");
        }
    }
}

说明:参数验证,我们每次都要添加if语句来做判断, 重复的工作会做好多次。getPerson方法只有2个参数,验证规则也不是很复杂,如果参数过度,验证规则复杂后,上面代码的可读性都会很差的,复用性就更谈不上了。

Guava类库中提供了一个作参数检查的工具类--Preconditions类, 该类可以大大地简化我们代码中对于参数的预判断和处理,让我们对方法输入参数的验证实现起来更加简单优雅,下面我们看看Preconditions类的使用实例:

public class GuavaTest {
    @Test
    public void Preconditions() throws Exception {

        getPersonByPrecondition(28, "zhangsan");

        try {
            getPersonByPrecondition(-28, "zhangsan");
        } catch (Exception e) {
            System.out.println(e.getMessage());
        }

        try {
            getPersonByPrecondition(28, "");
        } catch (Exception e) {
            System.out.println(e.getMessage());
        }

        try {
            getPersonByPrecondition(28, null);
        } catch (Exception e) {
            System.out.println(e.getMessage());
        }
    }

    public static void getPersonByPrecondition(int age, String name) throws Exception {
        Preconditions.checkNotNull(name, "neme为null");
        Preconditions.checkArgument(name.length() > 0, "neme为\'\'");
        Preconditions.checkArgument(age > 0, "age 必须大于0");
        System.out.println("a person age:" + age + ",neme:" + name);
    }
}

运行结果:

a person age:28,neme:zhangsan
age 必须大于0
neme为''
neme为null

Preconditions里面的方法

1 .checkArgument

public static void checkArgument(boolean expression) {
    if (!expression) {
        throw new IllegalArgumentException();
    }
}
public static void checkArgument(boolean expression, Object errorMessage) {
    if (!expression) {
        throw new IllegalArgumentException(String.valueOf(errorMessage));
    }
}

功能描述:检查expression是否为真。 用作方法中检查参数失败时抛出IllegalArgumentException异常。

2.checkNotNull 

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

功能描述:检查reference不为null, 直接返回reference;否则抛出NullPointerException异常。

我们使用的时候通常使用第二种,有异常信息更加易读!

3.checkState(boolean,Object):

功能描述:检查对象的一些状态,不依赖方法参数。 例如, Iterator可以用来next是否在remove之前被调用。失败时抛出的异常类型:IllegalStateException

/**
* Ensures the truth of an expression involving the state of the calling instance, but not
* involving any parameters to the calling method.
*
* @param expression a boolean expression
* @param errorMessage the exception message to use if the check fails; will be converted to a
*     string using {@link String#valueOf(Object)}
* @throws IllegalStateException if {@code expression} is false
* @see Verify#verify Verify.verify()
*/
public static void checkState(boolean expression, @Nullable Object errorMessage) {
    if (!expression) {
        throw new IllegalStateException(String.valueOf(errorMessage));
    }
}

4.checkElementIndex(int index, int size,String desc):
功能描述:检查index是否为在一个长度为size的list, string或array合法的范围。 index的范围区间是[0, size)(包含0不包含size)。无需直接传入list, string或array, 只需传入大小。返回index。 失败时抛出的异常类型:IndexOutOfBoundsException

/**
* Ensures that {@code index} specifies a valid <i>element</i> in an array, list or string of size
* {@code size}. An element index may range from zero, inclusive, to {@code size}, exclusive.
*
* @param index a user-supplied index identifying an element of an array, list or string
* @param size the size of that array, list or string
* @param desc the text to use to describe this index in an error message
* @return the value of {@code index}
* @throws IndexOutOfBoundsException if {@code index} is negative or is not less than {@code size}
* @throws IllegalArgumentException if {@code size} is negative
*/
@CanIgnoreReturnValue
public static int checkElementIndex(int index, int size, @Nullable String desc) {
    // Carefully optimized for execution by hotspot (explanatory comment above)
    if (index < 0 || index >= size) {
        throw new IndexOutOfBoundsException(badElementIndex(index, size, desc));
    }
    return index;
}

5.checkPositionIndex(int index, int size,String desc):
功能描述:检查位置index是否为在一个长度为size的list, string或array合法的范围。 index的范围区间是[0, size)(包含0不包含size)。无需直接传入list, string或array, 只需传入大小。返回index。失败时抛出的异常类型:IndexOutOfBoundsException

/**
* Ensures that {@code index} specifies a valid <i>position</i> in an array, list or string of
* size {@code size}. A position index may range from zero to {@code size}, inclusive.
*
* @param index a user-supplied index identifying a position in an array, list or string
* @param size the size of that array, list or string
* @param desc the text to use to describe this index in an error message
* @return the value of {@code index}
* @throws IndexOutOfBoundsException if {@code index} is negative or is greater than {@code size}
* @throws IllegalArgumentException if {@code size} is negative
*/
@CanIgnoreReturnValue
public static int checkPositionIndex(int index, int size, @Nullable String desc) {
    // Carefully optimized for execution by hotspot (explanatory comment above)
    if (index < 0 || index > size) {
        throw new IndexOutOfBoundsException(badPositionIndex(index, size, desc));
    }
    return index;
}

6.checkPositionIndexes(int start, int end, int size):
功能描述:检查[start, end)是一个长度为size的list, string或array合法的范围子集。伴随着错误信息。
失败时抛出的异常类型:IndexOutOfBoundsException                                                                                                                                                          

/**
* Ensures that {@code start} and {@code end} specify a valid <i>positions</i> in an array, list
* or string of size {@code size}, and are in order. A position index may range from zero to
* {@code size}, inclusive.
*
* @param start a user-supplied index identifying a starting position in an array, list or string
* @param end a user-supplied index identifying a ending position in an array, list or string
* @param size the size of that array, list or string
* @throws IndexOutOfBoundsException if either index is negative or is greater than {@code size},
*     or if {@code end} is less than {@code start}
* @throws IllegalArgumentException if {@code size} is negative
*/
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));
    }
}

一个比较实用实例:

public class GuavaTest {
    @Test
    public void Preconditions() throws Exception {

        getPersonByPrecondition(28, "zhangsan");

        try {
            getPersonByPrecondition(-28, "zhangsan");
        } catch (Exception e) {
            System.out.println(e.getMessage());
        }

        try {
            getPersonByPrecondition(28, "");
        } catch (Exception e) {
            System.out.println(e.getMessage());
        }

        try {
            getPersonByPrecondition(28, null);
        } catch (Exception e) {
            System.out.println(e.getMessage());
        }

        List<Integer> intList = new ArrayList<Integer>();
        for (int i = 0; i < 10; i++) {
            try {
                checkState(intList, 9);
                intList.add(i);
            } catch (Exception e) {
                System.out.println(e.getMessage());
            }

        }

        try {
            checkPositionIndex(intList, 3);
        } catch (Exception e) {
            System.out.println(e.getMessage());
        }

        try {
            checkPositionIndex(intList, 13);
        } catch (Exception e) {
            System.out.println(e.getMessage());
        }

        try {
            checkPositionIndexes(intList, 3, 7);
        } catch (Exception e) {
            System.out.println(e.getMessage());
        }

        try {
            checkPositionIndexes(intList, 3, 17);
        } catch (Exception e) {
            System.out.println(e.getMessage());
        }

        try {
            checkPositionIndexes(intList, 13, 17);
        } catch (Exception e) {
            System.out.println(e.getMessage());
        }

        try {
            checkElementIndex(intList, 6);
        } catch (Exception e) {
            System.out.println(e.getMessage());
        }

        try {
            checkElementIndex(intList, 16);
        } catch (Exception e) {
            System.out.println(e.getMessage());
        }
    }

    private static void getPersonByPrecondition(int age, String neme) throws Exception {
        Preconditions.checkNotNull(neme, "neme为null");
        Preconditions.checkArgument(neme.length() > 0, "neme为\'\'");
        Preconditions.checkArgument(age > 0, "age 必须大于0");
        System.out.println("a person age:" + age + ",neme:" + neme);

    }

    private static void checkState(List<Integer> intList, int index) throws Exception {
        //表达式为true不抛异常
        Preconditions.checkState(intList.size() < index, " intList size 不能大于" + index);
    }

    private static void checkPositionIndex(List<Integer> intList, int index) throws Exception {
        Preconditions.checkPositionIndex(index, intList.size(), "index " + index + " 不在 list中, List size为:" + intList.size());
    }

    private static void checkPositionIndexes(List<Integer> intList, int start, int end) throws Exception {
        Preconditions.checkPositionIndexes(start, end, intList.size());
    }

    private static void checkElementIndex(List<Integer> intList, int index) throws Exception {
        Preconditions.checkElementIndex(index, intList.size(), "index 为 " + index + " 不在 list中, List size为: " + intList.size());
    }
}

输出结果:

a person age:28,neme:zhangsan
age 必须大于0
neme为''
neme为null
 intList size 不能大于9
index 13 不在 list中, List size为:9 (13) must not be greater than size (9)
end index (17) must not be greater than size (9)
start index (13) must not be greater than size (9)
index 为 16 不在 list中, List size为: 9 (16) must be less than size (9)

Guava的preconditions有这样几个优点:

在静态导入后, 方法很明确无歧义, checkNotNull可以清楚地告诉你它是干什么的, 它会抛出怎样的异常.
checkNotNull在验证通过后直接返回, 可以这样方便地写代码: this.field = checkNotNull(field).
简单而又强大的可变参数'printf'风格的自定义错误信息.

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值