Effective Java 读书笔记——38:检查参数的有效性

来源:互联网 发布:win10下装mac双系统 编辑:程序博客网 时间:2024/06/06 17:36

一般在方法执行之前先检查参数的有效性,如果参数值无效,那么很快它就会失败,并且清楚的抛出合适的异常。

如果这个方法没有检查参数的异常,那么可能在方法处理中出现令人费解的异常。更糟糕的有可能是,方法可以正常返回,但是却使得某个对象处于被破坏的状态.

抛出异常

对于公有方法,可以在Javadoc中的@throw标签来说明违反异常时所抛出的异常类型。一旦在文档中说明了异常,那么强加这些类型的异常检测就会是比较容易的事情,例子如下:

    // Modular Arithmetic Operations    /**     * Returns a BigInteger whose value is {@code (this mod m}).  This method     * differs from {@code remainder} in that it always returns a     * <i>non-negative</i> BigInteger.     *     * @param  m the modulus.     * @return {@code this mod m}     * @throws ArithmeticException {@code m} ≤ 0     * @see    #remainder     */    public BigInteger mod(BigInteger m) {        if (m.signum <= 0)            throw new ArithmeticException("BigInteger: modulus not positive");        BigInteger result = this.remainder(m);        return (result.signum >= 0 ? result : result.add(m));    }

上面这个例子是BigInteger中的求模方法,取模的时候需要其大于0,否则抛出异常。

断言

另外,对于未被导出的方法,作为包的创建者,你可以控制这个方法在哪些情况下可以被调用,因此你可以,也应该确保只将有效的参数传递进去。因此,非公有方法通常应该使用断言(assert)来检查它们的参数,如下:

private static void sort(long a[], int offset, int length) {assert a != null;assert offset >= 0 && offset <= a.length;assert length >= 0 && length <= a.length - offset;}

在生产环境中,一般是不支持assert的,因此这样可以提高效率,没有成本开销。所以,assert只在私有方法中使用,因为私有方法的调用者开发者,他和被调用者之间是一种弱契约关系,或者说没有契约关系,其间的约束是依靠开发者自己控制的,开发者应该有充分的理由相信自己传入的参数是有效的。所以,从某种角度上来说,assert只是起到一个预防开发者自己出错,或者是程序的无意出错。

另外

有一些参数暂时没有直接用到,只是保存起来供以后使用,这种参数的有效性检查也是尤其重要:
    static List<Integer> intArrayAsList(final int[] a) {        if (a == null)            throw new NullPointerException();        return new AbstractList<Integer>() {            public Integer get(int i) {                return a[i];  // Autoboxing (Item 5)            }            @Override public Integer set(int i, Integer val) {                int oldVal = a[i];                a[i] = val;     // Auto-unboxing                return oldVal;  // Autoboxing            }            public int size() {                return a.length;            }        };    }

在上面的例子,传入的是一个int数组,返回的是它的list视图。如果传入的是null,返回了一个新建的list,然后错误的null在后面的程序中可能会非常难以定位。因此,构造器检查参数的有效性是非常重要的,必须保证构造出来的对象是有效的。

例外

尽管在构造器中检查参数的有效性非常必要,但是也有例外,可能在有效情况下检查参数的有效性是及其昂贵的,甚至是不切实际的。比如说,Collections.sort(list)。列表中的所有对象都是可以比较的。在排序过程中会自动检查这些参数的有效性,而并不是在构造的时候检查参数的有效性。

总结

并非对参数的任何限制都是好事,一般来说要尽可能的通用, 符合实际的需要。假如方法对它能接受的参数都能完成合理的计算,那么对于参数的限制其实是越少越好的。因此,鼓励开发者把限制写到文档中,并在方法的开头显式的检查参数的有效性。


0 0
原创粉丝点击