顾名思义,抑制异常是在代码中抛出但以某种方式被忽略的异常。如果您还记得try-catch-finally块的执行顺序以及它们如何返回任何值或异常,您会记得在try块中抛出异常的同时,如果在finally块中抛出异常,那么finally块中抛出的异常会被抑制。

在Java 7之前,如果实现了日志记录,您会通过日志记录来了解这些异常,但一旦finally块结束,您就无法控制这些类型的异常。

好吧,借助Java 7 中的新功能,您还可以控制这些被抑制的异常。

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. 抑制异常功能之前

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 中抑制异常支持之后

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 块并捕获异常

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 块

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) 

嗯,看到包含完整信息和抑制异常的输出真是太棒了。