这个想法是要快速失败。例如,考虑这个愚蠢的类:
public class Foo { private final String s; public Foo(String s) { this.s = s; } public int getStringLength() { return s.length(); }}假设您不想允许使用null值
s。(否则
getStringLength将抛出NPE)。照原样讲课,到您发现
null它的时候,已经太晚了-
很难找到谁把它放在那里。罪魁祸首很可能是完全不同的一类,而这种
Foo情况本来可以在很久以前就建成。现在,您必须对代码库进行梳理,以找出谁可能在其中输入了
null值。
相反,想象一下这个构造函数:
public Foo(String s) { this.s = checkNotNull(s);}现在,如果有人把一个
null在那里,你会发现 马上 -你就会有堆栈跟踪指向正是你走错了电话。
另一个有用的时间是,如果要在执行可以修改状态的操作之前检查参数。例如,考虑此类计算其获得的所有字符串长度的平均值的类:
public class StringLengthAverager { private int stringsSeen; private int totalLengthSeen; public void accept(String s) { stringsSeen++; totalLengthSeen += s.length(); } public double getAverageLength() { return ((double)totalLengthSeen) / stringsSeen; }}调用
accept(null)将引发NPE抛出-
但在
stringsSeen增加之前不会发生。这可能不是您想要的;作为类的用户,我可能希望,如果它不接受null,那么如果您传递null,则其状态应该保持不变(换句话说:调用应该失败,但不应使对象无效)。显然,在此示例中,您还可以通过
s.length()在递增之前获取来解决此问题
stringsSeen,但是您可以看到对于更长且涉及更多的方法,首先检查所有参数是否有效,然后再修改状态可能是有用的:
public void accept(String s) { checkNotNull(s); // that is, s != null is a precondition of the method stringsSeen++; totalLengthSeen += s.length(); }


