原文: https://howtodoinjava.com/java7/java-suppressed-exceptions/
顾名思义, 被抑制的异常是在代码中引发的异常,但是以某种方式被忽略了。 如果您记得try-catch-finally
块的执行顺序以及它们如何返回任何值或异常,那么您会记得,如果try
中引发了异常,则也将抑制finally
块中引发的异常。
在 Java 7 之前的版本中,您通过记录日志了解了这些异常(如果已实现),但是一旦finally
块结束,您就无法控制这些类型的异常。
好吧,借助 Java 7 中的新特性,您还可以控制这些受抑制的异常。
Table of contents
1\. What are suppressed exceptions?
2\. Suppressed exception example
3\. Demonstration in different scenarios
1. 什么是禁止的异常?
在 Java 7 中,遇到抑制异常的最常见用例是 try-with-resources 语句。 当我们在try
块中遇到异常时,应用程序将尝试关闭资源。 如果它遇到关闭AutoCloseable
资源时可能发生的多个异常,则会将其他异常作为抑制的异常附加到主要异常上。
为了支持抑制的异常,在 JDK 7 中向Throwable
类(Exception
和Error
类的父级)添加了新的构造器和两个新方法。
Throwable.getSupressed(); // Returns Throwable[]
Throwable.addSupressed(aThrowable);
2. 抑制异常的例子
例如,在写入输出流时,可以从try
块引发一个异常,当try-with-resources
语句尝试关闭流时,可以从该异常中引发最多两个异常。
如果从try
块引发一个异常,并且从try-with-resources
语句引发一个或多个异常,则将从try-with-resources
语句引发的那些异常抑制,并且由该块引发的异常由closeStream()
方法抛出。
您可以通过从try
块引发的异常中调用Throwable.getSuppressed()
方法来检索这些受抑制的异常。
3. 在不同情况下的示例
例如,我正在编写一个自动关闭的资源(即DirtyResource.java
),无论我们尝试访问它还是关闭它,它都会引发异常。 这样,当以不同方式访问时,我们将能够看到不同的行为。
public class DirtyResource implements AutoCloseable
{
/**
* Need to call this method if you want to access this resource
* @throws RuntimeException no matter how you call this method
* */
public void accessResource()
{
throw new RuntimeException("I wanted to access this resource. Bad luck. Its dirty resource !!!");
}
/**
* The overridden closure method from AutoCloseable interface
* @throws Exception which is thrown during closure of this dirty resource
* */
@Override
public void close() throws Exception
{
throw new NullPointerException("Remember me. I am your worst nightmare !! I am Null pointer exception !!");
}
}
3.1 抑制异常之前的特性
package com.howtodoinjava.demo.core;
import static java.lang.System.err;
public class SuppressedExceptionDemoWithTryFinallyPrevious
{
/**
* Executable member function demonstrating suppressed exceptions
* One exception is lost if not added in suppressed exceptions list
*/
public static void memberFunction() throws Exception
{
DirtyResource resource= new DirtyResource();
try
{
resource.accessResource();
}
finally
{
resource.close();
}
}
public static void main(String[] arguments) throws Exception
{
try
{
memberFunction();
}
catch(Exception ex)
{
err.println("Exception encountered: " + ex.toString());
final Throwable[] suppressedExceptions = ex.getSuppressed();
final int numSuppressed = suppressedExceptions.length;
if (numSuppressed > 0)
{
err.println("tThere are " + numSuppressed + " suppressed exceptions:");
for (final Throwable exception : suppressedExceptions)
{
err.println("tt" + exception.toString());
}
}
}
}
}
Output:
Exception encountered: java.lang.NullPointerException: Remember me. I am your worst nightmare !! I am Null pointer exception !!
如您所见,仅捕获了一个异常,而第二个RuntimeException
被抑制。
3.2 在 Java 7 中抑制异常之后
package com.howtodoinjava.demo.core;
import static java.lang.System.err;
public class SuppressedExceptionDemoWithTryFinallyNew
{
/**
* Executable member function demonstrating suppressed exceptions
* Suppressed expression is added back in primary exception
*/
public static void memberFunction() throws Exception
{
Throwable th = null;
DirtyResource resource= new DirtyResource();
try
{
resource.accessResource();
}
catch(Exception e)
{
th = e;
}
finally
{
try
{
resource.close();
}
catch(Exception e)
{
if(th != null)
{
e.addSuppressed(th); //Add to primary exception
throw e;
}
}
}
}
/**
* Executable function demonstrating suppressed exceptions.
*/
public static void main(String[] arguments) throws Exception
{
try
{
memberFunction();
}
catch(Exception ex)
{
err.println("Exception encountered: " + ex.toString());
final Throwable[] suppressedExceptions = ex.getSuppressed();
final int numSuppressed = suppressedExceptions.length;
if (numSuppressed > 0)
{
err.println("tThere are " + numSuppressed + " suppressed exceptions:");
for (final Throwable exception : suppressedExceptions)
{
err.println("tt" + exception.toString());
}
}
}
}
}
Output:
Exception encountered: java.lang.NullPointerException: Remember me. I am your worst nightmare !! I am Null pointer exception !!
There are 1 suppressed exceptions:
java.lang.RuntimeException: I wanted to access this resource. Bad luck. Its dirty resource !!!
在这里,在catch
块中,我们可以访问两个异常。 一个作为主要异常,第二个作为受抑制异常。
3.3 成员函数中的try-with-resource
块并捕获异常
package com.howtodoinjava.demo.core;
import static java.lang.System.err;
public class SuppressedExceptionDemoWithTryCatch
{
public static void memberFunction() throws Exception
{
try (DirtyResource resource= new DirtyResource())
{
resource.accessResource();
}
}
/**
* Executable member function demonstrating suppressed exceptions using try-with-resources
*/
public static void main(String[] arguments) throws Exception
{
try
{
memberFunction();
}
catch(Exception ex)
{
err.println("Exception encountered: " + ex.toString());
final Throwable[] suppressedExceptions = ex.getSuppressed();
final int numSuppressed = suppressedExceptions.length;
if (numSuppressed > 0)
{
err.println("tThere are " + numSuppressed + " suppressed exceptions:");
for (final Throwable exception : suppressedExceptions)
{
err.println("tt" + exception.toString());
}
}
}
}
}
Output:
Exception encountered: java.lang.RuntimeException: I wanted to access this resource. Bad luck. Its dirty resource !!!
There are 1 suppressed exceptions:
java.lang.NullPointerException: Remember me. I am your worst nightmare !! I am Null pointer exception !!
太好了! 在成员函数中使用try-with-resource
时,我们能够看到这两种异常。
3.4 默认try-with-resource
块
package com.howtodoinjava.demo.core;
public class SuppressedExceptionDemoWithTryWithResource
{
/**
* Demonstrating suppressed exceptions using try-with-resources
*/
public static void main(String[] arguments) throws Exception
{
try (DirtyResource resource= new DirtyResource())
{
resource.accessResource();
}
}
}
Output:
Exception in thread "main" java.lang.RuntimeException: I wanted to access this resource. Bad luck. Its dirty resource !!!
at DirtyResource.accessResource(DirtyResource.java:9)
at SuppressedExceptionDemoWithTryWithResource.main(SuppressedExceptionDemoWithTryWithResource.java:12)
Suppressed: java.lang.NullPointerException: Remember me. I am your worst nightmare !! I am Null pointer exception !!
at DirtyResource.close(DirtyResource.java:19)
at SuppressedExceptionDemoWithTryWithResource.main(SuppressedExceptionDemoWithTryWithResource.java:13)
好吧,非常高兴看到包含抑制异常的完整信息的输出。
学习愉快!