Tia*_*que 17 java validation constructor object
我正在做一个基本的Java课程,我遇到了一个问题:如果我已经将有效参数传递给构造函数,我该如何创建一个对象?
在实现验证后,我应该创建一个替代类并从那里调用构造函数吗?
或者我应该/可以在类中使用静态方法进行验证吗?
在这种情况下,最佳做法是什么?
ass*_*ias 28
标准做法是验证构造函数中的参数.例如:
class Range {
private final int low, high;
Range(int low, int high) {
if (low > high) throw new IllegalArgumentException("low can't be greater than high");
this.low = low;
this.high = high;
}
}
Run Code Online (Sandbox Code Playgroud)
附注:要验证参数不是null,这是相当常见的,您可以使用:
import static java.util.Objects.requireNonNull;
Constructor(Object o) {
this.o = requireNonNull(o); //throws a NullPointerException if 'o' is null
}
Run Code Online (Sandbox Code Playgroud)
UPDATE
回复您关于社会安全号码的具体评论.一种方法是在类中添加一个方法:
//constructor
public YourClass(String ssn) {
if (!isValidSSN(ssn)) throw new IllegalArgumentException("not a valid SSN: " + ssn);
this.ssn = ssn;
}
public static boolean isValidSSN(String ssn) {
//do some validation logic
}
Run Code Online (Sandbox Code Playgroud)
调用代码可能如下所示:
String ssn = getSsnFromUser();
while(!YourClass.isValidSSN(ssn)) {
showErrorMessage("Not a valid ssn: " + ssn);
ssn = getSsnFromUser();
}
//at this point, the SSN is valid:
YourClass yc = new YourClass(ssn);
Run Code Online (Sandbox Code Playgroud)
通过这种设计,您实现了两件事:
YourClass被滥用会引发异常并且它将帮助你检测错误您可以通过创建一个SSN包含SSN 的类并封装验证逻辑来进一步完善.YourClass然后接受一个SSN对象作为一个参数,它始终是一个有效的SSN构造.
我只是IllegalArgumentException在构造函数本身中抛出一个:
public class MyClass {
private int i;
public MyClass (int i) {
// example validation:
if (i < 0) {
throw new IllegalArgumentException ("i mustn't be negatve!");
}
this.i = i;
}
Run Code Online (Sandbox Code Playgroud)
编程中众所周知的真理是"不要使用例外进行流量控制".您的代码应该在调用构造函数之前了解这些限制并防范它们,而不是处理错误.预期情况存在例外情况,特别是那些无法预测或防范的情况(例如,尽管在上次检查期间可以正常,但IO流可能在写入期间变为无效).
虽然您可以在构造函数中抛出异常,但这并不总是理想的.如果您正在编写您希望被其他人使用/重用的公共对象,则异常是公共构造函数的唯一真正选项,但是这些限制及其结果(例如将抛出的异常)应该在javadoc中清楚地记录下来.类.
对于内部类,断言更合适.正如Oracle所述:"断言......应该用于检查永远不会发生的情况,检查有关数据结构的假设,或对私有方法的参数强制执行约束." - 在Java技术中使用断言.您可能仍应记录您对该类的期望,但您的应用程序应在内部进行任何检查,而不是依赖于抛出的任何异常.
静态工厂方法可以帮助一点,它们的好处正在详细阐述另一个问题:如何使用"静态工厂方法"而不是构造函数.但是,当事情无效时(或返回null,信息量较少),它们不再提供强有力的验证选项.
理想的解决方案是Builder模式.它不仅可以在管理参数时提供更大的灵活性,还可以单独验证每个参数,或者使用可以一次评估所有字段的验证方法.构建器可以并且应该用于隐藏对象的实际构造函数,享受对它的唯一访问并防止任何不需要的值被提交,而断言可以防止"构建器永远不应该提交这些值".