在大部分情况下,我们写的方法所接受的参数都会有所限制,例如参数不能为null,索引必须大于0等等。
对于这些情况,我们需要在文档注释里清晰的标明这些情况,且在方法的开头就对参数进行有效性校验。这是“发生错误后尽快捕获错误”原则的体现。且这样可以避免参数不正确对程序造成破坏。以避免方法正常运行,但返回值出现错误这种比较难以定义错误位置的情况。
对于访问类型为public和protect的方法来说,我们在文档注释中使用
throws来标注违法参数将会抛出的异常,这些异常有IllegalArgumentException,IndexOutOfBoundException,NullPointerExpection等等。举个栗子:
/***ReturnsaBigIntegerwhosevalueis{
code(thismodm}).Thismethod*differsfrom{coderemainder}inthatitalwaysreturnsa*inon-negative/iBigInteger.**parammthemodulus.*return{codethismodm}*throwsArithmeticException{codem}≤0*see#remainder*/publicBigIntegermod(BigIntegerm){if(m.signum=0)thrownewArithmeticException("BigInteger:modulusnotpositive");BigIntegerresult=this.remainder(m);return(result.signum=0?result:result.add(m));}这是一段来自于bigInteger包装类的源码,你可以在bitInteger.java[1]第行看到它。
mod()这个方法就在开头对与输入的参数m做了一次有效性校验,可以看到,当m≤0的时候,方法或抛出ArithmeticException异常。但你有没有发现,在方法中m.signum校验了空值,方法可能会抛出NullPointerExpection,但在这里的文档注释中并没有标注抛出NullPointerExpection的注释。
这是因为对于NullPointerExpection异常的抛出被写在了bigInteger的类级别文档注释中了,你可以在BigInteger.java[2]的第96行开始,看到对于所有类内参数在接收到Null时会抛出NummPointerException的注释。
这样做的好处是,类级注释是运用到该类的所有公有方法的所有公有参数的。当你在BigInteger类级别的注释文档中说明了异常抛出情况后,就可以避免分别在每个方法注释中重复声明空值可能带来的空指针错误而引发的注释混乱。这个注释可以和
Nullable注解一起使用,标识参数可以为空。在Java7中增加的方法Objects.requireNonNull()方法非常灵活,可以用来进行null检查。举个栗子:
this.name=Objects.requireNonNull(name,"name");
因为Objects.requireNonNull()会返回输入的参数值,因此可以直接在使用一个值的同时进行null值检查。非常的方便。
在Java9中,你还可以使用java.util.Objects来进行对列表和数组索引的范围检查。
对于方位类型为private的方法而言,进行参数校验应当使用断言。断言时在声称被断言判断的条件将会为真,如果断言失败,将会抛出AssertionError。
privatestaticvoidsort(longa[],intoffset,intlength){asserta!=null;assertoffset=0offset=a.length;assertlength=0length=a.length-offset;...//dosomthing
断言的好处在于,如果断言不生效,也不会有性能上的开销。
当然,并不是所有时候我们都需要进行有效性检查,例如在某些情况下,有效性检查的代价非常高。例如排序算法Collections.sort(List),在方法中,每个对象间都会进行比较,如果检测到对象不能相互比较的话,会抛出ClassCastExpection。这是sort()方法应该做的事情,我们就没有必要提前检测参数是否可以互相比较。
进行有效性检查并不意味着我们我们一定要对参数加上限制,恰恰相反,我们在设计方法时,应该尽可能的让方法通用,并符合实际需要。
预览时标签不可点收录于话题#个上一篇下一篇