java中的异常,重新抛出

时间:2013-11-06 22:02:54

标签: java

在一些遗留代码中,我看到这个,一个过于宽泛的异常被捕获,然后又被抛出,这是一个好习惯吗? 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;
}

5 个答案:

答案 0 :(得分:2)

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

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

答案 1 :(得分:1)

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

我不会认为好/坏做法。根据您的要求,您可以考虑采用任何一种方式,例如可能有100个不同的客户使用您的API,并且每个客户都有不同的方法从exception恢复。通过显示出现问题的方法,在客户决定如何处理exception的图层下方添加默认操作图层。

现在回到你的问题。我认为throw e会抛出相同的异常对象。由于java中的例外情况为objects,因此您需要先创建new exception object,然后才能throw我无法在您的代码中看到它。

答案 2 :(得分:1)

这通常是一种不好的做法。 catch(Exception e)(有时称为 Pokemon异常处理,当你必须抓住所有时)捕获每个单个异常。这种异常处理很少有用,因为:

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

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

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

如果链上没有任何东西,我想这并不是那么糟糕(尽管如此)仍然不是很好。它看起来像是一个尝试记录抛出的所有异常的方法。然而,再次,有更好的方法来做到这一点。

答案 3 :(得分:1)

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

但是,在您的情况下,异常应转换为运行时异常,因为声明抛出一般Exception的方法与抛出RuntimeException的方法相同主叫方。在第一种情况下,它'捕获所有',在后者中它'捕获任何东西'。我还没有体验到其中两个在实际应用程序中的区别。所以我更喜欢RuntimeException,因为他们需要更少的输入。

抓取Exception

  • 检查异常(IO异常,安全错误,并发等)
  • 运行时异常(任何,不可预测的垃圾,见下文)
  • Everything - 这些是所有错误的99%(但是还剩Error

抓取RuntimeException

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

我的观点是,当你捕捉Exception时,你无法真正处理所有这些情况。因此,除非主叫方输入较少,如果将其包装成RuntimeException,它就没有区别。

答案 4 :(得分: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附加到堆栈跟踪以帮助调试。