Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

how can suppressed exception in the 'try' block be retrieved?

Tags:

java

exception

From Java 7, we can use the try-with-resources statement:

static String readFirstLineFromFile(String path) throws IOException {
    try (BufferedReader br =
                   new BufferedReader(new FileReader(path))) {
        return br.readLine();
    }
}

if br.readLine() and br.close() both throw exceptions, readFirstLineFromFile will throw the exception from the try block (the exception of br.readLine() ), and the exception from the implicit finally block of the try-with-resources statement (the exception of br.close() ) will be suppressed.

In this case, we can retrieve suppressed exceptions from the implicit finally block by calling the getSuppresed method from the exception of the try block like this:

try {   
    readFirstLineFromFile("Some path here..."); // this is the method using try-with-resources statement
}   catch (IOException e) {     // this is the exception from the try block  
    Throwable[] suppressed = e.getSuppressed();
    for (Throwable t : suppressed) {
        // Check t's type and decide on action to be taken
    }
}

But suppose we have to work with a method written with an older version than Java 7, in which the finally block is used:

static String readFirstLineFromFileWithFinallyBlock(String path) throws IOException {
    BufferedReader br = new BufferedReader(new FileReader(path));
    try {
        return br.readLine();
    } finally {
        if (br != null) br.close();
    }
}

then if br.readLine() and br.close() once again both throw exceptions, the situation will be reversed. The method readFirstLineFromFileWithFinallyBlock will throw the exception from the finally block (the exception of br.close() ), and the exception from the try block (the exception of br.readLine() ) will be suppressed.

So my question here is: how can we retrieve the suppressed exceptions from the try block in the second case?

Source: http://docs.oracle.com/javase/tutorial/essential/exceptions/tryResourceClose.html

like image 795
Hải Phong Avatar asked May 10 '13 11:05

Hải Phong


2 Answers

You can't, basically. The suppressed exception is lost if br.close() throws.

The closest you could come would be to have a catch block which assigns the value to a locla variable:

static String readFirstLineFromFileWithFinallyBlock(String path) throws IOException {
    IOException exception = null;
    BufferedReader br = new BufferedReader(new FileReader(path));
    try {
      return br.readLine();
    } catch (IOException e) {
      exception = e;
    } finally {
      try {
        if (br != null) br.close();
      } catch (IOException e) {
        // Both the original call and close failed. Eek!
        // Decide what you want to do here...
      }
      // close succeeded, but we already had an exception
      if (exception != null) {
        throw exception;
      }
    }
}

... but this only handles IOException (rather than any unchecked exceptions) and is horribly messy.

like image 126
Jon Skeet Avatar answered Oct 30 '22 10:10

Jon Skeet


the exception from the try block (the exception of br.readLine() ) will be suppressed.

That's not quite correct. The Java Language Specification writes:

  • If execution of the try block completes abruptly because of a throw of a value V, then there is a choice:

    • If the run-time type of V is not assignment compatible with a catchable exception class of any catch clause of the try statement, then the finally block is executed. Then there is a choice:

      • If the finally block completes normally, then the try statement completes abruptly because of a throw of the value V.

      • If the finally block completes abruptly for reason S, then the try statement completes abruptly for reason S (and the throw of value V is discarded and forgotten).

That is, the exception is "discarded and forgotten", not merely suppressed.

BTW, as the mechanism for attaching a suppressed exception to another exception has been introduced in Java 7, there was no general support for this in Java 6. Therefore, there is no way code targeting Java 6 can make use of that feature.

like image 45
meriton Avatar answered Oct 30 '22 11:10

meriton