构造函数可以在Java中抛出异常吗?

构造函数可以在Java中抛出异常吗?,java,exception,constructor,Java,Exception,Constructor,是否允许构造函数抛出异常?绝对允许 如果构造函数没有接收到有效的输入,或者无法以有效的方式构造对象,那么它除了抛出异常并通知调用方之外别无选择。是 构造函数只不过是特殊的方法,可以像其他方法一样抛出异常 是的,构造函数可以抛出异常。通常这意味着新对象可以立即进行垃圾收集(当然,它可能在一段时间内不会被收集)。但是,如果“半构造”对象在构造函数的早期使其自身可见(例如,通过指定静态字段或将其自身添加到集合),则它可能会保留 在构造函数中抛出异常需要注意的一点是:因为调用方(通常)无法使用新对象,所

是否允许构造函数抛出异常?

绝对允许

如果构造函数没有接收到有效的输入,或者无法以有效的方式构造对象,那么它除了抛出异常并通知调用方之外别无选择。


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

是的,构造函数可以抛出异常。通常这意味着新对象可以立即进行垃圾收集(当然,它可能在一段时间内不会被收集)。但是,如果“半构造”对象在构造函数的早期使其自身可见(例如,通过指定静态字段或将其自身添加到集合),则它可能会保留


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

是的,构造函数可以抛出异常

但是,在选择应该检查哪些异常时要非常明智——检查异常还是不检查异常。未经检查的异常基本上是RuntimeException的子类

在几乎所有的情况下(我不能为这种情况想出一个异常),您都需要抛出一个选中的异常。原因是未经检查的异常(如NullPointerException)通常是由于编程错误(如未充分验证输入)造成的


检查异常提供的优点是,程序员被迫在其实例化代码中捕获异常,从而意识到创建对象实例可能会失败。当然,只有代码审查才能发现吞咽异常的糟糕编程实践。

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

以下内容来自

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


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

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...");
        }
    }
}

+1.通常没有人会想到子类引发的异常。@塔里克:代码示例正好可以做到这一点-例如
someStaticField=this
someCollection。在构造函数中添加(this)
。@jonSkeet,从语法上讲,构造函数可以抛出,也可以声明它可以抛出。然而,构造函数是否应该抛出?这里的最佳做法是什么?@baris.aydinoz:完全不同意。如果您向构造函数提供无效参数,我希望它会抛出-不这样做会让人感觉不舒服。@Ghilteras:而我更愿意用语言惯用的方式来表达错误:也就是通过Java中的异常来表达错误。在我看来,避免这个习语是代码体操的用武之地。同样,当您已经使用依赖项注入而不是在代码中调用构造函数时,模拟会更加有效。毕竟,当您调用构造函数时,您将自己限制在该实现上,而模拟的目的通常是模拟接口或抽象类,而不是使用实现类。这是否意味着从非final类抛出会违反安全性?这仍然是一个问题吗?请注意,只有当您的代码正在或可能在安全性非常重要的上下文中使用时,此指南才相关。例如,大多数Java代码都是在没有SecurityManager的环境中使用的。在调用超级构造函数之前进行检查可以避免这个问题。当您在此时抛出时,
finalize()
将永远不会被调用。此外,在将任何值分配给实例字段之前,您应该始终检查所有值,因为这样,“部分初始化”意味着“不可用”,因此没有安全风险。语句中的重要内容是“特殊方法”。因此,它们不同于任何其他方法。从非最终类的构造函数抛出异常可能会造成安全漏洞,因此在决定这样做时应特别小心。请参阅上面@Billy的答案,以及Java安全编码指南的摘录。