当前位置: 首页 > 面试题库 >

为什么将exception.printStackTrace()视为不良做法?

牧甫
2023-03-14
问题内容

有一个很大的材料了有这表明印刷异常的堆栈跟踪是不好的做法。

例如从Checkexp中的RegexpSingleline检查:

可以使用此检查来查找常见的不良做法,例如调用ex.printStacktrace()

但是,我正在努力寻找能够给出正当理由的任何地方,因为肯定可以使堆栈跟踪对于跟踪导致异常的原因非常有用。我知道的事情:

  1. 最终用户永远不应看到堆栈跟踪(出于用户体验和安全目的)

  2. 生成堆栈跟踪是一个相对昂贵的过程(尽管在大多数“例外”情况下这不太可能成为问题)

  3. 许多日志记录框架会为你打印堆栈跟踪(我们不会,也不行,我们无法轻松更改它)

  4. 打印堆栈跟踪不构成错误处理。它应与其他信息记录和异常处理结合在一起。

还有什么其他原因可以避免在代码中打印堆栈跟踪?


问题答案:

Throwable.printStackTrace()将堆栈跟踪写入System.errPrintStreamSystem.err可以通过以下方式重定向JVM流程的流和基础标准“错误”输出流:

  • 调用System.setErr()会更改所指向的目的地System.err
  • 或通过重定向流程的错误输出流。错误输出流可以重定向到文件/设备
  • 人员可能会忽略其内容,
  • 文件/设备可能无法进行日志轮换,这意味着在归档文件/设备的现有内容之前,需要重新启动进程才能关闭打开的文件/设备句柄。
  • 或文件/设备实际上丢弃所有写入其中的数据,例如的情况/dev/null
    从以上推断,调用仅Throwable.printStackTrace()构成有效的(不好/很好的)异常处理行为

  • 如果你System.err在整个应用程序生命周期中都没有被重新分配,

  • 如果你在应用程序运行时不需要轮换日志,
  • 如果应用程序接受或设计了日志记录实践,则将写入System.err(以及JVM的标准错误输出流)。
    在大多数情况下,不满足上述条件。一个人可能不知道JVM中正在运行的其他代码,并且一个人无法预测日志文件的大小或进程的运行时间,因此,一种设计良好的日志记录实践将围绕编写“机器可解析的”日志文件(记录器中最好的但可选的功能),以帮助支持。

最后,应该记住,的输出Throwable.printStackTrace()肯定会与写入的其他内容交织在一起System.err(甚至System.out可能都被重定向到同一文件/设备)。这是一个必须处理的烦恼(对于单线程应用程序),因为在此类事件中不容易解析异常周围的数据。更糟糕的是,多线程应用程序很可能会生成非常混乱的日志,因为Throwable.printStackTrace() 它不是线程安全的。

没有同步机制可以将堆栈跟踪的写入与System.err多个线程同时调用Throwable.printStackTrace()时的同步。要解决此问题,实际上需要你的代码在与之关联的监视器上进行同步System.err(System.out如果目标文件/设备相同,则还需要同步),这对于支付日志文件的完整性来说是一笔不小的代价。举个例子,ConsoleHandlerand StreamHandler类负责在java.util.logging; 提供的日志记录工具中将日志记录追加到控制台。发布日志记录的实际操作是同步的-尝试发布日志记录的每个线程也必须获得与该日志记录关联的监视器上的锁StreamHandler实例。如果希望使用System.out/保证具有非交错日志记录System.err,则必须确保相同-消息以可序列化的方式发布到这些流中。

考虑到以上所有内容以及在Throwable.printStackTrace()实际中非常有用的非常受限制的场景,通常会发现调用它是一种不好的做法。

扩展前面段落之一中的参数,将它Throwable.printStackTrace与写入控制台的记录器结合使用也是一个糟糕的选择。部分原因是由于记录器将在另一个监视器上进行同步,而你的应用程序(可能,如果你不想插入日志记录)将在另一个监视器上进行同步。当你在应用程序中使用两个写入相同目的地的不同记录器时,该参数也适用。



 类似资料:
  • 问题内容: 我一直看到警告,不要在JavaScript中使用全局变量,但是似乎人们说这的唯一原因是因为阻塞了全局名称空间。我可以想象通过将所有变量放入一个大对象中来轻松解决此问题。现在的问题是:除了方便起见,还有其他原因不使用全局变量吗?它们是否涉及任何性能或兼容性问题? 问题答案: 它们使全局名称空间混乱,并且查找速度比局部变量慢。 首先,拥有许多全局变量始终是一件坏事,因为很容易忘记您在某个地

  • 问题内容: 我目前遇到一个问题,我有两个我需要调用的模块,它们需要能够修改相同的变量。 我决定创建一个名为的全局变量,并在其中存储所需的变量。 但是我一直在阅读,使用全局变量是一种不好的做法。为什么? 我仅创建一个变量,该变量不应与其他任何冲突,因为它是我的应用程序的名称。 问题答案: 几乎在所有编程语言中,全局变量都被视为反模式,因为它们使遵循和调试代码变得非常困难。 浏览代码时,您永远不知道哪

  • 问题内容: 以及你使用哪种替代策略来避免LazyLoadExceptions? 我确实了解到公开会议存在以下问题: 在不同的jvm中运行的分层应用程序 事务仅在最后提交,最有可能你希望在结果之前提交。 但是,如果你知道你的应用程序在单个vm上运行,为什么不通过使用开放会话视图策略来减轻痛苦呢? 问题答案: 因为从性能和理解的角度来看,在视图层中发送可能未初始化的代理(尤其是集合)并从那里触发hib

  • 问题内容: 看到这个答案。它说: 六个非常糟糕的例子; … 锁定在可变字段上。例如,synced(object){object = …; } 锁定可变字段有什么问题?如果被声明为但不是不可变的类怎么办? 问题答案: 这是一个坏主意,因为如果另一个线程更改了关键部分中的引用,则这些线程将不再看到相同的引用,因此它们将不会在同一对象上同步,从而不受控制地运行。例: 假设有2个线程试图进入此关键部分。线

  • 问题内容: 我大致认为使用iframe是“不好的做法”。 这是真的?使用它们的优点/缺点是什么? 问题答案: 与所有技术一样,它也有起有落。如果您要使用iframe到一个经过适当开发的网站周围走走,那当然是个坏习惯。但是,有时iframe是可以接受的。 iframe的主要问题之一与书签和导航有关。如果您使用它只是将页面嵌入内容中,我认为很好。这就是iframe的用途。 但是我也看到iframe也被

  • 问题内容: function foo () { global $var; // rest of code } 在我的小型PHP项目中,我通常采用过程方式。通常,我有一个包含系统配置的变量,当我需要在函数中访问此变量时,我会这样做。 这是不好的做法吗? 问题答案: 当人们谈论其他语言的全局变量时,这意味着与PHP中的操作有所不同。那是因为变量在PHP 中并不是 真正的 全局变量。典型的PHP程序的范