Catching an Exception and rethrowing it, but it's not an Exception

一个人想着一个人 提交于 2019-12-08 15:40:36

问题


I stumbled upon code looking something like this:

void run() {
    try {
        doSomething();
    } catch (Exception ex) {
        System.out.println("Error: " + ex);
        throw ex;
    }
}

void doSomething() {
    throw new RuntimeException();
}

This code surprises me because it looks like the run()-method is capable of throwing an Exception, since it catches Exception and then rethrows it, but the method is not declared to throw Exception and apparently doesn't need to be. This code compiles just fine (in Java 11 at least).

My expectation would be that I would have to declare throws Exception in the run()-method.

Extra information

In a similar way, if doSomething is declared to throw IOException then only IOException needs to be declared in the run()-method, even though Exception is caught and rethrown.

void run() throws IOException {
    try {
        doSomething();
    } catch (Exception ex) {
        System.out.println("Error: " + ex);
        throw ex;
    }
}

void doSomething() throws IOException {
    // ... whatever code you may want ...
}

Question

Java usually likes clarity, what is the reason behind this behavior? Has it always been like this? What in the Java Language Specification allows the run() method not need to declare throws Exception in the code snippets above? (If I would add it, IntelliJ warns me that Exception is never thrown).


回答1:


I have not scan through the JLS as you have asked in your question, so please take this answer with a grain of salt. I wanted to make it a comment, but it would have been too big.


I find funny at times, how javac is pretty "smart" in some cases (like in your case), but leaves a lot of other things to be handled later by JIT. In this case, it is just that the compiler "can tell" that only a RuntimeException would be caught. This is obvious, it's the only thing you throw in doSomething. If you slightly change your code to:

void run() {
    try {
        doSomething();
    } catch (Exception ex) {
        Exception ex2 = new Exception();
        System.out.println("Error: " + ex);
        throw ex2;
    }
}

you will see a different behavior, because now javac can tell that there is a new Exception that you are throwing, un-related to the one you caught.

But things are far from ideal, you can "trick" the compiler yet again via:

void run() {
    try {
        doSomething();
    } catch (Exception ex) {
        Exception ex2 = new Exception();
        ex2 = ex;
        System.out.println("Error: " + ex);
        throw ex2;
    }
}

IMO, because of ex2 = ex; it should not fail again, but it does.

Just in case this was compiled with javac 13+33



来源:https://stackoverflow.com/questions/58416402/catching-an-exception-and-rethrowing-it-but-its-not-an-exception

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!