可以将文章内容翻译成中文,广告屏蔽插件可能会导致该功能失效(如失效,请关闭广告屏蔽插件后再试):
问题:
A comment (by user soc) on an answer to a question about tail call optimisation mentioned that Java 7 has a new feature called "suppressed exceptions", because of "the addition of ARM" (support for ARM CPUs?).
What is a "suppressed exception" in this context? In other contexts a "suppressed exception" would be an exception that was caught and then ignored (rarely a good idea); this is clearly something different.
回答1:
I believe the commenter is referring to is an exception which is semi-ignored when it's thrown within the implicit finally
block of a try-with-resources block, in the context of an existing exception being thrown from the try
block:
An exception can be thrown from the block of code associated with the try-with-resources statement. In the example writeToFileZipFileContents, an exception can be thrown from the try block, and up to two exceptions can be thrown from the try-with-resources statement when it tries to close the ZipFile and BufferedWriter objects. If an exception is thrown from the try block and one or more exceptions are thrown from the try-with-resources statement, then those exceptions thrown from the try-with-resources statement are suppressed, and the exception thrown by the block is the one that is thrown by the writeToFileZipFileContents method. You can retrieve these suppressed exceptions by calling the Throwable.getSuppressed method from the exception thrown by the try block.
(That's quoting a section called "Suppressed Exceptions" from the linked page.)
回答2:
To clarify the quote in Jon's answer, only one exception can be thrown by a method (per execution) but it is possible, in the case of a try-with-resources
, for multiple exceptions to be thrown. For instance one might be thrown in the block and another might be thrown from the implicit finally
provided by the try-with-resources
.
The compiler has to determine which of these to "really" throw. It chooses to throw the exception raised in the explicit code (the code in the try
block) rather than the one thrown by the implicit code (the finally
block). Therefore the exception(s) thrown in the implicit block are suppressed (ignored). This only occurs in the case of multiple exceptions.
回答3:
Before Java7; There are exceptions thrown in the code but were ignored somehow.
e.g.)
public class SuppressedExceptions {
public static void main(String[] args) throws Exception {
try {
callTryFinallyBlock();
} catch (Exception e) {
e.printStackTrace(); **//Only Finally Exception is Caught**
}
}
private static void callTryFinallyBlock() throws Exception {
try
{
throw new TryException(); **//This is lost**
}
finally
{
FinallyException fEx = new FinallyException();
throw fEx;
}
}
}
class TryException extends Exception {
}
class FinallyException extends Exception {
}
A new constructor and two new methods were added to the Throwable class in JDK 7.
These are as below:
Throwable.getSupressed(); // Returns Throwable[]
Throwable.addSupressed(aThrowable);
with this new approach, we can handle those suppressed exception as well.
public class SuppressedExceptions {
public static void main(String[] args) throws Exception {
try {
callTryFinallyBlock();
} catch (Exception e) {
e.printStackTrace();
for(Throwable t: e.getSuppressed())
{
t.printStackTrace();
}
}
}
private static void callTryFinallyBlock() throws Exception {
Throwable t = null;
try
{
throw new TryException();
}
catch (Exception e) {
t = e;
}
finally
{
FinallyException fEx = new FinallyException();
if(t != null)fEx.addSuppressed(t);
throw fEx;
}
}
}
class TryException extends Exception {
}
class FinallyException extends Exception {
}
In Java7 try-with-resources; the exception at AutoCloseable::close()
is added as suppressed exception by default along with try exception.
Also aware that this is different from chained exceptions (were introduced with JDK 1.4 and were intended to make it possible to easily track causal relationships between exceptions.)
回答4:
Suppressed exceptions are additional exceptions that occur within a try-with-resources statement (introduced in Java 7) when AutoCloseable
resources are closed. Because multiple exceptions may occur while closing AutoCloseable
resources, additional exceptions are attached to a primary exception as suppressed exceptions.
Looking at the bytecode of a piece of try-with-resources sample code, standard JVM exception handlers are used to accommodate the try-with-resources semantics.
回答5:
Concedering the code below:
public class MultipleExceptionsExample {
static class IOManip implements Closeable{
@Override
public void close() {
throw new RuntimeException("from IOManip.close");
}
}
public static void main(String[] args) {
try(IOManip ioManip = new IOManip()){
throw new RuntimeException("from try!");
}catch(Exception e){
throw new RuntimeException("from catch!");
}finally{
throw new RuntimeException("from finally!");
}
}
}
With all lines you will get: java.lang.RuntimeException: from finally!
Removing finally
block you will get: java.lang.RuntimeException: from catch!
Removing catch
block you will get:
Exception in thread "main" java.lang.RuntimeException: from try!
Suppressed: java.lang.RuntimeException: from IOManip.close
回答6:
I think this has to do with the "chained exception facility". It will affect how an exception is handled by this facility as the stack trace evolves. Over time exceptions that are part of a group of chained exception can be suppressed. Look at the Throwable documentation for more details.
回答7:
You can suppress Exceptions in Java 6 as well (a little trickery involved),
I created a utility that transparently handles suppressing exception in Java 1.6 and Java 1.7. You can find the implementation here
All you need is to call:
public static <T extends Throwable> T suppress(final T t, final Throwable suppressed)
to supress a exception, and
public static Throwable [] getSuppressed(final Throwable t) {
to get the suppressed exceptions of a Exception, in case anybody still uses Java 1.6
回答8:
ARM - Automatic Resource Management(Introduced since Java 7)
Take a very simple example
static String readFirstLineFromFileWithFinallyBlock(String path)
throws IOException {
BufferedReader br = new BufferedReader(new FileReader(path));
try {
return br.readLine();
} finally {
if (br != null) br.close();
}
}
Now if readLine()
function throws Exception and then even close()
function [in finally block] throws exception then the later is given more priority and is thrown back to the calling function. In this case the Exception thrown by the readLine() method is ignored/suppressed
. You can chain the causing exception in your exception and rethrow your exception from finally block.
Since java 7
functionality has been provided to retrieve suppressed Exceptions. You can call public final java.lang.Throwable[] getSuppressed()
function on the catched throwable object to view the suppressed Exceptions.
For Eg.
static String readFirstLineFromFileWithFinallyBlock(String path)
throws Exception {
try (BufferedReader br = new BufferedReader(new FileReader(path));) {
return br.readLine();
}
}
Now if br.readLine();
line throws Exception1
and then lets say Exception2
is thrown while closing the resource [Imagine this happening in an implicit finally block that try-with-resource statement creates] then Exception1 suppresses Exception2.
Few points to note here -
- If try-with-resource block throws exception i.e while resource instantiation then try block will not execute and the same exception will be thrown.
- If instantiation of resource is successful, try block throws an exception and exception is thrown while closing the resource then the exception thrown while closing resource is suppressed by the exception thrown from try block.
- If you provide explicit finally block and exception is thrown from that block it will suppress all other exception. (This explicit finally block executes after resources are closed)
I have compiled most of the possible scenarios with code snippets and output in following post.
Suppressed exceptions in java 7
Hope that helps.