java 报异常时候 printstacktrace 为什么不能用_java – 为什么exception.printStackTrace()被认为是不好的做法?...

本文探讨了使用Throwable.printStackTrace()方法进行异常处理的有效性和局限性。指出该方法在特定条件下可能不是一个理想的选择,尤其是在需要考虑日志轮换、多线程环境及日志文件解析的情况下。

Throwable.printStackTrace()将堆栈跟踪写入System.err PrintStream。 System.err流和JVM进程的底层标准“错误”输出流可以重定向

>调用System.setErr(),改变System.err指向的目的地。

>或通过重定向进程的错误输出流。错误输出流可以重定向到文件/设备

>其内容可能被人员忽视,

>文件/设备可能无法记录旋转,推断在归档文件/设备的现有内容之前需要进程重新启动以关闭打开的文件/设备句柄。

>或者文件/设备实际上丢弃写入它的所有数据,如/ dev / null的情况。

从上述推断,调用Throwable.printStackTrace()构成有效(不好/很好)异常处理行为,只有

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

>如果在应用程序运行时不需要日志轮换,

>如果接受/设计的应用程序的日志实践是写入System.err(和JVM的标准错误输出流)。

在大多数情况下,不满足上述条件。可能不知道在JVM中运行的其他代码,并且不能预测日志文件的大小或进程的运行时间,而良好设计的日志实践将围绕编写“机器可解析”日志文件在记录器中的优选但可选的特征),以帮助支持。

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

当多个线程同时调用Throwable.printStackTrace()时,没有同步机制来同步将堆栈跟踪写入System.err。解决此问题实际上需要您的代码在与System.err(以及System.out,如果目标文件/设备是相同的)相关联的监视器上同步,并且这是相当沉重的价格来支付日志文件的健全性。例如,ConsoleHandler和StreamHandler类负责将日志记录附加到控制台,在由java.util.logging提供的日志记录工具中;发布日志记录的实际操作是同步的 – 尝试发布日志记录的每个线程还必须获取与StreamHandler实例关联的监视器上的锁。如果希望使用System.out / System.err具有非交叉日志记录的同样保证,则必须确保相同 – 消息以可串行化的方式发布到这些流。

考虑到上述所有情况,以及Throwable.printStackTrace()实际上很有用的非常有限的情况,它经常证明调用它是一个坏的做法。

扩展前面段落中的参数,使用Throwable.printStackTrace与向控制台写入的记录器结合使用也是一个不好的选择。这部分是由于记录器在不同的监视器上同步的原因,而您的应用程序(可能,如果不想交叉日志记录)在不同的监视器上同步。当您在应用程序中使用两个不同的记录器写入相同的目标时,参数也是很好的。

### 生产环境中不应使用 `e.printStackTrace()` 的原因 #### 日志管理混乱 `e.printStackTrace()` 打印的日志与应用程序正常运行时生成的业务日志混杂在一起,这使得定位和分析问题变得困难。当出现问题时,开发人员很难从中提取有用的信息来快速诊断问题所在[^1]。 #### 性能风险 调用 `e.printStackTrace()` 方法会在内部创建大量的字符串对象用于表示堆栈跟踪信息,并将其存储于JVM中的字符串常量池里。一旦发生频繁异常或单次异常涉及非常深的调用链路,则可能迅速消耗掉这部分有限资源。当字符串常量池的空间不足而无法容纳新的条目时,不仅会影响当前操作的速度,还可能导致后续依赖相同区域的操作受阻,进而影响整个系统的响应速度乃至稳定性[^4]。 #### 可能引发更严重的错误 在极端情况下——比如高并发场景下多个线程同时触发异常并尝试通过 `printStackTrace()` 记录它们的情况——这种做法有可能耗尽可用内存,造成OutOfMemoryError (OOM),从而迫使Java虚拟机停止工作,使服务不可用[^3]。 为了更好地处理异常情况,在生产环境下推荐采用专业的日志框架(如Logback、SLF4J等),这些工具可以提供更加灵活可控的方式来进行日志记录,包括但不限于设置不同的日志级别、指定目标文件位置以及配置轮转策略等功能特性,有助于提高运维效率的同时也保障了程序的安全稳定执行。 ```java // 建议的做法:利用日志库替代 e.printStackTrace() import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class Example { private static final Logger logger = LoggerFactory.getLogger(Example.class); public void someMethod() { try { // Some code that may throw an exception... } catch (Exception e) { logger.error("An error occurred", e); } } } ```
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符  | 博主筛选后可见
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值