Java 抑制异常示例

Java 抑制异常示例

原文: 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类(ExceptionError类的父级)添加了新的构造器和两个新方法。

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)

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

学习愉快!