为什么Java不允许从静态初始化块中抛出已检查的异常?

问题

为什么Java不允许从静态初始化块中抛出已检查的异常?这个设计决定背后的原因是什么?


#1 热门回答(100 赞)

因为无法在源中处理这些已检查的异常。你无法控制初始化过程,并且无法从源调用静态{}块,因此你可以使用try-catch包围它们。

因为你无法处理由已检查异常指示的任何错误,所以决定禁止抛出已检查的异常静态块。

静态块不能抛出检查exceptions但仍允许抛出未经检查/运行时异常。但根据上述原因,你也无法处理这些问题。

总而言之,此限制可防止(或至少使开发人员更难以)构建可能导致应用程序无法恢复的错误的内容。


#2 热门回答(59 赞)

你可以通过捕获任何已检查的异常并将其重新抛出为未经检查的异常来解决此问题。这个未经检查的异常类适用于包装器:java.lang.ExceptionInInitializerError

示例代码:

protected static class _YieldCurveConfigHelperSingleton {

    public static YieldCurveConfigHelper _staticInstance;

    static {
        try {
            _staticInstance = new YieldCurveConfigHelper();
        }
        catch (IOException | SAXException | JAXBException e) {
            throw new ExceptionInInitializerError(e);
        }
    }
}

#3 热门回答(19 赞)

它必须看起来像这样(这是不是有效的Java代码)

// Not a valid Java Code
static throws SomeCheckedException {
  throw new SomeCheckedException();
}

但广告如何抓住它?检查异常需要捕获。想象一下可能初始化类的一些例子(或者可能因为它已经被初始化而没有),并且只是为了引起它将引入的复杂性的注意,我将这些例子放在另一个静态的initalizer中:

static {
  try {
     ClassA a = new ClassA();
     Class<ClassB> clazz = Class.forName(ClassB.class);
     String something = ClassC.SOME_STATIC_FIELD;
  } catch (Exception oops) {
     // anybody knows which type might occur?
  }
}

另一件令人讨厌的事 -

interface MyInterface {
  final static ClassA a = new ClassA();
}

想象一下,ClassA有一个静态初始化器抛出一个检查异常:在这种情况下,MyInterface(这是一个带有'隐藏'静态初始化器的接口)必须抛出异常或处理它 - 接口处的异常处理?最好保持原样。