JavaSE7中抑制的异常
我试图理解Java SE7中被抑制的异常,我在下面发布了两个示例,它们很相似,在下面的示例中,我的印象是,当新的“主异常”发生时,被抑制的异常会被忽略,例如,我希望输出为“Java.lang.RuntimeException:y”,但答案是:JavaSE7中抑制的异常,java,exception-handling,Java,Exception Handling,我试图理解Java SE7中被抑制的异常,我在下面发布了两个示例,它们很相似,在下面的示例中,我的印象是,当新的“主异常”发生时,被抑制的异常会被忽略,例如,我希望输出为“Java.lang.RuntimeException:y”,但答案是: java.lang.RuntimeException:y 抑制的java.lang.RuntimeException:a 代码如下: class Animal implements AutoCloseable{ @Override pub
java.lang.RuntimeException:y
抑制的java.lang.RuntimeException:a
代码如下:
class Animal implements AutoCloseable{
@Override
public void close() {
throw new RuntimeException("a");
}
}
public class ExceptionsDemo {
public static void main(String[] args) throws IOException {
try(Animal a1 = new Animal();){
foo();
}
catch(Exception e){
System.err.println(e);
for(Throwable t : e.getSuppressed()){
System.err.println("suppressed "+ t);
}
}
}
static void foo() {
try {
throw new RuntimeException("x");
} catch (Exception e) {
throw new RuntimeException("y");
}
}
}
我的理解是,在tryWithResources子句之后,“a”是主Exc,然后在foo()中,x成为主Exc,而a被抑制,但在catch中,我认为y将成为单独的主Exc,并将忽略所有其他异常,包括抑制的异常?就像第二个示例,它实现了我刚才提到的,它输出java.lang.RuntimeException:c,没有抑制的异常
public class ExceptionDemo2 {
class Animal implements AutoCloseable{
@Override
public void close() {
throw new RuntimeException("a");
}
}
public static void main(String[] args) {
try{
new ExceptionDemo2().go();
}
catch(Exception e){
System.err.println(e);
for(Throwable t : e.getSuppressed()){
System.err.println("suppressed "+ t);
}
}
}
void go(){
try(Animal a = new Animal()){
throw new IOException();
}catch(Exception e){
throw new RuntimeException("c");
}
}
}
输出:java.lang.RuntimeException:c
您的示例
try(Animal a1 = new Animal();){
foo();
}
catch(Exception e){
System.err.println(e);
for(Throwable t : e.getSuppressed()){
System.err.println("suppressed "+ t);
}
}
终止,因为foo()
抛出运行时异常(y
)。这就是捕获的目标。因为执行会离开try
块,所以所有声明的资源都将关闭。关闭Animal
实例时,会抛出另一个RuntimeException
(a
)。那一个被抑制了,因为它不是根本原因
JLS中解释了将try with resources
转换为try catch finally
块的过程
基本的try with resources语句的含义:
try ({VariableModifier} R Identifier = Expression ...)
Block
{
final {VariableModifierNoFinal} R Identifier = Expression;
Throwable #primaryExc = null;
try ResourceSpecification_tail
Block
catch (Throwable #t) {
#primaryExc = #t;
throw #t;
} finally {
if (Identifier != null) {
if (#primaryExc != null) {
try {
Identifier.close();
} catch (Throwable #suppressedExc) {
#primaryExc.addSuppressed(#suppressedExc);
}
} else {
Identifier.close();
}
}
}
}
通过以下对局部变量声明的转换给出
还有一个try-catch-finally语句:
try ({VariableModifier} R Identifier = Expression ...)
Block
{
final {VariableModifierNoFinal} R Identifier = Expression;
Throwable #primaryExc = null;
try ResourceSpecification_tail
Block
catch (Throwable #t) {
#primaryExc = #t;
throw #t;
} finally {
if (Identifier != null) {
if (#primaryExc != null) {
try {
Identifier.close();
} catch (Throwable #suppressedExc) {
#primaryExc.addSuppressed(#suppressedExc);
}
} else {
Identifier.close();
}
}
}
}
在哪里
如果资源规范声明了一个资源,那么
ResourceSpecification\u tail
为空(并且try catch finally
语句本身不是try with resources语句)
上面的代码基本上可以转换为
try {
final Animal a1 = new Animal();
Throwable thr = null;
try {
foo();
} catch (Throwable root) {
thr = root;
throw root;
} finally {
if (a1 != null) {
if (thr != null) {
try {
a1.close();
} catch (Throwable suppressed) {
thr.addSuppressed(suppressed); // <<<<<< suppressing the failure of 'close'
}
} else {
a1.close();
}
}
}
} catch (Exception e) {
System.err.println(e);
for (Throwable t : e.getSuppressed()) {
System.err.println("suppressed " + t);
}
}
试试看{
最终动物a1=新动物();
可丢弃thr=null;
试一试{
foo();
}捕获(可丢弃的根){
thr=根;
生根;
}最后{
如果(a1!=null){
如果(thr!=null){
试一试{
a1.关闭();
}捕捉(可丢弃抑制){
Oracle文档中的thr.addsupprested(supprested);//:
如果从try块引发异常,并且从try with resources语句引发一个或多个异常,则从try with resources语句引发的异常将被抑制。您可以通过从try块引发的异常调用Throwable.getsupprested方法来检索这些抑制的异常
正如预期的那样,第一个示例给出了输出:
java.lang.RuntimeException: y
suppressed java.lang.RuntimeException: a
在第二个代码段中还存在异常抑制的情况。要验证我是否已将您的函数修改为:
void go() {
try (Animal a = new Animal()) {
throw new IOException();
} catch (Exception e) {
for (Throwable t : e.getSuppressed()) {
System.err.println("suppressed " + t);
}
throw new RuntimeException("c");
}
}
那么输出将是:
suppressed java.lang.RuntimeException: a
java.lang.RuntimeException: c
这是令人困惑的,因为它混合了try-with-resources和try-with-resources应该能够解决的异常掩蔽行为
另外,您似乎不知道异常被抑制意味着什么。抑制意味着异常被附加到现有异常上,而不是被抛出,并且在过程中导致try块中抛出的异常丢失(通常的术语是“屏蔽”)
异常屏蔽意味着从finally或catch块抛出的异常会导致从try块内抛出的任何异常被丢弃。由于try块中抛出的异常通常描述错误,而close时抛出的异常通常是无趣的,这是一件坏事;请尝试-创造资源是为了减少这一问题的普遍性
因此,在第一个示例中,在try块内的a1上调用foo,在foo中,catch中抛出的异常y掩盖了foo的try块中抛出的异常。然后,当try with resources块退出时,将调用close方法,并将close时抛出的异常添加到正在运行的y异常中。因此,您的printlns显示y,然后遍历附加到y的抑制异常
在第二个示例中,c是从go方法抛出的(与上面描述的屏蔽行为相同)。go方法try块中的IOException被抛出,close方法在退出时被调用,导致close上的异常作为抑制异常添加到IOException,然后IOException被c屏蔽。由于a被屏蔽,且抑制的异常附加到a,我们也丢失了抑制的异常。c exception关闭时抛出的异常没有与之关联的抑制异常,因为它是在退出try with resources块后生成的。因此,在go()函数的第二个示例中,存在IOException和抑制的“a”异常,然后它执行新的运行时异常“c”,为什么它会丢弃抑制的“a”?@user1529412不是这样做的,你是。你显式地忽略了你捕获的异常,e
(它有被抑制的异常),并抛出一个全新的异常,c
。该异常与try with resources
语句无关。假设我删除了throw new RuntimeException(“c”)行;这意味着我仍然会有附加了“a”的IOException,那么为什么代码什么也不打印?@user1529412:如果您所做的只是删除带有的行,抛出新的RuntimeException(“c”)
,然后捕获仍然存在。你吃了异常,它消失得无影无踪。好的,是的,这是有意义的。我现在明白了,我把这个例子弄糊涂了,因为我在学习Java证书的东西,他们往往会遇到类似的困惑问题。@user1529412:理解这种事情很好,在现实生活中很有用世界。