数组占位符_日志输出都有歧义!字符拼接 VS 占位符,到底该采用哪种方式?

前言

说来也巧,这几天正在看一本书,叫做《Java系统性能优化实战》,李家智著的,在代码审查这章中提到了一个关于日志输出问题,先看一下我们原本是怎么输出信息的,如下。

private static  Logger logger = LoggerFactory.getLogger(FileManageApplication.class);

 public static void main(String[] args) {
  logger.info("日志输出{}",1);
 }

第一个参数是格式化模板,“{}”是占位符,第二个参数是类型可以是Object... arguments的,会将第一个参数中的"{}"依次替换为这个数组中的数据,不出意外的话,会输出如下信息。

2021年01月07日 19:52:09:INFO main (FileManageApplication.java:35) - 日志输出1

但是他却不建议使用这种方式,理由是日志框架内部会有一个把占位符"{}"替换成目标变量的耗时过程,考虑到info方法可能被频繁调用,对性能有影响,所以建议直接拼接,代码如下:

public static void main(String[] args) {
 User user  =getUser();
 logger.info("用户名:"+user.getUserName());
}

这听起来似乎也有几分道理,但是在今天早上刷到了一篇公众号文章,里面也恰好提到了这个问题(是个某大V),里面这样说:“不要进行字符串拼接,那样会产生很多String对象,占用空间,影响性能”。

what???

cab3c0f82ffbee39e05611beb92eef73.png

并且他给出了一个反例,如下:

logger.debug("Processing trade with id: " + id + " symbol: " + symbol);

并且还有个正例,如下:

logger.debug("Processing trade with id:[{}] and symbol : [{}] ", id, symbol)

另外这样的格式,可读性更好,对于排查问题更有帮助。

所以,最后我们用什么方法?

下面我们还是自己看测试一下把。

时间比较

使用拼接方式

public class Main {
    private static Logger logger = LoggerFactory.getLogger(Main.class);
    public static void main(String[] args) {
        long startTimer = System.currentTimeMillis();
        for (int i = 0; i 200000; i++) {
            logger.info("i="+i);
        }
        System.out.println(System.currentTimeMillis()-startTimer);
        
    }
}

运行10次,结果是如下,平均是512.2。

534、510、486、518、495、505、526、507、511、530

使用模板方式

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class Main {
    private static Logger logger = LoggerFactory.getLogger(Main.class);
    public static void main(String[] args) {
        long startTimer = System.currentTimeMillis();
        for (int i = 0; i 200000; i++) {
            logger.info("i={}",i);
        }
        System.out.println(System.currentTimeMillis()-startTimer);
    }
}

运行10次,结果是如下,平均是642.9。

654、648、599、624、678、660、643、656、583、684

确实如书中所说,替换"{}"的过程比较耗时。

这里没使用System.out.println()做比较,因为他实在太慢了,因为内部会涉及到加锁。

内存占用比较

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.swing.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

public class Main extends JFrame {
    private static Logger logger = LoggerFactory.getLogger(Main.class);

    public Main() {
        this.setSize(300, 300);
        this.setVisible(true);
        this.setDefaultCloseOperation(EXIT_ON_CLOSE);

        JButton jButton = new JButton("开始");
        jButton.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                for (int i = 0; i 1000000; i++) {
                    logger.info("i={}",i);
//                    logger.info("i="+ i);
                }
            }
        });
        this.add(jButton);
    }

    public static void main(String[] args) {
        new Main();
    }
}

模板方式

点击按钮等待输出完成后,内存停留在112,764KB。

1a77958fcad5d09ee8fa419f33d34099.png

执行GC后降到13,484KB。

51ee88b107042421e582f227fc9b3919.png

拼接方式

点击按钮等待输出完成后,内存停留在128,014KB,相差15,250KB。

82d8e8cdfa1b272d19e035a007e5d20b.png

执行GC后降到17,777KB。

3cab83e9c3d3fe9e7c3e5609dc631af2.png

在这次比较中,拼接方式占用的内存较高,也符合公众号中所说。

结论

显然都各胜一筹,所以只能看看自己需求了,另外在如Tomcat源码中,使用的也是拼接方式....

还有在阿里巴巴Java开发手册中这样说....

5fe5cd3594ee50eec4977154270d4cd5.png
- END -
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值