在Java中,如果值错误、返回或引发异常,退出构造函数的最佳实践是什么?
我有一个关于最佳实践的问题 假设我有一门课:在Java中,如果值错误、返回或引发异常,退出构造函数的最佳实践是什么?,java,exception,Java,Exception,我有一个关于最佳实践的问题 假设我有一门课: public class test { int value = 0; int value2 = 0; boolean valid = true; test(int a, int b) { if (a>5){ this.value = a; } else{ this.valid = false;
public class test {
int value = 0;
int value2 = 0;
boolean valid = true;
test(int a, int b) {
if (a>5){
this.value = a;
}
else{
this.valid = false;
return;
}
if (b>100){
this.value2=b;
}
else{
this.valid = false;
return;
}
}
public static void main(String[] args){
test t = new test(6,120);
System.out.println(t.valid);
System.out.println(t.value);
System.out.println(t.value2);
}
}
如您所见,我想构造这个类,但我还想检查这些值是否在预期范围内。如果没有,忘记其他事情,因为结果是错误的。在这种情况下,继续构造对象是没有用的,因此我也可以立即退出
正如输出在最后所证明的那样,使用返回完成工作。
但这被认为是最佳实践吗?还是我应该提出例外?还是没关系
使用异常,我可以看到哪一个完全失败,但我也可以打印出来
谢谢
thx.抛出异常是好的,因为它可以明显防止非法使用,并且可以提供信息,而不是长期使用对象。这种QA原则称为快速失效 你选择了一个较轻的使用。可选类也确保了安全使用。以肯定或否定的方式
public class Test {
public final int a;
public final int b;
private Test(int a, int b) {
this.a = a;
this.b = b;
}
public static Optional<Test> create(int a, int b) {
if (a <= 5 || b <= 100) {
return Optional.empty();
} else {
return Optional.of(new Test(a, b));
}
}
public static void main(String[] args){
Optional<Test> t = Test.create(6, 120);
System.out.println(t.isPresent());
t.ifPresent(x -> System.out.printf("(%d %d)%n", x.a, x.b));
}
}
公共类测试{
公共最终INTA;
公共最终int b;
专用测试(int a、int b){
这个a=a;
这个.b=b;
}
公共静态可选创建(int a、int b){
如果(a我不知道它是否被正式认可为最佳实践,但在我看来,在这种情况下,您应该更喜欢抛出异常。返回无效实例可能会导致在不应该使用它们的时候使用它们,这肯定是不好的。您可以忘记检查它们是否有效,因此错误迟早会发生
它还有另一个影响。如果您创建并引用实例,垃圾收集器将不会删除它。这意味着您将在不需要时使用内存。已经有另一个实例对此进行了详细解释
关于验证输入,也许您可以使用注释来提高可读性,不再担心自己做。这取决于您。好吧,您有2
选项:
如果您从构造函数返回
public MyClass() {
...
if (somethingWentWrong)
return;
// This initialization will never run on somethingWentWrong
myField = ...
...
}
您将创建部分实例,这几乎肯定是不正确的;更糟糕的是:由于构造函数的代码是类的私有事务,我们不知道实例出了什么问题
MyClass myClass = new MyClass();
// Is it safe to execute the line below? We don't know
DoSomething(myClass.getMyField());
另一方面,抛出异常
确保您有一个有效的实例或根本没有实例:
...
MyClass myClass = new MyClass();
// It's safe now : if somethingWentWrong appeared
// 1. myClass will not be assigned
// 2. This line will never be executed
DoSomething(myClass.getMyField());
我认为在这种情况下最好的解决方案是抛出一个IllegalArgumentException:
抛出新的IllegalArgumentException();
如果构造函数出现问题,有两种选择:
构造函数可以返回:
- 这将隐式返回正在构造的对象,而不是
null
或其他类的实例
- 调用方获取一个部分创建的对象
- 调用方通常必须对此进行测试。这意味着:
- 部分对象中需要有字段来记录错误信息,以及检查状态和返回错误信息的方法
- 调用者1需要记住测试对象
- 其他API方法的类也可能需要处理部分构造的对象,以避免异常和其他异常行为
- 类的子类需要处理这样的情况:
super()
为它们提供了超类的部分实例
此构造函数可能引发异常
- 问题的解释和细节可以(应该)作为例外的一部分
- 不会返回任何对象
- 调用方可以捕获异常或允许它传播
- 由于无法返回任何部分对象:
- 调用方不需要测试结果
- 该类不需要实现状态和/或错误信息字段或方法
< P>类不需要考虑其他方法中的部分对象的行为。
>P>子类不需要考虑部分超类。(构造函数不能捕获在<代码>()中抛出的异常< /代码>!
主要的缺点是最终需要捕获和处理异常。对于已检查的异常,还存在添加抛出子句的(编码)开销
第二个缺点是跨线程边界传递或传播异常会使事情复杂化
在部分对象方法中,上述因素(我声称)使类和调用方更加复杂,并且更容易出现难以调试的错误2
作为一般规则,我认为Java中的错误处理更容易使用异常。这就是它们的主要设计目的。如果将异常抛出到尽可能靠近错误源的位置,并允许传播到处理它们的最佳位置,这也是最好的
简而言之,我的观点3是抛出异常几乎总是比返回部分构造的对象更好
1-最有可能是在调用之后或接近调用时。传递部分对象可能会使问题复杂化,并增加调用方代码需要检查和处理部分对象的位置
2-我声称,导致stacktrace的bug通常比导致错误输出或意外行为的bug更容易调试。例外是你的朋友
3…可能是最有经验的Java程序员…抛出异常和/或日志记录都是不错的选择。如果您从构造函数返回,您将有一个部分创建的实例,这几乎肯定是不正确的;抛出异常
让其他人知道实例在一次管理中是错误的,但那将是错误的在这种情况下就足够了,因为在函数中
...
MyClass myClass = new MyClass();
// It's safe now : if somethingWentWrong appeared
// 1. myClass will not be assigned
// 2. This line will never be executed
DoSomething(myClass.getMyField());