【问题标题】:what's wrong with e.printStackTrace() for an unknown exceptione.printStackTrace() 对于未知异常有什么问题
【发布时间】:2011-08-16 21:16:26
【问题描述】:

如果我在已知异常的情况下使用记录器,e.printStackTrace() 对于未知异常有什么问题?

我总是被告知不要这样做 - 但没有给出理由

下面的例子

try {
            dostuff();
        } catch (AException ae) {
            logger.error("ae happened");
        } catch (BException be) {
            logger.error("be happened");
        } catch (CException ce) {
            logger.error("ce happened");
        } catch (Exception e) {
            e.printStackTrace();
        }

【问题讨论】:

    标签: java logging exception-handling


    【解决方案1】:

    这很糟糕,因为e.printStackTrace() 不一定会写入与logger.error() 相同的日志文件,因此为了保持一致性,您应该对所有内容都使用logger.error()

    e.printStackTrace() 也没有做任何事情来描述导致错误的原因。您应该始终包含一条日志消息,让阅读日志文件的人清楚这一点。

    如果您将异常对象作为第二个参数发送,您将在日志文件中获得堆栈跟踪,以及异常的消息字符串。阅读日志文件的可怜人会很高兴获得这些信息。

    try {
        doStuff();
    }
    catch (AException ae) {
    
        // Send to the log file a message describing what we were doing,
        // and what happened as a result
    
        logger.error("ae happened, while attempting to do stuff, but that's okay", ae);
    
        dealWithTheSituation();
    }
    catch (Exception e) {
    
        logger.fatal("an unexpected error happened, while attempting to do stuff, cannot proceed", e);
    
        abortAndCatchFire();  // Burn the evidence
    }
    

    【讨论】:

    • 很好的实际例子,9 年后仍然有用
    【解决方案2】:

    因为它不使用记录器系统,所以它直接stderr,这是必须避免的。

    编辑:为什么必须避免直接写入标准错误?

    在回答您的问题时,@shinynewbike,我稍微修改了我的回答。必须避免的是在不使用logger 功能的情况下直接 写入stderr

    loggers 提供有用的功能来按优先级和包更改日志记录跟踪,除此之外,它们还允许将跟踪重定向到不同的输出机制......队列、文件、数据库、流......

    当您直接写入 System.errSystem.out 时,您将失去这些功能,更糟糕的是,如果您将 loggerSystem.err.write 混合使用,您最终可能会在不同的“文件”中获得跟踪,这将导致调试你的系统有问题。

    【讨论】:

    • 我想你的意思是stderrSystem.err ;)
    • 因为 logger 被配置为监视它,所以没有人会看到 stderr。
    • @shinynewbike 在新版本的答案中看到答案,希望它澄清。
    【解决方案3】:

    日志框架为您提供的其中一件事是对最终输出日志消息的位置进行了强大的抽象。您可能认为使用标准输出和标准错误可以达到相同的效果,但情况并非总是如此。在许多环境中,开发人员无法控制应用程序中的标准 io 流会发生什么。

    最常见的情况是您的应用在另一个容器(例如 tomcat)中运行,该容器可能会将自己的消息输出到标准输出。由于您的应用在同一进程中运行,因此您的所有消息将与容器的消息以及在同一容器中运行的任何其他应用的消息混合在一起。

    使用日志库可以让您的应用灵活地将消息记录到部署者可以配置的多个不同目的地。当您使用e.printStackTrace() 时,您不会获得此好处。

    顺便说一句,您给出的示例还引发了一些其他问题。一些后续问题可能是:

    • 什么时候可以catch(Exception ex)
    • 应何时/如何记录异常?

    【讨论】:

      【解决方案4】:

      catch (Exception e) 捕获所有异常,即使是从 RuntimeException 派生的未经检查的异常,例如 NullPointerExceptionIndexOutOfBoundsException,然后程序继续运行,即使您很可能不希望这样,因为这些通常是致命的并且可以在意想不到的位置退出控制流。

      如果您期望出现其中一种未经检查的异常,那么您应该明确捕获该类型的异常并进行处理。

      【讨论】:

        【解决方案5】:

        首先,打印堆栈跟踪并不能解决问题,问题可能不会报告给父线程进一步处理。我的建议是你在 catch 子句中处理异常,通过使用 e.getClass().getName() 识别程序中的异常类型。

        【讨论】:

          【解决方案6】:

          恕我直言,你应该

          • 始终记录到记录器或标准错误,但不是混合记录(也许这就是投诉的原因)
          • 除非您确定永远不需要它,否则始终使用堆栈跟踪记录异常。

          【讨论】:

            猜你喜欢
            • 2020-09-19
            • 2011-01-11
            • 1970-01-01
            • 2013-01-16
            • 1970-01-01
            • 2016-07-14
            • 1970-01-01
            • 1970-01-01
            • 2013-09-01
            相关资源
            最近更新 更多