实习有一个多月了,突然发现好久都没有在项目见到System.out.println了,全部用logger.info,logger.error代替,于是请教了师傅们,总结如下:

首先System.out日志打印不可控制、打印时间无法确定、不能添加过滤器、日志没有级别区分。在Log中可以根据需要添加一个自定义的过滤器,在成百上千条日志中轻松找到我们要想要的信息。

 

知识剖析

Log4j有三个主要的组件:Loggers(记录器),Appenders  (输出源)和Layouts(布局)。这里可简单理解为日志类别,日志要输出的地方和日志以何种形式输出。

Loggers组件在此系统中被分为五个级别:DEBUG、INFO、WARN、ERROR和FATAL。

这五个级别是有顺序的,DEBUG < INFO < WARN< ERROR < FATAL,分别用来指定这条日志信息的重要程度。

Log4j有一个规则:只输出级别不低于设定级别的日志信息。

Appenders 配置日志信息输出。

Layouts 设置日志输出的格式,Layouts提供四种日志输出样式,如根据HTML样式、自由指定样式、包含日志级别与信息的样式和包含日志时间、线程、类别等信息的样式。

log4j的配置文件中有输出到文件的相关配置,这就是它和System.out.println的区别,也是我们为什么使用log的关键点,因为我们查找日志信息的时候就可以到相应的日志文件中去查看,并且不会因为程序关闭等等因素丢失掉之前的日志信息,如果是sout的话,程序关闭,信息就丢失了,那我们想看到报错等等,就必须要重新运行程序。

在java项目中日志输出一般不建议使用System.out.println(),和log4j等日志工具相比,除了不能对日志进行灵活配置,还会对性能有影响。
关于性能的影响,在网上查了很多资料,一直没找到想要的答案,今天无聊,点开源码一看豁然开朗

//System.out.println()的jdk源码:
    /**
     * Prints a String and then terminate the line.  This method behaves as
     * though it invokes <code>{@link #print(String)}</code> and then
     * <code>{@link #println()}</code>.
     *
     * @param x  The <code>String</code> to be printed.
     */
    public void println(String x) {
        synchronized (this) {
            print(x);
            newLine();
        }
    }
    /*进一步看,println()中的两个方法同样是加了线程同步的,有兴趣的可以看一下JDK源码。*/



这个方法是同步的,代码中的System.out.println() 和java运行程序运行在同一线程,业务程序会等待system.out的动作,导致资源被占用。

总结:程序中大量使用System.out.println()势必会影响项目的性能。
在项目上线后尽量把System.out.println()的日志改用log4j 等工具进行调试信息的打印。这类工具是异步线程的,不会使程序处于等待状态。