通过构造函数抛出异常

时间:2013-01-10 11:16:57

标签: java exception

假设我有以下代码:

public class Conf{    
  public Conf(String szPath) throws IOException, ConfErrorException{
      ...
  }
  public void someMethod(){
    ...
  }
}

然后我想以这种方式实例化对象:

Conf configuration = new Conf("/etc/myapp/myconf.conf");

如果由于某种原因,构造函数抛出任何定义的异常,是否会创建对象?我的意思是,我是否仍然可以访问其中的方法,例如,如下所示码?

Conf configuration;
try{
   configuration = new Conf("/etc/myapp/myconf.conf");
}catch(IOException|ConfErrorException e){
   //Suppose we entered here
   configuration.someMethod();
}

8 个答案:

答案 0 :(得分:5)

  

构造函数抛出任何定义的异常,是否会创建对象?

始终在调用构造函数之前创建对象。否则,构造函数中将没有this对象进行初始化。

如果你抛出一个Exception,你将失去对该对象的引用,除非你做了一些可疑的事情,比如在抛出异常之前将对象存储在构造函数中。

public class Main {
    static class ThrowsException {
        static final List<ThrowsException> BAD_LIST = new ArrayList<>();

        ThrowsException() {
            System.out.println("this = " + this);
            BAD_LIST.add(this);
            throw new RuntimeException();
        }
    }

    public static void main(String... args) {
        for (int i = 0; i < 3; i++) {
            ThrowsException te = null;
            try {
                te = new ThrowsException();
            } catch (Exception ignored) {
            }
            System.out.println("te = " + te);
        }
        System.out.println(ThrowsException.BAD_LIST);
    }

打印

this = Main$ThrowsException@22911fb5
te = null
this = Main$ThrowsException@65b8b5cd
te = null
this = Main$ThrowsException@41a7d9e7
te = null
[Main$ThrowsException@22911fb5, Main$ThrowsException@65b8b5cd, Main$ThrowsException@41a7d9e7]

答案 1 :(得分:5)

让我先从一个失败的对象构造开始,这个场景可以说明如果你可以使用这样的失败对象会出现什么问题:

让我们定义一个A类,以便:

class A {
   private String a = "A";

   public A() throws Exception {
        throw new Exception();
   }
}

现在,我们假设我们想在try...catch块中创建一个类型为A的对象。

A a = null;
try{
  a = new A();
}catch(Exception e) {
  //...
}
System.out.println(a);

显然,此代码的输出将为:null

为什么Java不返回部分构造的A版本?毕竟,在构造函数失败的情况下,name字段成员已经初始化了,对吗?

Java没有这样做,因为该对象未成功构建。该对象处于不一致状态,因此被Java丢弃。您的变量A甚至没有初始化,它保持为null。

现在,正如您所知,要完全构建新对象,必须首先初始化其所有超类。如果其中一个超类无法构建,那么对象的最终状态是什么?无法确定这一点。

看看这个更详细的例子

class A {
   private final int a;
   public A() throws Exception { 
      a = 10;
   }
}

class B extends A {
   private final int b;
   public B() throws Exception {
       methodThatThrowsException(); 
       b = 20;
   }
}

class C extends B {
   public C() throws Exception { super(); }
}

当调用C的构造函数时,如果在初始化B时发生异常,那么最终变量int b的值是多少?

因此,无法创建对象C,它是虚假的,它是垃圾,它没有完全初始化。

答案 2 :(得分:2)

Conf configuration = new Conf("/etc/myapp/myconf.conf");

此代码分三步完成:

  1. 创建所有基础对象。
  2. 创建对象Conf
  3. 分配对configuration
  4. 的引用

    由于您已完成第二步,第二步也不会完成,这意味着configuration将不会被初始化。这意味着configuration 不是 null,甚至没有初始化。您的代码将无法编译。

    然而,由于第一步完成,会有一堆丢失的物品(符合GC条件)。

答案 3 :(得分:2)

不,构造函数抛出异常会突然完成try块。构造函数没有返回任何内容。块中没有更多内容。这意味着,在您的代码中,配置保持不变。

答案 4 :(得分:1)

将创建一个对象但您永远不会收到对它的引用。就目前而言,您的代码永远不会编译:

Conf configuration;
try{
    configuration = new Conf("/etc/myapp/myconf.conf");
}catch(IOException|ConfErrorException e){
    //Suppose we entered here
   configuration.someMethod();
}

编译器认识到configuration在到达catch块时可能不会被初始化。

答案 5 :(得分:0)

  

如果由于某种原因,构造函数抛出任何定义的异常,是否会创建对象?

没有。如果构造函数抛出异常,则引用configuration将不会赋值。

请参阅:What conditions cause object instantiation to return null?

答案 6 :(得分:0)

不,如果对象的构造函数抛出异常,则不会获取对象的实例。

它是不应该由构造函数创建的单例对象的“最佳”方法之一。

答案 7 :(得分:-1)

不,如果在初始化对象时抛出异常,则不会创建该对象。