Rethrow exception in java

2020-02-01 02:19发布

问题:

I have a very simple question about re-throwing exception in Java.

Here is the code snippet:

public static void main(String[] args) throws FileNotFoundException {
    try {
        FileReader reader = new FileReader("java.pdf");
    } catch (FileNotFoundException ex) {
        throw ex;
    }
}

public static void main(String[] args) throws FileNotFoundException {        
        FileReader reader = new FileReader("java.pdf");        
}

Why do we need to re-throw ex in the first version while the second version looks more elegant? What might be the benefits and which version is preferred over the other?

回答1:

You are right. Second version is better. Moreover the first version does not make any sense. It does the same except the stack trace of the exception will be "wrong".

There are the following reasons to "re-throw" exceptions:

  1. If you have something to do before.
  2. If you catch exception of one type and throw exception of other type:

example:

try {
   // do something
} catch (IOException ioe) {
    throw new IllegalStateException(ioe);
}


回答2:

In the example given, re-throwing the Exception serves no purpose.

Doing this can be useful if the method that catches and then re-throws the exception needs to take some additional action upon seeing the Exception, and also desires that the Exception is propagated to the caller, so that the caller can see the Exception and also take some action.



回答3:

I would only catch/rethrow an exception (instead of just throwing it) if I wanted to do something else in the catch block - for example, write a logging statement before rethrowing.



回答4:

In addition to wanting to do something with the exception before exiting - like logging, the other time you would do something like that is if you want to wrap it as a different exception, like:

try {
    FileReader reader = new FileReader("java.pdf");
} catch (FileNotFoundException ex) {
    throw new ServletException(ex);
}


回答5:

The question is why you think you need to rethrow the exception. Did Eclipse suggest surrounding with try-catch? In practice we rarely rethrow the same exception, but very often catch one and throw another that wraps the first one, especially if the wrapper exception is unchecked. This happens whenever you have calls declaring checked exceptions, but the method you write those calls in doesn't declare those exceptions:

public int findId(String name) {
  try {
    return db.select("select id from person where name=?", name);
  } catch (SQLException e) {
    throw new RuntimeException(e);
  }
}


回答6:

The flow of execution stops immediately after the throw statement; any subsequent statements are not executed. The nearest enclosing try block is inspected to see if it has a catch statement that matches the type of exception.

If it does find a match, control is transferred to that statement. If not, then the next enclosing try statement is inspected and so on. If no matching catch is found, then the default exception handler halts the program and prints the stack trace.

If the method is capable of causing an exception that it does not handle, it must specify this behavior so that callers of the method can guard themselves against that exception.

One can do this by including a throws clause in method's declaration. A throws clause lists the types of exceptions that a method might throw. This is necessary for all exceptions, except those of type Error or RuntimeException, or any of their subclasses. All other exceptions that a method can throw must be declared int the throws clause. If they are not, a compile-time error will result.



回答7:

Both versions will output the same stacktrace

without try/catch

import java.io.FileNotFoundException;
import java.io.FileReader;

public class Test {
    public static void main(String[] args) throws FileNotFoundException {
//        try {
            FileReader reader = new FileReader("java.pdf");
//        } catch (FileNotFoundException ex) {
//            throw ex;
//        }
    }
}

will output

Exception in thread "main" java.io.FileNotFoundException: java.pdf (The system cannot find the file specified)
    at java.io.FileInputStream.open0(Native Method)
    at java.io.FileInputStream.open(FileInputStream.java:195)
    at java.io.FileInputStream.<init>(FileInputStream.java:138)
    at java.io.FileInputStream.<init>(FileInputStream.java:93)
    at java.io.FileReader.<init>(FileReader.java:58)
    at Test.main(Test.java:7)

with try/catch/throw same exception

import java.io.FileNotFoundException;
import java.io.FileReader;

public class Test {
    public static void main(String[] args) throws FileNotFoundException {
        try {
            FileReader reader = new FileReader("java.pdf");
        } catch (FileNotFoundException ex) {
            throw ex;
        }
    }
}

will output exactly the same as before

Exception in thread "main" java.io.FileNotFoundException: java.pdf (The system cannot find the file specified)
    at java.io.FileInputStream.open0(Native Method)
    at java.io.FileInputStream.open(FileInputStream.java:195)
    at java.io.FileInputStream.<init>(FileInputStream.java:138)
    at java.io.FileInputStream.<init>(FileInputStream.java:93)
    at java.io.FileReader.<init>(FileReader.java:58)
    at Test.main(Test.java:7)

try/catch/throw wrapping exception

An advisable approach is to throw your own exceptions. wrap the exception you just caught into it if you want to provide details of the root cause (might be wanted or not wanted)

import java.io.FileNotFoundException;
import java.io.FileReader;

public class Test {
    public static void main(String[] args) {
        try {
            FileReader reader = new FileReader("java.pdf");
        } catch (FileNotFoundException ex) {
            throw new RuntimeException("Error while doing my process", ex);
        }
    }
}

You can clearly see the top-level issue (my process did not complete), and the root cause that led to it (java.pdf file not found)

Exception in thread "main" java.lang.RuntimeException: Error while doing my process
    at Test.main(Test.java:9)
Caused by: java.io.FileNotFoundException: java.pdf (The system cannot find the file specified)
    at java.io.FileInputStream.open0(Native Method)
    at java.io.FileInputStream.open(FileInputStream.java:195)
    at java.io.FileInputStream.<init>(FileInputStream.java:138)
    at java.io.FileInputStream.<init>(FileInputStream.java:93)
    at java.io.FileReader.<init>(FileReader.java:58)
    at Test.main(Test.java:7)