原文: https://howtodoinjava.com/java7/java-suppressed-exceptions/

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

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

好吧,借助 Java 7 中的新特性,您还可以控制这些受抑制的异常。

  1. Table of contents
  2. 1\. What are suppressed exceptions?
  3. 2\. Suppressed exception example
  4. 3\. Demonstration in different scenarios

1. 什么是禁止的异常?

在 Java 7 中,遇到抑制异常的最常见用例是 try-with-resources 语句。 当我们在try块中遇到异常时,应用程序将尝试关闭资源。 如果它遇到关闭AutoCloseable资源时可能发生的多个异常,则会将其他异常作为抑制的异常附加到主要异常上。

为了支持抑制的异常,在 JDK 7 中向Throwable类(ExceptionError类的父级)添加了新的构造器和两个新方法。

  1. Throwable.getSupressed(); // Returns Throwable[]
  2. Throwable.addSupressed(aThrowable);

2. 抑制异常的例子

例如,在写入输出流时,可以从try块引发一个异常,当try-with-resources语句尝试关闭流时,可以从该异常中引发最多两个异常。

如果从try块引发一个异常,并且从try-with-resources语句引发一个或多个异常,则将从try-with-resources语句引发的那些异常抑制,并且由该块引发的异常由closeStream()方法抛出。

您可以通过从try块引发的异常中调用Throwable.getSuppressed()方法来检索这些受抑制的异常。

3. 在不同情况下的示例

例如,我正在编写一个自动关闭的资源(即DirtyResource.java),无论我们尝试访问它还是关闭它,它都会引发异常。 这样,当以不同方式访问时,我们将能够看到不同的行为。

  1. public class DirtyResource implements AutoCloseable
  2. {
  3. /**
  4. * Need to call this method if you want to access this resource
  5. * @throws RuntimeException no matter how you call this method
  6. * */
  7. public void accessResource()
  8. {
  9. throw new RuntimeException("I wanted to access this resource. Bad luck. Its dirty resource !!!");
  10. }
  11. /**
  12. * The overridden closure method from AutoCloseable interface
  13. * @throws Exception which is thrown during closure of this dirty resource
  14. * */
  15. @Override
  16. public void close() throws Exception
  17. {
  18. throw new NullPointerException("Remember me. I am your worst nightmare !! I am Null pointer exception !!");
  19. }
  20. }

3.1 抑制异常之前的特性

  1. package com.howtodoinjava.demo.core;
  2. import static java.lang.System.err;
  3. public class SuppressedExceptionDemoWithTryFinallyPrevious
  4. {
  5. /**
  6. * Executable member function demonstrating suppressed exceptions
  7. * One exception is lost if not added in suppressed exceptions list
  8. */
  9. public static void memberFunction() throws Exception
  10. {
  11. DirtyResource resource= new DirtyResource();
  12. try
  13. {
  14. resource.accessResource();
  15. }
  16. finally
  17. {
  18. resource.close();
  19. }
  20. }
  21. public static void main(String[] arguments) throws Exception
  22. {
  23. try
  24. {
  25. memberFunction();
  26. }
  27. catch(Exception ex)
  28. {
  29. err.println("Exception encountered: " + ex.toString());
  30. final Throwable[] suppressedExceptions = ex.getSuppressed();
  31. final int numSuppressed = suppressedExceptions.length;
  32. if (numSuppressed > 0)
  33. {
  34. err.println("tThere are " + numSuppressed + " suppressed exceptions:");
  35. for (final Throwable exception : suppressedExceptions)
  36. {
  37. err.println("tt" + exception.toString());
  38. }
  39. }
  40. }
  41. }
  42. }
  43. Output:
  44. Exception encountered: java.lang.NullPointerException: Remember me. I am your worst nightmare !! I am Null pointer exception !!

如您所见,仅捕获了一个异常,而第二个RuntimeException被抑制。

