6

在一些遗留代码中,我看到这个,一个过度广泛的异常被捕获,然后再次抛出,这是一个好习惯吗?throw e;是重新抛出相同的异常,还是创建一个新异常?

catch (Exception e) {
        StringBuilder sb = new StringBuilder(
                            "Oops. Something went wrong with id: ");
        sb.append(id);
        sb.append(". Exception is: ");
        sb.append(e.toString());
        System.out.println(sb.toString());
        throw e;
}
4

5 回答 5

2

throw e正在重新抛出相同的异常。至少它保留了原始堆栈跟踪。它只是向标准输出写入一条消息,记录一些有关发生的事情的信息,然后让原始异常继续进行。

这不是一个很好的做法,在一个中心位置记录异常并记录它们的堆栈跟踪就足够了。如果您需要添加更多信息(如示例中记录 id 的位置),最好将原始异常嵌套在新异常中作为原因,然后抛出新异常。我猜这可能发生在没有集中日志记录或异常容易在某处被吃掉的情况下。

于 2013-11-06T22:12:30.263 回答
1

throw e确实抛出了同样的异常。这样做可能有原因,但也有理由不这样做。在您的示例代码中,一条消息被发送到System.out,但是如果稍后打印了堆栈跟踪System.err,它将不会被同步,实际上这两者可能最终会在您的控制台中交织在一起。

更好的方法如下:

catch (Exception e) {
    StringBuilder sb = new StringBuilder(
                        "Oops. Something went wrong with id: ");
    sb.append(id);
    sb.append(". Exception is: ");
    sb.append(e.toString());
    throw new Exception(sb.toString(), e); // The original exception is an argument
}

这将使用修改后的消息创建一个Exception新消息,并将原始消息附加Exception到堆栈跟踪以帮助调试。

于 2013-11-06T22:17:46.297 回答
1

我最好的猜测是它试图有两层保护。确保显示一条错误消息,并要求客户端以它想要的方式处理异常,因为该catch子句没有做任何事情来从异常中恢复。

我不会认为这是好/坏的做法。根据您的要求,您可以考虑采用任何一种方式,例如可能有 100 个不同的客户端使用您的 API,并且每个客户端都有不同的从exception. 通过显示出了什么问题,它在客户端决定如何处理exception.

现在回到你的问题。我认为throw e抛出相同的异常对象。由于 java 中存在异常,因此objects您需要先创建一个,我在new exception objectthrow的代码中看不到它。

于 2013-11-06T22:08:05.757 回答
1

这通常是一种不好的做法。catch(Exception e)(有时称为口袋妖怪异常处理,当你必须全部捕获时)捕获一个异常。这种异常处理很少有用,因为:

  • 它也捕获运行时异常。
  • 您会丢失有关所引发异常类型的信息。
  • 您无法对特定异常做出反应或处理。

您现在的方法签名是public void whatever() throws Exception,这很少有用。现在链上的所有东西都不知道你抛出了什么样的异常;他们将不得不进行instanceof检查,这完全违背了捕获特定异常的目的。

就您的第二个异常而言,throw e;抛出相同的异常对象。如果你想包装异常,你可以创建一个新的,这意味着你会做类似throw new MyCustomException(e);. 您还需要更改方法签名。

如果没有更进一步的链条,我想这还不错(虽然仍然不是很好)。它看起来像是一个试图记录所有抛出的异常的方法。然而,同样,有更好的方法来做到这一点。

于 2013-11-06T22:15:46.677 回答
1

这可能是一个很好的做法。我想我RuntimeException在原型制作过程中总是使用转换为 s。在此之后,如果需要,可以将其更改为更好的异常处理。为此,我在 Guava 中有一个名为Throwables的实用程序类,它可以进行异常传播。

但是,在您的情况下,应该将异常转换为运行时异常,因为声明抛出一般的方法与为调用方Exception抛出的方法相同。RuntimeException在第一种情况下,它“捕获一切”,在后一种情况下,它“捕获任何东西”。在实际应用中,我还没有体验过这两者之间的区别。所以我更喜欢RuntimeExceptions 因为它们需要更少的打字。

捕捉Exception

  • 检查异常(IO异常、安全错误、并发等)
  • 运行时异常(任何东西,不可预测的垃圾,见下文)
  • 一切——这些是所有错误的 99%(但是还有Errors)

捕捉RuntimeException

  • 空指针异常,索引越界异常,访问异常,+ API 将异常传播到RuntimeException- 这也是很多

我的意思是,当你抓到一个Exception你无法真正处理所有这些情况之后。因此,如果将其包装成RuntimeException.

于 2013-11-06T22:16:39.703 回答