抛出 e 和抛出新的异常(e) 有什么区别?

2022-09-01 01:28:40

考虑:

try  {
    // Some code here
} catch (IOException e) {
    throw e;
} catch (Exception e) {
    throw e;
}

和 有什么区别?throw ethrow new Exception(e)

try  {
   // Some code here
} catch (IOException e) {
   throw new IOException(e);
} catch (Exception e) {
   throw new Exception(e);
}

答案 1

如果不需要调整异常类型,则可以重新抛出(进一步抛出)同一实例,而不进行任何更改:

catch (IOException e) {
    throw e;
}

如果确实需要调整异常类型,则可以e(作为原因)包装到所需类型的新异常中。

catch (IOException e) {
    throw new IllegalArgumentException(e);
}

我认为所有其他方案都是代码异味。您的第二个代码段就是一个很好的例子


以下是可能弹出的问题的答案。

为什么我要重新抛出异常?

你可以放手。但是,如果发生这种情况,您将无法在此级别上做任何事情。

当我们在方法中捕获异常时,我们仍然处于该方法中,并且可以访问其范围(例如局部变量及其状态)。在我们重新抛出异常之前,我们可以做任何我们需要做的事情(例如.log一条消息,把它发送到某个地方,制作当前状态的快照)。

为什么我要调整异常?

根据经验,

较高层应捕获较低级别的异常,并在其位置上抛出可以用较高级别抽象来解释的异常。

有效的 Java - 第 2 版 - 项 61:引发适合于抽象的异常

换句话说,在某些时候,一个晦涩难懂的东西应该变成一个显眼的 。IOExceptionMySpecificBusinessRuleException

我称之为“调整异常类型”,聪明人称之为异常翻译(特别是异常链接)。


为了清楚起见,让我们举一些愚蠢的例子。

class StupidExample1 {
    public static void main(String[] args) throws IOException {
        try {
            throw new IOException();
        } catch (IOException e) {
            throw new IOException(new IOException(e));
        }
    }
}

导致详细的堆栈跟踪,如

Exception in thread "main" java.io.IOException: java.io.IOException: java.io.IOException
    at StupidExample1.main(XXX.java:XX)
Caused by: java.io.IOException: java.io.IOException
    ... 1 more
Caused by: java.io.IOException
    at StupidExample1.main(XXX.java:XX)

可以(并且应该)有效地减少到

Exception in thread "main" java.io.IOException
    at StupidExample1.main(XXX.java:XX)

另一个:

class StupidExample2 {
    public static void main(String[] args) {
        takeString(new String(new String("myString")));
    }

    static void takeString(String s) { }
}

很明显,这是一个冗长的版本,应该重构为后者。new String(new String("myString"))"myString"


答案 2
catch (IOException e) {
    throw e;
}

您将看到原始异常,只有原始堆栈跟踪。你不会在堆栈跟踪中看到这个“重新抛出”行,所以它有点透明。

catch (IOException e) {
    throw new IllegalStateException(e);
}

您将看到已创建及其堆栈跟踪,其中包含“由”原始异常信息和堆栈跟踪。您正在设置(即将是)抛出的异常作为新创建的 的原因。上层将看到并且有可能捕获(您不会捕获该捕获导致异常)。IllegalStateExceptionIOExceptionIllegalStateException

catch (IOException e) {
     throw new IOException();
}

您将只看到创建的当前堆栈跟踪,而不添加原因。IOException