3.2 在 Java 7 中抑制异常之后

  1. package com.howtodoinjava.demo.core;
  2. import static java.lang.System.err;
  3. public class SuppressedExceptionDemoWithTryFinallyNew
  4. {
  5. /**
  6. * Executable member function demonstrating suppressed exceptions
  7. * Suppressed expression is added back in primary exception
  8. */
  9. public static void memberFunction() throws Exception
  10. {
  11. Throwable th = null;
  12. DirtyResource resource= new DirtyResource();
  13. try
  14. {
  15. resource.accessResource();
  16. }
  17. catch(Exception e)
  18. {
  19. th = e;
  20. }
  21. finally
  22. {
  23. try
  24. {
  25. resource.close();
  26. }
  27. catch(Exception e)
  28. {
  29. if(th != null)
  30. {
  31. e.addSuppressed(th); //Add to primary exception
  32. throw e;
  33. }
  34. }
  35. }
  36. }
  37. /**
  38. * Executable function demonstrating suppressed exceptions.
  39. */
  40. public static void main(String[] arguments) throws Exception
  41. {
  42. try
  43. {
  44. memberFunction();
  45. }
  46. catch(Exception ex)
  47. {
  48. err.println("Exception encountered: " + ex.toString());
  49. final Throwable[] suppressedExceptions = ex.getSuppressed();
  50. final int numSuppressed = suppressedExceptions.length;
  51. if (numSuppressed > 0)
  52. {
  53. err.println("tThere are " + numSuppressed + " suppressed exceptions:");
  54. for (final Throwable exception : suppressedExceptions)
  55. {
  56. err.println("tt" + exception.toString());
  57. }
  58. }
  59. }
  60. }
  61. }
  62. Output:
  63. Exception encountered: java.lang.NullPointerException: Remember me. I am your worst nightmare !! I am Null pointer exception !!
  64. There are 1 suppressed exceptions:
  65. java.lang.RuntimeException: I wanted to access this resource. Bad luck. Its dirty resource !!!

在这里,在catch块中,我们可以访问两个异常。 一个作为主要异常,第二个作为受抑制异常。

3.3 成员函数中的try-with-resource块并捕获异常

  1. package com.howtodoinjava.demo.core;
  2. import static java.lang.System.err;
  3. public class SuppressedExceptionDemoWithTryCatch
  4. {
  5. public static void memberFunction() throws Exception
  6. {
  7. try (DirtyResource resource= new DirtyResource())
  8. {
  9. resource.accessResource();
  10. }
  11. }
  12. /**
  13. * Executable member function demonstrating suppressed exceptions using try-with-resources
  14. */
  15. public static void main(String[] arguments) throws Exception
  16. {
  17. try
  18. {
  19. memberFunction();
  20. }
  21. catch(Exception ex)
  22. {
  23. err.println("Exception encountered: " + ex.toString());
  24. final Throwable[] suppressedExceptions = ex.getSuppressed();
  25. final int numSuppressed = suppressedExceptions.length;
  26. if (numSuppressed > 0)
  27. {
  28. err.println("tThere are " + numSuppressed + " suppressed exceptions:");
  29. for (final Throwable exception : suppressedExceptions)
  30. {
  31. err.println("tt" + exception.toString());
  32. }
  33. }
  34. }
  35. }
  36. }
  37. Output:
  38. Exception encountered: java.lang.RuntimeException: I wanted to access this resource. Bad luck. Its dirty resource !!!
  39. There are 1 suppressed exceptions:
  40. java.lang.NullPointerException: Remember me. I am your worst nightmare !! I am Null pointer exception !!

太好了! 在成员函数中使用try-with-resource时,我们能够看到这两种异常。

3.4 默认try-with-resource

  1. package com.howtodoinjava.demo.core;
  2. public class SuppressedExceptionDemoWithTryWithResource
  3. {
  4. /**
  5. * Demonstrating suppressed exceptions using try-with-resources
  6. */
  7. public static void main(String[] arguments) throws Exception
  8. {
  9. try (DirtyResource resource= new DirtyResource())
  10. {
  11. resource.accessResource();
  12. }
  13. }
  14. }
  15. Output:
  16. Exception in thread "main" java.lang.RuntimeException: I wanted to access this resource. Bad luck. Its dirty resource !!!
  17. at DirtyResource.accessResource(DirtyResource.java:9)
  18. at SuppressedExceptionDemoWithTryWithResource.main(SuppressedExceptionDemoWithTryWithResource.java:12)
  19. Suppressed: java.lang.NullPointerException: Remember me. I am your worst nightmare !! I am Null pointer exception !!
  20. at DirtyResource.close(DirtyResource.java:19)
  21. at SuppressedExceptionDemoWithTryWithResource.main(SuppressedExceptionDemoWithTryWithResource.java:13)

好吧,非常高兴看到包含抑制异常的完整信息的输出。

学习愉快!