为什么不允许在Java实例初始化块中抛出异常?

cev*_*ing 11 java

当我尝试在实例初始化(而不是类初始化)块中抛出异常时,我得到错误:

initializer must be able to complete normally
Run Code Online (Sandbox Code Playgroud)

尽管Java本身就是这样,为什么不允许这样做?

以下示例创建了四个类.A由于ArithmeticException ,该类在实例化期间失败.这可以用和处理catch.B与NullPointerException失败的相同.但是当我尝试自己抛出一个NullPointerException时,因为在C程序中没有编译.当我尝试定义自己的RuntimeException时,我得到了同样的错误D.所以:

我怎么能像Java一样做?

// -*- compile-command: "javac expr.java && java expr"; -*-

class expr
{
    class A
    {
        int y;
        {{ y = 0 / 0; }}
    }

    class B
    {
        Integer x = null;
        int y;
        {{ y = x.intValue(); }}
    }

    class C
    {
        {{ throw new NullPointerException(); }}
    }

    class Rex extends RuntimeException {}

    class D
    {
        {{ throw new Rex(); }}
    }

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

        try { B b = new B(); }
        catch (Exception e) { System.out.println (e); }

        try { C c = new C(); }
        catch (Exception e) { System.out.println (e); }

        try { D d = new D(); }
        catch (Exception e) { System.out.println (e); }
    }

    public static void main (String argv[])
    {
        expr e = new expr();
        e.run();
    }
}
Run Code Online (Sandbox Code Playgroud)

Dan*_*her 15

初始化程序必须能够正常完成

意味着必须有一个不会引发异常的可能代码路径.您的示例无条件抛出,因此被拒绝.在其他示例中,静态分析不足以确定它们也会抛出所有情况.

例如,

public class StaticThrow {
    static int foo = 0;
    {{ if (Math.sin(3) < 0.5) { throw new ArithmeticException("Heya"); } else { foo = 3; } }}
    public static void main(String[] args) {
        StaticThrow t = new StaticThrow();
        System.out.println(StaticThrow.foo);
    }
}
Run Code Online (Sandbox Code Playgroud)

编译,并在运行时抛出

Exception in thread "main" java.lang.ArithmeticException: Heya
        at StaticThrow.<init>(StaticThrow.java:3)
        at StaticThrow.main(StaticThrow.java:5)
Run Code Online (Sandbox Code Playgroud)

  • 编译器不会对代码进行足够远的分析,以确保始终抛出代码.在你的例子中,你把`{{扔东西; 在静态初始化器中,这很明显.尝试一些永远是真实的东西,但不是很明显,`{{if(Math.sin(3)<0.5){throw new ArithmeticException; } else {whatever; }. (4认同)
  • 谢谢!`if (true) throw ...` 就足够了。 (2认同)

Pet*_*rey 5

Java旨在具有最小的功能,并且只有在有充分理由的情况下才会添加复杂性.Java不问; 为什么不呢,它问道; 我真的需要支持吗?(有时甚至没有;)

必须将初始化块的代码插入到每个构造函数中,这些构造函数具有编译器知道无法正常完成的块,而编译器发现该条件太难以生成代码.

编译器可以编译这个代码,但它不太可能有用.


在这个特定的情况下它不会帮助你,但知道.....很有用

必须声明已检查的异常,并且无法在静态或实例初始化块中声明已检查的异常.

相反,您可以捕获并处理或包装已检查的异常.(或使用技巧,重新抛出)

  • 未经检查的异常会扩展`RuntimeException`.没有好的办法来获取原本会被检查的异常,例如`IOException`,并使其取消选中.但是如果你创建一个直接或间接扩展`RuntimeException`的新类型,那么你可以抛出它的一个实例,而不必添加`throws`子句. (2认同)