当前位置: 首页 > 科技观察

程序员,你如何检查参数的合法性?

时间:2023-03-22 14:59:53 科技观察

作为程序员,您的代码中有各种方法。你如何验证参数?背景大多数方法和构造函数对传入的参数值都有一些限制,比如:普通索引值必须是非负的,对象引用不能为null。您应该清楚地记录所有这些限制,然后在方法主体的开头强制执行它们的检查。出现错误要尽快检查出来,这是基本原则。如果不这样做,错误发生时将无法检测到,从而更难定位错误源。如果将非法参数传递给方法,则在执行方法之前执行参数检查。它会快速失败并显示一条明确的异常消息。如果该方法不检查参数,则会发生以下情况。级别语句Badmethods在执行过程中失败并抛出一个不明确的异常;更糟糕的方法正常返回,但默默地计算出一个错误的值。最坏的情况是该方法正常返回,但某些对象处于不正确的状态,从而在未来不确定的某个不相关点导致错误。一句话总结:不校验参数会导致原子性失败。推荐做法对于public和protected方法,使用java文档的@throws标签标记参数值不合法时将抛出的异常。参数验证常见的异常类型有以下几种:只要在文档中标注了对方法参数的限制以及违反限制时会抛出的异常,限制就简单了。下面是一个典型的例子。/***@paramm必须是正整数*@throwsArithmeticExceptionifm<=0**/publicBigIntegermod(BigIntegerm){if(m<=0){thrownewArithmeticException("modulus<=0:"+m);}//todoothercode}注意:文档注释并未说明如果m为null,mod将抛出NullPointException,尽管此方法确实如此。调用m.signum()时,此异常会标记在类级BigInteger文档注释中。类级注释适用于所有公共方法参数。这是一种避免在每个方法的单独文档中出现NullPointException的方法。乱七八糟的好方法。可以结合@Nullable或类似的注解来指示特殊参数可以为空,但这种做法并不标准,有许多注解可用于此目的。Java7中添加的Objects实用类Objects.requireNonNull方法非常灵活方便,因此没有理由手动执行空指针检查。您还可以指定异常的详细信息,并且此方法返回其自己的输入,因此您可以在使用该值时执行空指针检查。//一行代码使用java的空指针检查this.strategy=Objects.requireNonNull(strategy,"strategy")如果可以忽略返回值,也可以根据需要使用Objects.requireNonNull作为独立的空指针检查.在Java9中,java.util.Objects中增加了一个范围检查方法,它包含3个方法:这3个方法没有空指针检查方法灵活,它不允许你指定你自己的异常细节,它被设计用于List和Array的索引检查。它也不能处理闭区间,但是在你需要的时候它是一个小小的便利。Java断言,对于一个未公开的方法,你作为包的作者,控制着该方法的调用状态,你必须保证只传入合法的参数值。因此,对于非公开的方法,可以使用断言进行参数检查,如下所示://privatehelpersortingfunctionprivatestaticvoidsort(longa[],intoffset,intlength){asserta!=null;//morecode}本质一般来说,断言声明条件必须为真,忽略客户端如何使用相应的包。与一般的合法性检查不同,AssertError在断言失败时抛出;与一般的合法性检查不同,断言对您没有影响和消耗,除非您启用它们。java命令行启用指令:-ea或-enableassertions断言的更多信息参见java手册中的Asserts;检查参数的有效性非常重要,即使它们没有在您的方法中使用,但已存储,稍后将使用它们。例如:静态工厂方法:输入一个int数组,返回一个数组列表视图。如果客户端传入null,这个方法会抛出NPE,因为这个方法会直接检查调用Objects.requireNonNull。如果忽略检查,该方法将返回一个引用新创建的List的实例;客户端在尝试使用它时会抛出NPE;这时候原始的List实例就很难确定了,可能会复杂到成为调试任务。构造函数代表了该原则的一个特例:您应该检查您将要存储以备后用的参数的有效性。检查构造函数参数的合法性对于防止构造违反类不变性的对象非常重要。例外您应该在执行方法评估之前检查方法参数。这条规则也有例外。一个重要的例外是有效性检查非常昂贵和重要,并且检查是在执行计算的过程中进行的。例如:有一种方法可以对一个对象列表进行排序,比如Collectios.sort(list),列表中的所有对象必须可以相互比较。在处理列表比较时,每个对象都将与其他每个对象进行比较,如果对象不能相互比较,一个或多个比较将抛出ClassCastException,这是排序方法应该做的。所以:这里是一个小店,一开始检查列表中的元素应该相互比较,注意:修改有效性检查将失去原子失败。有时,计算会执行所需的有效性检查,但当检查失败时,会抛出错误的异常。换句话说,计算经常会抛出参数有效性检查的异常,这与方法文档中声明的异常不匹配。在这种情况下,您应该使用异常翻译成语。将自然异常转换为适当的异常。这个原则并不是说任意限制参数是好事,而是说:你应该设计通用的实用方法。假设你的方法接受参数的所有组合并且可以做一些合理的事情,你的参数限制应该尽可能少。然而,一些限制是在抽象类中固有地实现的。总结如果看完只能记住一句话:每次写方法或者构造函数的时候,都要想想是否有参数限制,应该把限制写在文档里,保证在方法的开头身体进行了检查。养成这种习惯很重要,当第一次合法性检查失败时,正确的工作会给你带来回报。