出于日志目的捕获 RuntimeException 是一种不好的做法吗?

Is it bad practice to catch RuntimeException for logging purposes?

我发现捕获 RuntimeException 通常被认为是不好的做法,因为它们无法更正并且通常是程序员错误。

但是,我们有一个(疯狂的)大型应用程序,其中任何部分的更改都会产生无法预料的后果(是的,这本身就是一个问题)

现在开始在应用程序的顶层捕获和记录 RuntimeExceptions 的想法已经出现,这样我们就可以更有效地解决出现的此类出血问题。

像每个优秀的 Java 团队一样,我们有一个可爱的热心 Bob 叔叔追随者,他绝对禁止我们这样做。

这样做到底有多糟糕?真的没有可以甚至推荐这样做的情况吗?

捕获 RuntimeExceptions 不是问题,它们是异常,因此可以捕获并正确处理。如果 Java 开发人员希望您不要捕获 RuntimeExceptions,他们会将其命名为 RuntimeError。

糟糕的是捕获 RuntimeExceptions,静静地丢弃它们并继续 运行 就好像什么都没有发生过一样。 RuntimeExceptions 用于通知 developer/user 程序明显离开预期状态的关键问题和情况。至少应该记录下来,并且您应该尝试让程序恢复到舒适状态。

这么大的失败后能不能继续,完全看你的应用了。 Web 服务器即通常捕获所有异常和错误,然后重新启动相应的 Servlet,以便它们可以继续为请求提供服务。

完全取决于流量和你在哪里捕获它。

如果您正在使用 Spring,请考虑编写一个 ControllerAdvice。在这里阅读更多 https://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/web/bind/annotation/ControllerAdvice.html

在需要时捕捉 RuntimeException 不是 不好的做法。

它在使用第 3 方代码时非常有用,它抛出自己的异常扩展 RuntimeException 然后您 需要 捕获它以便进行良好的异常处理。

也在 JSP 中 捕捉 RuntimeException 有时有助于防止页面因为 NullPointerException.

而根本不显示

赶上 RuntimeException 并不总是坏事。但即使您的团队决定不捕获 RuntimeException 的,您也可以随时捕获它,记录一些东西然后重新抛出它。它根本不会改变您的应用程序逻辑。

除了日志消息之外,现在几乎所有的记录器库都有可能记录关于异常的不同细节(比如堆栈跟踪和所有嵌套异常)。

public void doStuff(String param){
  try {
    process(param);
  } catch(RuntimeException e) {
    logger.error("Something weird happened while processing " + param, e);
    throw e;
  }
}


以下是关于上下文的更新,谢谢Ralf Kleberhoff指出

最好只在应用程序的顶层记录有关 RuntimeException(或任何其他 Exception)的消息,以避免在日志中出现关于同一异常的重复消息。

如果您只想添加一些上下文(如参数值,如 Ralf Kleberhoff 所述)并且它不是应用程序顶层 catch(您确定,顶层 catch 实际存在),最好创建一个新的 Exception 并将原来的 Exception 作为 cause 添加到新的

public void doStuff(String param){
  try {
    process(param);
  } catch(RuntimeException e) {
    throw new RuntimeException("Something weird happened while processing " + param, e);
  }
}

private void process(String value){
  throw new IllegalStateException("Not implemented yet!");
}