Jon*_*eet 350

是的,构造函数可以抛出异常.通常这意味着新对象立即有资格进行垃圾收集(当然,它可能在一段时间内不会被收集).如果它在构造函数中早先可见(例如,通过指定静态字段或将其自身添加到集合中),那么"半构造"对象可能会留下来.

关于在构造函数中抛出异常要注意的一件事:因为调用者(通常)无法使用新对象,构造函数应该小心避免获取非托管资源(文件句柄等)然后抛出异常没有释放它们.例如,如果构造函数尝试打开a FileInputStream和a FileOutputStream,并且第一个成功但第二个失败,则应尝试关闭第一个流.如果它是抛出异常的子类构造函数,这会变得更难,当然......这一切都变得有点棘手.这不是经常出现的问题,但值得考虑.

  • +1.通常没有人会想到子类抛出的异常. (29认同)
  • @ baris.aydinoz:完全不同意.如果你给构造函数提供了无效的参数,我会*期望它抛出 - 不这样做就是那时的气味. (6认同)
  • @Tarik:代码示例就是这样 - 例如`someStaticField = this;`或构造函数中的`someCollection.add(this)`. (3认同)
  • @jonSkeet,语法上一个构造函数可以抛出并且可以声明它可以抛出.但是,构造函数应该抛出?这里的最佳做法是什么? (2认同)
  • @Ghilteras:我绝对希望通过语言惯用的方式来表达错误:Java中的异常。在我看来,避免这种惯用法是代码体操的源头。同样,当您已经使用依赖注入而不是在代码内调用构造函数时,模拟将更加有效。毕竟,当您调用构造函数时,您将自己约束为该*实现,而模拟的重点通常是模拟*接口*或抽象类,而不是根本不使用实现类。 (2认同)

Bil*_*ain 78

是的,他们可以抛出异常.如果是这样,它们将仅部分初始化,如果不是最终的,则受到攻击.

以下内容来自安全编码指南2.0.

可以通过终结器攻击来访问非最终类的部分初始化实例.攻击者覆盖子类中受保护的finalize方法,并尝试创建该子类的新实例.此尝试失败(在上面的示例中,SecurityManager检查ClassLoader的构造函数会引发安全性异常),但攻击者只是忽略任何异常并等待虚拟机对部分初始化的对象执行最终化.当发生这种情况时,将调用恶意终结方法实现,使攻击者能够访问此对象,即对正在最终确定的对象的引用.尽管该对象仅部分初始化,但攻击者仍然可以在其上调用方法(从而绕过SecurityManager检查).

  • 请注意,仅当您的代码在或可能在安全性很重要的环境中使用时,本指南才有意义。例如,大多数 Java 代码都在没有 SecurityManager 的上下文中使用。 (2认同)

Yuv*_*val 33

绝对.

如果构造函数没有收到有效的输入,或者无法以有效的方式构造对象,则除了抛出异常并警告其调用者之外,它没有其他选择.


V_S*_*ngh 14

是的,它可以抛出异常,您也可以在构造函数的签名中声明它,如下例所示:

public class ConstructorTest
{
    public ConstructorTest() throws InterruptedException
    {
        System.out.println("Preparing object....");
        Thread.sleep(1000);
        System.out.println("Object ready");
    }

    public static void main(String ... args)
    {
        try
        {
            ConstructorTest test = new ConstructorTest();
        }
        catch (InterruptedException e)
        {
            System.out.println("Got interrupted...");
        }
    }
}
Run Code Online (Sandbox Code Playgroud)


Vin*_*lds 11

是的,允许构造函数抛出异常.

但是,选择它们应该是什么例外非常明智 - 检查异常或未选中.未经检查的异常基本上是RuntimeException的子类.

在几乎所有情况下(我都不能对这种情况提出异常),你需要抛出一个检查过的异常.原因是未经检查的异常(如NullPointerException)通常是由于编程错误(如未充分验证输入).

检查异常提供的优点是程序员被迫在其实例化代码中捕获异常,从而意识到可能无法创建对象实例.当然,只有代码审查才会捕获吞噬异常的糟糕编程习惯.


Isa*_*aac 7

是.

构造函数只不过是特殊方法,并且可以像任何其他方法一样抛出异常.