Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/317.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
在Java中,如果值错误、返回或引发异常,退出构造函数的最佳实践是什么?_Java_Exception - Fatal编程技术网

在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());