Java 为什么您要捕获Throwable,而只打印堆栈跟踪?

Java 为什么您要捕获Throwable,而只打印堆栈跟踪?,java,exception-handling,Java,Exception Handling,我试着在其他线程上寻找这个问题的答案,但到目前为止,我只看到一些线程表示捕捉可丢弃的对象是不好的。我的问题是,有没有一个原因让你想这样做,然后在catch块中除了打印堆栈跟踪之外什么都不做 我最近被带到一个项目中,负责为RESTful服务清理一组现有类的错误处理。几个助手服务类具有try/catch块,这些块只捕获可丢弃的内容并打印堆栈跟踪,如下所示: class MainService { SubService1 s1; SubService2 s2; public doMai

我试着在其他线程上寻找这个问题的答案,但到目前为止,我只看到一些线程表示捕捉可丢弃的对象是不好的。我的问题是,有没有一个原因让你想这样做,然后在catch块中除了打印堆栈跟踪之外什么都不做

我最近被带到一个项目中,负责为RESTful服务清理一组现有类的错误处理。几个助手服务类具有try/catch块,这些块只捕获可丢弃的内容并打印堆栈跟踪,如下所示:

class MainService {

  SubService1 s1;
  SubService2 s2;

  public doMainService() {
  }

}


class SubService1 {

  public int findSomething() {

    try {
        // Do Something
    } catch (Throwable t) {
        t.printStackTrace();
    }
  }
}

class SubService2 {

  public int findSomethingElse() {

    try {
        // Do Something
    } catch (Throwable t) {
        t.printStackTrace();
    }  
  }

}

这是否可以接受?方法抛出异常而不使用try/catch块是否更好?

如果您不知道获取堆栈跟踪的其他方法,并且希望知道如何到达当前位置,则可以这样做。这不是一个很好的理由,但却是一个可能的理由。这似乎不符合你所看到的;您似乎收到的代码不会崩溃,但在错误处理方面也做得不好。

我使用它来查看程序崩溃的确切位置。所以基本上只是为了调试。我认为人们这样做的一个原因是Java迫使您要么用try/catch块包围抛出的调用,要么将抛出添加到方法声明中


如果您“知道”不会发生异常,那么这是一种防止异常向上传播的方法(因为如果您确实抛出,谁调用过您的代码,都需要围绕一个try/catch等等),但是如果确实发生了什么,它将在不崩溃的情况下转储它。

他们可能希望在不崩溃程序的情况下查看堆栈跟踪


例如,当线程崩溃是不可接受的,因为下一次迭代(比如线程从队列中提取项目)可能会按预期工作时,线程执行的代码可以记录异常,但不能执行任何操作。这取决于用例,但对于服务器来说,您通常希望线程是防弹的,并记录任何错误,而不是停止任何进一步的处理(但用例可能会有所不同)。

由于各种众所周知的原因,这几乎不是一个好的实践

特别是,它没有区分和异常以及。更重要的是,该代码的作用之一是允许应用程序在异常处理程序之外执行,这可能会由于违反不变量而导致各种奇怪的行为。换句话说,由于捕获的异常实际上可能是任何东西,包括违反断言、编程错误、线程中断、缺少类、I/O错误、OOM条件,甚至库和VM错误,因此程序状态实际上是不可预测的,超出了异常处理程序的范围

在某些罕见的情况下,广泛的异常处理可能是有意义的。设想一台服务器处理多个独立的请求。您可能不希望由于在服务其中一个请求时遇到问题而崩溃。由于不依赖于异常处理程序后留下的状态,因此可以简单地打印堆栈跟踪,让某人在服务器继续服务其他请求时进行调查


即使在这样的情况下,也应该仔细考虑错误是否应该被真正捕获。

我们遇到的最简单的例子是在关闭输入流时。FooWoWin是输入流类中的方法声明。 public void close()引发IOException

尽管调用此方法时可能会引发异常,但对程序的执行不会有任何伤害(因为我们不会进一步使用该InputStream),在这种情况下,我们应该只记录错误并继续程序。但是,如果您发现一个改变对象状态的异常,那么您必须考虑恢复代码或停止执行

永远不要这样做(
e.printStackTrace()
)。许多IDE默认使用它,但它很可怕(许多应用程序在运行时会以无法访问的方式重定向stderr,因此从未见过)。经验法则:

  • 如果你真的不在乎这个异常(永远,永远,永远,永远,永远都不会在乎),抓住它,什么也不做,只留下一条大评论,上面写着“我们真的,真的永远都不在乎这个异常是否被抛出”
  • 如果您从未期望实际抛出异常(接口定义了一个选中的异常,但您知道impl实际上并没有抛出它),请将异常重新抛出,类似于
    newunsupportedOperationException(“这永远不会发生”,t)
    (这样,如果/当基础impl发生更改时,您会尽早发现它)
  • 如果您认为异常不太可能发生,并且通常不会关心它,那么使用适当的日志基础设施(log4j、commons logging或java.util.logging)记录它。这样,如果您决定确实关心异常,那么它很可能会出现在您以后可以看到的某个地方

如果没有ESP和与编写者的直接链接,这个问题就没有答案。最有可能的答案是?差劲或懒惰的程序员。其他可能是?未完成/匆忙的代码,从未脱离调试阶段。这是一个有效的问题,特别是对Java新手来说。他/她正在问我们Java专家,是否有问题这是一个很好的理由。对不起,我想我应该问得更好一点,因为不可能知道以前的程序员在想什么。代码运行良好,代码中有ExceptionMapper将异常映射到HTTP状态代码,这让我更加困惑。“
抛出异常
”顺便说一句,这通常也是个坏主意。我提到泛型异常类的原因是由于try/catch抛出异常中的一些代码