1. Introduction
1.绪论
In this quick tutorial, we’re going to learn about suppressed exceptions in Java. In short, a suppressed exception is an exception that is thrown but somehow ignored. A common scenario for this in Java is when the finally block throws an exception. Any exception originally thrown in the try block is then suppressed.
在这个快速教程中,我们将学习Java中的抑制性异常。简而言之,被抑制的异常是一种被抛出但被忽略的异常。在Java中,一个常见的情况是当finally块抛出一个异常。任何最初在try块中抛出的异常都会被压制。
Starting with Java 7, we can now use two methods on the Throwable class to handle our suppressed exceptions: addSuppressed and getSuppressed. We should note that the try-with-resources construct was also introduced in Java 7. We’ll see in our examples how they’re related.
从 Java 7 开始,我们现在可以使用 Throwable 类上的两个方法来处理被抑制的异常。addSuppressed和getSuppressed。我们应该注意到,try-with-resources结构也是在Java 7中引入的。我们将在我们的例子中看到它们之间的关系。
2. Suppressed Exceptions in Action
2.被禁止的例外情况在行动
2.1. Suppressed Exception Scenario
2.1.被禁止的例外情况
Let’s begin by taking a quick look at an example where the original exception is suppressed by an exception occurring in the finally block:
让我们先来看看一个例子,原始异常被发生在finally块中的异常所抑制。
public static void demoSuppressedException(String filePath) throws IOException {
FileInputStream fileIn = null;
try {
fileIn = new FileInputStream(filePath);
} catch (FileNotFoundException e) {
throw new IOException(e);
} finally {
fileIn.close();
}
}
As long as we provide a path to an existing file, no exceptions will be thrown and the method will work as expected.
只要我们提供一个现有文件的路径,就不会出现异常,该方法将按预期工作。
However, suppose we provide a file that doesn’t exist:
然而,假设我们提供一个不存在的文件。
@Test(expected = NullPointerException.class)
public void givenNonExistentFileName_whenAttemptFileOpen_thenNullPointerException() throws IOException {
demoSuppressedException("/non-existent-path/non-existent-file.txt");
}
In this case, the try block will throw a FileNotFoundException when it tries to open the non-existent file. Because the fileIn object was never initialized, it’ll throw a NullPointerException when we try to close it in our finally block. Our calling method will only get the NullPointerException, and it won’t be readily obvious what the original problem was: that the file doesn’t exist.
在这种情况下,try块在试图打开不存在的文件时将抛出一个FileNotFoundException。因为fileIn对象从未被初始化,所以当我们在finally块中试图关闭它时,它会抛出一个NullPointerException。我们的调用方法只会得到NullPointerException,而原来的问题是什么并不明显:文件不存在。
2.2. Adding Suppressed Exception
2.2.添加被禁止的例外情况
Now let’s look at how we can take advantage of the Throwable.addSuppressed method to provide the original exception:
现在让我们看看如何利用Throwable.addSuppressed方法来提供原始异常。
public static void demoAddSuppressedException(String filePath) throws IOException {
Throwable firstException = null;
FileInputStream fileIn = null;
try {
fileIn = new FileInputStream(filePath);
} catch (IOException e) {
firstException = e;
} finally {
try {
fileIn.close();
} catch (NullPointerException npe) {
if (firstException != null) {
npe.addSuppressed(firstException);
}
throw npe;
}
}
}
Let’s go to our unit test and see how getSuppressed works in this situation:
让我们进入单元测试,看看getSuppressed在这种情况下如何工作。
try {
demoAddSuppressedException("/non-existent-path/non-existent-file.txt");
} catch (Exception e) {
assertThat(e, instanceOf(NullPointerException.class));
assertEquals(1, e.getSuppressed().length);
assertThat(e.getSuppressed()[0], instanceOf(FileNotFoundException.class));
}
We now have access to that original exception from the array of suppressed exceptions provided.
我们现在可以从提供的被抑制的异常数组中访问那个原始异常。
2.3. Using try-with-resources
2.3.使用try-with-resources
Lastly, let’s look at an example using try-with-resources where the close method throws an exception. Java 7 introduced the try-with-resources construct and the AutoCloseable interface for resource management.
最后,我们来看一个使用try-with-resources的例子,其中close方法抛出一个异常。Java 7为资源管理引入了try-with-resources构造和AutoCloseable接口。
First, let’s create a resource that implements AutoCloseable:
首先,让我们创建一个实现AutoCloseable的资源。
public class ExceptionalResource implements AutoCloseable {
public void processSomething() {
throw new IllegalArgumentException("Thrown from processSomething()");
}
@Override
public void close() throws Exception {
throw new NullPointerException("Thrown from close()");
}
}
Next, let’s use our ExceptionalResource in a try-with-resources block:
接下来,让我们在ExceptionalResource中使用try-with-resources块。
public static void demoExceptionalResource() throws Exception {
try (ExceptionalResource exceptionalResource = new ExceptionalResource()) {
exceptionalResource.processSomething();
}
}
Finally, let’s go over to our unit test and see how the exceptions shake out:
最后,让我们去看看我们的单元测试,看看异常情况是如何发生的。
try {
demoExceptionalResource();
} catch (Exception e) {
assertThat(e, instanceOf(IllegalArgumentException.class));
assertEquals("Thrown from processSomething()", e.getMessage());
assertEquals(1, e.getSuppressed().length);
assertThat(e.getSuppressed()[0], instanceOf(NullPointerException.class));
assertEquals("Thrown from close()", e.getSuppressed()[0].getMessage());
}
We should note that when using AutoCloseable, it’s the exception thrown in the close method that’s suppressed. The original exception is thrown.
我们应该注意,当使用AutoCloseable时,被抑制的是close方法中抛出的异常。原来的异常会被抛出。
3. Conclusion
3.总结
In this short tutorial, we learned what suppressed exceptions are and how they happen. Then, we saw how to use the addSuppressed and getSuppressed methods to access those suppressed exceptions. Finally, we saw how suppressed exceptions work when using a try-with-resources block.
在这个简短的教程中,我们了解了什么是被抑制的异常以及它们是如何发生的。然后,我们看到了如何使用 addSuppressed 和 getSuppressed 方法来访问这些被抑制的异常。最后,我们看到了在使用try-with-resources块时被抑制的异常是如何工作的。
As always, the example code is available over on GitHub.
像往常一样,示例代码可在GitHub上获得。