让构造函数抛出异常是很好的做法吗?

内容来源于 Stack Overflow,并遵循CC BY-SA 3.0许可协议进行翻译与使用

  • 回答 (2)
  • 关注 (0)
  • 查看 (13)

让构造函数抛出异常是一个好习惯吗?例如,我有一个Person,我有age其唯一的属性。现在我提供这个

class Person{
  int age;
  Person(int age) throws Exception{
   if (age<0)
       throw new Exception("invalid age");
   this.age = age;
  }

  public void setAge(int age) throws Exception{
  if (age<0)
       throw new Exception("invalid age");
   this.age = age;
  }
}
提问于
用户回答回答于

我一直认为在构造函数中抛出检查异常是不好的习惯,或者至少应该避免的东西。

原因是你不能这样做:

private SomeObject foo = new SomeObject();

相反,你必须这样做:

private SomeObject foo;
public MyObject() {
    try {
        foo = new SomeObject()
    } Catch(PointlessCheckedException e) {
       throw new RuntimeException("ahhg",e);
    }
}

在构建SomeObject的时候,我知道它的参数是什么,为什么我需要将它包装在try catch中呢?啊,你说,但如果我从动态参数构造一个对象,我不知道它们是否有效。那么,你可以......在将参数传递给构造函数之前验证这些参数。这将是一个很好的做法。如果你关心的是参数是否有效,那么你可以使用IllegalArgumentException。

所以,而不是抛出检查异常只是做

public SomeObject(final String param) {
    if (param==null) throw new NullPointerException("please stop");
    if (param.length()==0) throw new IllegalArgumentException("no really, please stop");
}

当然,有些情况下抛出一个检查的异常可能是合理的

public SomeObject() {
    if (todayIsWednesday) throw new YouKnowYouCannotDoThisOnAWednesday();
}

但多久可能呢?

用户回答回答于

在构造函数中抛出异常并不是不好的习惯。事实上,这是施工人员说明存在问题的唯一合理方式; 例如参数无效。

但是明确宣布或抛出java.lang.Exception几乎总是不好的做法。

你应该选择一个与发生的异常情况相匹配的异常类。如果抛出Exception它,则调用者很难将此异常与任何其他可能的已声明和未声明的异常分开。这使得错误恢复困难,并且如果调用者选择传播异常,问题就会扩散。

有人建议使用assert检查参数。这样做的问题是,assert通过JVM命令行设置可以打开和关闭断言检查。使用断言来检查内部不变量是可以的,但使用它们来实现在javadoc中指定的参数检查不是一个好主意......因为这意味着只有在启用断言检查时,你的方法才会严格执行规范。

第二个问题assert是,如果一个断言失败了,那么AssertionError就会被抛出,并且得到的智慧是,尝试捕获它的任何子类型是一个坏主意Error

扫码关注云+社区