因为您无法在源代码中处理这些已检查的异常,所以您无法控制初始化过程,也无法从源代码中调用static{}块,以便您可以使用try-catch将其包围。
由于您无法处理已检查异常指示的任何错误,因此决定禁止抛出已检查异常的静态块。
静态块不得抛出已检查异常,但仍允许抛出未检查/运行时异常。但根据上述原因,您也无法处理这些异常。
总之,这个限制防止(或至少使开发人员更难建立)可能导致应用程序无法恢复的错误。
static { if(1 < 10) { throw new NullPointerException(); } }
- Kosi2801您可以通过捕获任何受检异常并将其重新抛出为未经检查的异常来解决该问题。 这个未经检查的异常类作为包装器效果很好: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);
}
}
}
catch(Exception e){
代替。 - kevinarpeSystem.exit(...)
(或等效方法)是你唯一的选择。 - Stephen C它应该看起来像这样(这 不是 有效的Java代码)
// Not a valid Java Code
static throws SomeCheckedException {
throw new SomeCheckedException();
}
但是你如何捕获这个广告呢?Checked exceptions 需要捕获。想象一些可能会初始化该类的示例(或者可能不需要因为它已经被初始化),为了引起注意,我将这些示例放在另一个静态初始化器中以展示它所引入的复杂性:
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(它是一个具有“隐藏”静态初始化器的接口)将不得不抛出异常或处理它-在接口中处理异常?最好保留原样。
main
可以抛出已检查异常。显然这些异常不能被处理。 - Mechanical snailmain()
的线程上,它将异常与堆栈跟踪打印到System.err
,然后调用System.exit()
。最终,这个问题的答案可能是:“因为Java设计者这样说”。 - kevinarpepublic class Test {
static {
int i = 1;
if (i == 1) {
throw new RuntimeException("Bang!");
}
}
public static void main(String[] args) {
try {
// stuff
} catch (Throwable ex) {
// This won't be executed.
System.out.println("Caught " + ex);
}
}
}
$ java Test
Exception in thread "main" java.lang.ExceptionInInitializerError
Caused by: java.lang.RuntimeException: Bang!
at Test.<clinit>(Test.java:5)
try ... catch
来捕获ExceptionInInitializerError
2。Class.forName(...)
来触发类初始化,您可以将调用包含在try
中并捕获ExceptionInInitializerError
或随后的NoClassDefFoundError
。ExceptionInInitializerError
中恢复,那么您可能会遇到障碍。问题在于,在抛出错误之前,JVM会将导致问题的类标记为“失败”。您根本无法使用它。此外,如果其他依赖于失败类的任何其他类尝试初始化,则这些类也将进入失败状态。唯一的前进方式是卸载所有失败的类。对于动态加载的代码而言,这可能是可行的3,但通常并非如此。
1 - 如果静态块无条件引发未检查的异常,则会发生编译错误。这是为了保护程序员免于编写无法处理的异常代码...因为程序员没有办法编写处理程序。这个设计决策背后的原因是什么?
如果您的代码“需要”在静态初始化程序中引发异常,该怎么办?
基本上,有两个选择:如果在块内(完全!)从异常中恢复是可能的,请执行该操作。
否则,请重构代码,使初始化不会发生在静态初始化块(或静态变量的初始化程序)中。将初始化放在可以从常规线程调用的方法或构造函数中。
public class Main
{
static
{
try{Class.forName("whathappenswhenastaticblockthrowsanexception");}
catch (ClassNotFoundException e){throw new RuntimeException(e);}
}
public static void main(String[] args){}
}
输出:Exception in thread "main" java.lang.ExceptionInInitializerError Caused by: java.lang.RuntimeException: java.lang.ClassNotFoundException: whathappenswhenastaticblockthrowsanexception at Main.<clinit>(Main.java:6) Caused by: java.lang.ClassNotFoundException: whathappen...
- Konrad Höffner由于你编写的任何代码都不能调用静态初始化块,因此抛出受检查的 异常
没有用处。如果可能的话,当抛出受检查的异常时,jvm会怎样处理呢?运行时异常
会向上传播。
static {
// Load default strategy implementations from properties file.
// This is currently strictly internal and not meant to be customized
// by application developers.
try {
ClassPathResource resource = new ClassPathResource(DEFAULT_STRATEGIES_PATH, DispatcherServlet.class);
defaultStrategies = PropertiesLoaderUtils.loadProperties(resource);
}
catch (IOException ex) {
throw new IllegalStateException("Could not load '" + DEFAULT_STRATEGIES_PATH + "': " + ex.getMessage());
}
我能够编译并抛出一个已检查的异常,同时……
static {
try {
throw new IOException();
} catch (Exception e) {
// Do Something
}
}