为什么使用System.out.println()这么糟糕?[关闭]


18

当然,对错误消息或警告使用日志记录框架非常有用。但是有时候如果我想在短时间内尝试一些新的东西,我会使用System.out.println()。

使用System.out.println()进行快速测试真的很糟糕吗?


3
不,这是一个快速测试,谁在乎?
Bryan Boettcher

10
谁说不好?有什么选择?
詹姆斯

1
@Kayser静态代码审查工具不适合用于快速测试-它们更多地用于您打算与他人一起开发的代码(或其他人必须理解的代码)。我今年似乎要吸取的教训是,即使在整个工作日中,也存在非常不同的问题空间,它们需要非常不同的工具集和实践。因此,为进行快速测试,请全部删除并使用Groovy :)
Bill K

1
尝试使用System.err.println(),看看会发生什么。我猜该工具认为您使用System.out的目的不正确。
Izkata 2012年

2
主要问题是可伸缩性和控制性。如果您有数百万条这样的语句,那么您将如何查看需要查看的内容。如果您需要对其中之一做出反应,那么如何以编程方式进行操作。日志记录框架通常是应用于System.out的这两个想法。

Answers:


18

正如评论中所揭示的,真正要问的问题是,为什么静态代码分析工具会标记System.out.println的使用?

原因是在生产环境中通常不适合向stdout发送消息。如果要对库进行编码,则库应将信息返回给其调用方,而不是打印到stdout。如果您正在编写GUI应用程序,则应将信息显示给用户,而不是显示stdout指向的位置(可能不指向任何地方)。如果要对服务器(或在服务器端容器中运行的服务器)进行编码,则应使用框架提供的任何日志记录工具。依此类推。

但是,如果您使用println进行调试或开发,或者您正在编写程序并读取stdin并将其写入stdout,则println非常好。在这种情况下,它没有错。


3
好答案。谢谢.. +1表示“如果您正在编写GUI应用,则应将信息呈现给用户,而不是stdout恰好指向的位置(可能无处)”
Kayser,2012年

10

所有stdout被缓冲,因此它是可能的,你的程序会崩溃以后你叫println(),但之前它到达屏幕。

话虽如此,这种情况真的不太可能。继续使用并使用它,但只需将较小的限制放在脑海中即可。


即使退出是由于未处理的异常所致,至少有两个主要的Python解释器会非常努力地在退出前刷新所有打开的文件。JVM不会做类似的事情吗?

1
@delnan,可能,但是任何事情都可能发生。(刷新stdout的代码可能是问题所在的地方。正在运行的线程可能会被强制关闭。当前进程可能会被OS从内存中强制转储。)不要过着我的声明,但是只是意识到这一点。
riwalk 2012年

1
刷新stdout的代码在VM本身中,因此不受VM实现的语言错误的影响。关于强制过程结束的要点。但是请注意,可以捕获例如Unix的SIGTERM和大多数其他信号来进行清理-但不适用于更极端的SIGKILL。

2
尽管我已经看到其他问题,但我认为我从未见过或听说过此事。使用记录器之类的工具也无法使该问题得到改善,因为它们可能会将System.out用作基础工具。
Bill K

@delnan永远不要假设您的清理代码可以保证运行...并且永远不要将关键的业务事务代码放入finally块中;) System.out适合调试,但是要注意缓冲。
2012年

8

System.out只是一个包裹BufferedOutputStream。这可能与您将使用的任何日志记录框架相似,这些框架仅以日志输出的配置和目标形式提供更多功能。


4
这并不能真正回答问题。“不好吗?”
sergserg 2012年

@Berg-因为问题的那一部分完全取决于上下文。(或只是,不,这不是坏)
spinning_plate

7

如果您使用的是非平凡的程序,那很不好

  • 将System.out用作拐杖,而不是自动进行单元测试(JUnit)
  • 花大量时间创建和删除System.out语句或对其进行注释/取消注释

1
大多数IDE应该具有自动完成System.out.println,注释/取消注释行以及删除行的热键。原则上,避免过度使用它是正确的,但是您至少可以这样节省时间。
2012年

7

关于使用System.out,即使在一次性代码中也有一些注意事项。

一个主要问题是它通常很慢。例如,如果您想大致了解某些代码的速度(请注意,微基准测试很困难),则在System.out.println()任何位置添加单个代码确实会弄乱您的时间(因为它正在同步并且经常等待实际输出到返回之前对用户可见)。

除此之外,我不会在一次性代码中对此太担心。如果您打算提交它(作为生产代码或作为测试代码),则应删除它,并用适当的日志记录调用替换它(是的,即使在测试代​​码中)。


性能是一个很好的理由..
凯泽

4

通常,答案是“取决于”。如果您的应用程序已经有一个日志记录框架,那么您也可以使用它。它不能有能力println(),你可以从它提供协议栈等特点痕迹,额外的上下文,更好地格式化,等受益。日志记录框架还具有提供更好的错误恢复的独特可能性,即使在发生灾难性故障的情况下,也可以确保成功写入日志。

因此,问题就变成了何时首先添加日志记录系统。这是一个判断电话:您不想过早添加它,只是发现您确实不需要它。您也不想添加得太晚,并且要从临时解决方案转换过多的工作。

如果发现您使用进行了大量日志记录println(),则您的代码库正在尝试告诉您它正在经历越来越大的痛苦。到那时,值得投资适当的日志记录。


3

我经常遇到这样的问题,即System.out.print使用“系统默认”代码页,在Linux下通常为UTF-8,而在Windows下却有些MS的东西。

根据程序的运行位置,这可能会导致unicode字符正确地显示在屏幕上。

因此,相对于System.out,我更喜欢自定义PrintWriter


通过减少MS的东西。您是说CP1352还是UTF16?
科尔·约翰逊

@ColeJohnson:不幸的是,Windows控制台窗口仍停留在UTF16之前的时代。但是,在内置控制台中使用合理的IDE可以减少该问题。
约阿希姆·绍尔

@科尔·约翰逊-我可以使用CP 65001(即utf8),但是似乎没有办法将其作为“系统默认”代码页,例如,当您使用德语键盘时,可以使用CP 850或类似的东西。
Ingo 2012年

1

一点也不坏。这个概念可能源于以下事实:它非常简单,而不像在应用程序中使用专用日志记录框架那样复杂。

但是,这并不是说这是一种无效的方法。在使用一些黑巫术伏都教编程技巧之后,我已经多次使用它来检查应用程序流程。


0

使用它没有任何问题,它可以帮助您弄清楚“到底发生了什么”。

但是,如果您的同龄人/其他开发人员/工具在嘲笑您,您可以始终使用Logger或开始Junit测试!


0

正如我所看到的那样,时空System.out.println的最大问题是它是“不良习惯气味(tm)”。如果您发现自己正在执行此操作,则可以通过使用自己喜欢的调试器更加自在来提高效率。

同样,使用调试器,您肯定知道断点不会插入您的生产代码中,而System.out.println可能会断点。

附带说明一下,如果您实际上只是在进行快速测试并且坚持不使用调试器,那么我认为System.out.println比使用日志记录框架要好,因为如果您不小心留下了log.debug语句,完成后,很难根除。


0

围绕回声内部状态的内容来构建整个测试策略并不是最明智的举动,但是对于开发中的快速而肮脏的代码测试,只要您记得将其删除,这里的println就不会受到伤害!

建议不要删除它们,而忘记删除它们的危险。


您认为忘记删除它们有什么问题?当然,控制台上还会有更多消息。您还有其他问题吗?
凯塞尔2012年
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.