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

问题描述 投票:0回答:7

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

java exception constructor
7个回答
363
投票

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

在构造函数中抛出异常需要注意一件事:因为调用者(通常)无法使用新对象,所以构造函数应该小心避免获取非托管资源(文件句柄等),然后抛出异常异常而不释放它们。例如,如果构造函数尝试打开一个

FileInputStream
和一个
FileOutputStream
,并且第一个成功但第二个失败,则应尝试关闭第一个流。当然,如果它是抛出异常的子类构造函数,这会变得更加困难......这一切都变得有点棘手。这不是一个经常出现的问题,但值得考虑。


79
投票

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

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

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


36
投票

当然。

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


15
投票

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

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

12
投票

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

但是,在选择异常时要非常明智 - 检查异常或未检查异常。未经检查的异常基本上是 RuntimeException 的子类。

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

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


9
投票

是的。

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


0
投票

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

在创建对象之前,有一些场景,比如我们可以将参数发送给构造函数(参数化构造函数),参数验证应该在构造函数中处理并抛出验证异常。

安全检查是在构造函数中抛出异常的另一个常见用例。有些对象在创建过程中需要进行安全检查。如果构造函数执行可能不安全或敏感的操作,我们可以抛出异常。

示例:-

public class Employee{
     private String name;
     private Integer age;
     public Employee(String name, Integer age) throws Exception{
         if (StringUtils.isEmpty(name)){
             throw new Exception("Name can not be empty");
         }
         if (age == null || age  100){
              throw new Exception("Entered age is not a valid one");
         }
         this.name = name;
         this.age = age;
    }
}
© www.soinside.com 2019 - 2024. All rights reserved.