为什么 Java 不允许从静态初始化块中抛出已检查的异常?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/2070293/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Why doesn't Java allow to throw a checked exception from static initialization block?
提问by missingfaktor
Why doesn't Java allow to throw a checked exception from a static initialization block? What was the reason behind this design decision?
为什么 Java 不允许从静态初始化块中抛出已检查的异常?这个设计决定背后的原因是什么?
采纳答案by Kosi2801
Because it is not possible to handle these checked exceptions in your source. You do not have any control over the initialization process and static{} blocks cannot be called from your source so that you could surround them with try-catch.
因为无法在您的源中处理这些已检查的异常。您无法控制初始化过程,并且无法从源调用静态{} 块,因此您可以使用 try-catch 包围它们。
Because you cannot handle any error indicated by a checked exception, it was decided to disallow throwing of checked exceptions static blocks.
由于您无法处理受检异常指示的任何错误,因此决定禁止抛出受检异常静态块。
The static block must not throw checkedexceptions but still allows unchecked/runtime-exceptions to be thrown. But according to above reasons you would be unable to handle these either.
静态块不得抛出已检查异常,但仍允许抛出未检查/运行时异常。但根据上述原因,您也无法处理这些。
To summarize, this restriction prevents (or at least makes it harder for) the developer from building something which can result in errors from which the application would be unable to recover.
总而言之,此限制阻止(或至少使开发人员更难)构建可能导致应用程序无法从中恢复的错误的内容。
回答by Laurent Etiemble
Take a look at the Java Language Specifications: it is stated that it is a compile time error if static initializer failsis able to complete abruptlywith a checked exception.
看一看Java 语言规范:如果静态初始值设定项失败能够通过检查异常突然完成,则说明这是一个编译时错误。
回答by Andreas Dolk
It would have to look like this (this is notvalid Java code)
它必须看起来像这样(这不是有效的 Java 代码)
// Not a valid Java Code
static throws SomeCheckedException {
throw new SomeCheckedException();
}
but how would ad where you catch it? Checked exceptions require catching. Imagine some examples that may initialize the class (or may not because it is already initialized), and just to draw the attention of the complexity of that it would introduce, I put the examples in another static 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?
}
}
And another nasty thing -
还有一件讨厌的事——
interface MyInterface {
final static ClassA a = new ClassA();
}
Imagine ClassA had a static initializer throwing a checked exception: In this case MyInterface (which is an interface with a 'hidden' static initializer) would have to throw the exception or handle it - exception handling at an interface? Better leave it as it is.
想象一下 ClassA 有一个静态初始值设定项抛出一个已检查的异常:在这种情况下 MyInterface(它是一个带有“隐藏”静态初始值设定项的接口)将不得不抛出异常或处理它 - 接口上的异常处理?最好保持原样。
回答by fastcodejava
Since no code you write can call static initialization block, it is not useful to throw checked exceptions
. If it were possible, what would the jvm do when a checked exceptions are thrown? Runtimeexceptions
are propagated up.
由于您编写的任何代码都不能调用静态初始化块,因此抛出已检查没有用exceptions
。如果可能,当抛出受检异常时 jvm 会做什么?Runtimeexceptions
被传播起来。
回答by kevinarpe
You can work around the problem by catching any checked exception and rethrowing it as an unchecked exception. This unchecked exception class works well as a wrapper: java.lang.ExceptionInInitializerError
.
您可以通过捕获任何已检查异常并将其作为未检查异常重新抛出来解决该问题。此未经检查的异常类的工作以及包装:java.lang.ExceptionInInitializerError
。
Sample code:
示例代码:
protected static class _YieldCurveConfigHelperSingleton {
public static YieldCurveConfigHelper _staticInstance;
static {
try {
_staticInstance = new YieldCurveConfigHelper();
}
catch (IOException | SAXException | JAXBException e) {
throw new ExceptionInInitializerError(e);
}
}
}
回答by user2775569
I am able to compile throwing a checked Exception Also....
我也可以编译抛出一个已检查的异常....
static {
try {
throw new IOException();
} catch (Exception e) {
// Do Something
}
}
回答by Stephen C
Why doesn't Java allow to throw a checked exception from a static initialization block?
为什么 Java 不允许从静态初始化块中抛出已检查的异常?
Technically, you can do this. However, the checked exception must be caught within the block. A checked exception is not allowed to propagateout of the block.
从技术上讲,你可以做到这一点。但是,必须在块内捕获已检查的异常。不允许检查的异常传播到块之外。
Technically, it is also possible to allow an unchecked exception to propagate out of a static initializer block1. But it is a really bad idea to do this deliberately! The problem is that the JVM itself catches the unchecked exception, and wraps it and rethrows it as a ExceptionInInitializerError
.
从技术上讲,还可以允许未经检查的异常传播出静态初始化程序块1。但是故意这样做是一个非常糟糕的主意!问题在于 JVM 本身捕获了未经检查的异常,并将其包装起来并作为ExceptionInInitializerError
.
NB: that is an Error
not a regular exception. You should not attempt to recover from it.
注意:这Error
不是一个常规的例外。您不应该尝试从中恢复。
In most cases, the exception cannot be caught:
大多数情况下,无法捕获异常:
public 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)
There is nowhere you can place a try ... catch
in the above to catch the ExceptionInInitializerError
2.
没有任何地方可以try ... catch
在上面放置 a来捕捉ExceptionInInitializerError
2。
In some cases you can catch it. For example, if you triggered the class initialization by calling Class.forName(...)
, you can enclose the call in a try
and catch either the ExceptionInInitializerError
or a subsequent NoClassDefFoundError
.
在某些情况下,您可以抓住它。例如,如果您通过调用 触发了类初始化Class.forName(...)
,则可以将调用括在 a 中try
并捕获 theExceptionInInitializerError
或后续的NoClassDefFoundError
。
However, if you attempt to recoverfrom an ExceptionInInitializerError
you are liable to run into a roadblock. The problem is that before throwing the error, the JVM marks the class that caused the problem as "failed". You simply won't be able to use it. Furthermore, any other classes that depend on the failed class will also go into failed state if they attempt to initialize. The only way forward is to unload all of the failed classes. That mightbe feasible for dynamically loaded code3, but in general it isn't.
但是,如果您尝试从故障中恢复,ExceptionInInitializerError
您很可能会遇到障碍。问题是在抛出错误之前,JVM 将导致问题的类标记为“失败”。你根本无法使用它。此外,任何依赖于失败类的其他类如果尝试初始化,也将进入失败状态。唯一的方法是卸载所有失败的类。这对于动态加载的代码3可能是可行的,但通常不是。
1 - It is a compilation error if a static block unconditionallythrows an unchecked exception.
1 - 如果静态块无条件抛出未经检查的异常,则为编译错误。
2 - You mightbe able to intercept it by registering a default uncaught exception handler, but that won't allow you to recover, because your "main" thread can't start.
2 - 您可以通过注册默认的未捕获异常处理程序来拦截它,但这将不允许您恢复,因为您的“主”线程无法启动。
3 - If you wanted to recover the failed classes, you would need to get rid of the classloader that loaded them.
3 - 如果你想恢复失败的类,你需要摆脱加载它们的类加载器。
What was the reason behind this design decision?
这个设计决定背后的原因是什么?
It is to protect the programmer from writing code that throws exceptions that cannotbe handled!
是为了保护程序员不会写出抛出无法处理的异常的代码!
As we have seen, an exception in a static initializer turns a typical application into a brick. The best thing think that the language designers could do is to deal with the checked case as a compilation error. (Unfortunately, it is not practical to do this for unchecked exceptions as well.)
正如我们所见,静态初始化程序中的异常将典型应用程序变成了砖块。认为语言设计者能做的最好的事情是将检查的情况作为编译错误处理。(不幸的是,对于未经检查的异常也这样做是不切实际的。)
OK, so what should you do if your code "needs" to throw exceptions in a static initializer. Basically, there are two alternatives:
好的,那么如果您的代码“需要”在静态初始值设定项中抛出异常,您应该怎么做。基本上,有两种选择:
If (full!) recovery from the exception within the block is possible, then do that.
Otherwise, restructure your code so that the initialization doesn't happen in a static initialization block (or in the initializers of static variables).
如果(完全!)从块内的异常中恢复是可能的,那么就这样做。
否则,重构您的代码,以便初始化不会发生在静态初始化块(或静态变量的初始化程序)中。
回答by pcdhan
For example: Spring's DispatcherServlet (org.springframework.web.servlet.DispatcherServlet) handles the scenario which catches a checked exception and throws another unchecked exception.
例如:Spring 的 DispatcherServlet (org.springframework.web.servlet.DispatcherServlet) 处理捕获已检查异常并抛出另一个未检查异常的场景。
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());
}