Java 记录器与System.out.println

Java 记录器与System.out.println,java,eclipse,pmd,java.util.logging,Java,Eclipse,Pmd,Java.util.logging,我正在使用eclipse的PMD插件,在使用System.out.println()时出现了一个错误,解释如下: 系统。(打印输出),使用打印,考虑使用记录器。 我的问题是-什么是记录器?如何将其打印到屏幕上?为什么更好?请参阅 问题在于使用System.out打印调试或诊断信息。这是一种糟糕的做法,因为您无法轻松更改日志级别、关闭日志级别、自定义日志级别等 但是,如果您合法地使用System.out向用户打印信息,则可以忽略此警告。PMD似乎认为您正在调用System.out.println(

我正在使用eclipse的PMD插件,在使用
System.out.println()
时出现了一个错误,解释如下:

系统。(打印输出),使用打印,考虑使用记录器。

我的问题是-什么是记录器?如何将其打印到屏幕上?为什么更好?

请参阅

问题在于使用
System.out
打印调试或诊断信息。这是一种糟糕的做法,因为您无法轻松更改日志级别、关闭日志级别、自定义日志级别等


但是,如果您合法地使用
System.out
向用户打印信息,则可以忽略此警告。

PMD似乎认为您正在调用
System.out.println()
,以进行调试;比如“我在你的方法中,执行你的代码”

如果你这样做,你将有一个更好的时间写一个日志,如,因为它将有多个流选项,而不仅仅是屏幕


但是,如果您正在执行控制台应用程序,并且正在调用
System.out
,则忽略该警告

System.out.println
不适合使用,因为它无法配置。相反,
记录器
可以配置为在不同级别上登录。它还有很多其他特性。

这个链接提供了关于如何使用Log4j的更简明的信息:但是它只有一个小缺陷,您不应该将库放在
/jre/lib/ext
中,而应该放在应用程序的运行时类路径中并随附

其优点是,您可以使用日志级别来指示信息的重要性,这样您就可以从外部配置输出中显示/隐藏哪些级别(这样您就不会被无用的信息所困扰)、输出的外观(例如,包括时间戳、线程ID、类名、方法名等)以及输出应写入的位置(例如控制台、文件、电子邮件等),以及例如文件的创建方式(例如,按年、月和/或日分组)


有几种记录器实现,如Java SE的内置、方便、流行、后续等。您可以在需要时作为额外的抽象层在这些记录器之间切换。

如果您使用System.out | err.println(..)在应用程序的主()控制台上打印用户信息-方法,你没有做错什么。您可以通过插入注释“//NOPMD”来删除该消息

为此,PMD违规概要中有一个“标记为已审核”选项

当然,您可以使用以下代码片段欺骗PMD:

PrintStream out=System.out;
out.println("I am fooling PMD.");  
在main()方法之外,使用日志系统,例如Log4j

更新:

您还可以修改PMD规则“SystemPrintln”以使用以下XPath:

//MethodDeclaration[@MethodName!="main"]//Name[
starts-with(@Image, 'System.out.print')
or
starts-with(@Image, 'System.err.print')
] | //Initializer//Name[
starts-with(@Image, 'System.out.print')
or
starts-with(@Image, 'System.err.print')
]
这将忽略代码中名为“main”的任何方法中的System.out.println等,但检查初始化器代码中的System.out.println。
我喜欢这样,因为在我看来,System.out.println在方法“main(String args[])”中是安全的。但是要小心使用,我必须检查,在AST中,System.out.println也可以出现在哪里,并且必须调整XPath。

日志记录器有多个日志级别

如果我们正在编写一个真正简短的程序,仅仅是为了学习目的
System.out.println
是可以的,但是当我们开发一个高质量的软件项目时,我们应该使用专业的记录器,应该避免使用SOP

专业的伐木工人提供不同级别的伐木和灵活性。我们可以得到相应的日志消息。例如,X组消息应仅在生产时打印,Y组消息应在错误时打印,等等


我们在
System.out
中重定向消息的选项有限,但对于记录器,您有提供大量选项的附加器。我们甚至可以创建一个自定义输出选项并将其重定向到该选项。

还可以看到最近的问题:我将答案扩展为“[…]将信息打印到用户或其他进程,然后您可以忽略此警告”。想想Unix进程之间的管道输出,是
System.out
的概念赋予了这一功能。
//MethodDeclaration[@MethodName!="main"]//Name[
starts-with(@Image, 'System.out.print')
or
starts-with(@Image, 'System.err.print')
] | //Initializer//Name[
starts-with(@Image, 'System.out.print')
or
starts-with(@Image, 'System.err.print')
]