大多数方法和构造方法对可以将哪些值传递到其对应参数中有一些限制。 例如,索引值必须是非负数,对象引用必须为非null。 你应该清楚地在文档中记载所有这些限制,并在方法主体的开头用检查来强制执行。 应该尝试在错误发生后尽快检测到错误,这是一般原则的特殊情况。 如果不这样做,则不太可能检测到错误,并且一旦检测到错误就更难确定错误的来源。
    如果将无效参数值传递给方法,并且该方法在执行之前检查其参数,则它抛出适当的异常然后快速且清楚地以失败结束。 如果该方法无法检查其参数,可能会发生一些事情。 在处理过程中,该方法可能会出现令人困惑的异常。 更糟糕的是,该方法可以正常返回,但默默地计算错误的结果。 最糟糕的是,该方法可以正常返回但是将某个对象置于受损状态,在将来某个未确定的时间在代码中的某些不相关点处导致错误。
    对于公共方法和受保护方法,请使用Java文档@throws注解来记在在违反参数值限制时将引发的异常。 通常,生成的异常是IllegalArgumentExceptionIndexOutOfBoundsExceptionNullPointerException。 一旦记录了对方法参数的限制,并且记录了违反这些限制时将引发的异常,那么强制执行这些限制就很简单了。 这是一个典型的例子:

    1. /**
    2. * Returns a BigInteger whose value is (this mod m). This method
    3. * differs from the remainder method in that it always returns a
    4. * non-negative BigInteger.
    5. *
    6. * @param m the modulus, which must be positive
    7. * @return this mod m
    8. * @throws ArithmeticException if m is less than or equal to 0
    9. */
    10. public BigInteger mod(BigInteger m) {
    11. if (m.signum() <= 0)
    12. throw new ArithmeticException("Modulus <= 0: " + m);
    13. ... // Do the computation
    14. }

    请注意,文档注释没有说“如果m为null,mod抛出NullPointerException”,尽管该方法正是这样做的,这是调用m.sgn()的副产品。这个异常记载在类级别文档注释中,用于包含的BigInteger类。类级别的注释应用于类的所有公共方法中的所有参数。这是避免在每个方法上分别记录每个NullPointerException的好方法。它可以与@Nullable或类似的注释结合使用,以表明某个特定参数可能为空,但这种做法不是标准的,为此使用了多个注解。
    在Java 7中添加的Objects.requireNonNull方法灵活方便,因此没有理由再手动执行空值检查。 如果愿意,可以指定自定义异常详细消息。 该方法返回其输入的值,因此可以在使用值的同时执行空检查:

    // Inline use of Java's null-checking facility
    this.strategy = Objects.requireNonNull(strategy, "strategy");
    

    你也可以忽略返回值,并使用Objects.requireNonNull作为满足需求的独立空值检查。
    在Java 9中,java.util.Objects类中添加了范围检查工具。 此工具包含三个方法:checkFromIndexSizecheckFromToIndexcheckIndex。 此工具不如空检查方法灵活。 它不允许指定自己的异常详细消息,它仅用于列表和数组索引。 它不处理闭合范围(包含两个端点)。 但如果它能满足你的需要,那就很方便了。
    对于未导出的方法,作为包的作者,控制调用方法的环境,这样就可以并且应该确保只传入有效的参数值。因此,非公共方法可以使用断言检查其参数,如下所示:

    // Private helper function for a recursive sort
    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;
        ... // Do the computation
    }
    

    本质上,这些断言声称断言条件将成立,无论其客户端如何使用封闭包。与普通的有效性检查不同,断言如果失败会抛出AssertionError。与普通的有效性检查不同的是,除非使用-ea(或者-enableassertions)标记传递给java命令来启用它们,否则它们不会产生任何效果,本质上也不会产生任何成本。
    你应该在执行计算之前显式检查方法的参数,但这一规则也有例外。 一个重要的例外是有效性检查昂贵或不切实际的情况,并且在进行计算的过程中隐式执行检查。 例如,考虑一种对对象列表进行排序的方法,例如Collections.sort(List)。 列表中的所有对象必须是可相互比较的。 在对列表进行排序的过程中,列表中的每个对象都将与其他对象进行比较。 如果对象不可相互比较,则某些比较操作抛出ClassCastException异常,这正是sort方法应该执行的操作。 因此,提前检查列表中的元素是否具有可比性是没有意义的。
    不要从本条目中推断出对参数的任意限制都是一件好事。 相反,你应该设计一些方法,使其尽可能通用。 假设方法可以对它接受的所有参数值做一些合理的操作,那么对参数的限制越少越好。 但是,通常情况下,某些限制是正在实现的抽象所固有的。
    总而言之,每次编写方法或构造方法时,都应该考虑对其参数存在哪些限制。 应该记在这些限制,并在方法体的开头使用显式检查来强制执行这些限制。 养成这样做的习惯很重要。 在第一次有效性检查失败时,它所需要的少量工作将会得到对应的回报。