美文网首页开发记录
String 连接 ,修正别人代码要有理有据

String 连接 ,修正别人代码要有理有据

作者: 叮咣铛 | 来源:发表于2019-04-08 20:31 被阅读0次

    公司监控server release一个版本跑了几天,都很正常,优化后尤其兴奋的是
    95 小时无FullGC

    jstat -gc 39148
     S0C    S1C    S0U    S1U      EC       EU        OC         OU       MC     MU    CCSC   CCSU   YGC     YGCT    FGC    FGCT     GCT
    2048.0 2048.0 1536.1  0.0   694784.0 302150.5 1398272.0   338841.9  25472.0 24952.5 2944.0 2787.9   1856   19.141   0      0.000   19.141
    

    但每次YoungGC后 Old Gen都有一点增长,有一个累积效果,怀疑有Leak
    用JProfile本地追一下,发现char[] 和String的 retain size 较大
    最后追踪到 业务逻辑拼接生成的大量sql身上

    然后发现了如下代码:

    List<SensorBean> ls = mdb.getSensorLs();
    String e01_value = "NULL,";
    ...
            for (SensorBean sbean : ls) {
                if ("E01".equals(sbean.getSensorNo())) {
                    e01_level = "'" + sbean.getAlarmLevel() + "', ";// getAlarmLevel()等返回都是String
                    e01_value = "'" + sbean.getDataValue() + "', ";
                } else if ("E02".equals(sbean.getSensorNo())) {
                    e02_level =  "'" + sbean.getAlarmLevel() + "', ";
                    e02_value = "'" + sbean.getDataValue() + "', ";
                } else if ("E03".equals(sbean.getSensorNo())) {
                    e03_level =  "'" + sbean.getAlarmLevel() + "', ";
                    e03_value = "'" + sbean.getDataValue() + "', ";
                } else if ("E11".equals(sbean.getSensorNo())) {
                    e11_level =  "'" + sbean.getAlarmLevel() + "', ";
                    e11_value = "'" + sbean.getDataValue() + "', ";
                } else if ("T01".equals(sbean.getSensorNo())) {
                    t01_level = "'" + sbean.getAlarmLevel() + "', ";
                    t01_value = "'" + sbean.getDataValue() + "', ";
                } else if ("T02".equals(sbean.getSensorNo())) {
                    t02_level = "'" + sbean.getAlarmLevel() + "', ";
                    t02_value = "'" + sbean.getDataValue() + "', ";
                } else if ("T03".equals(sbean.getSensorNo())) {
                    t03_level = "'" + sbean.getAlarmLevel() + "', ";
                    t03_value = "'" + sbean.getDataValue() + "', ";
                } else if ("T11".equals(sbean.getSensorNo())) {
                    t11_level = "'" + sbean.getAlarmLevel() + "', ";
                    t11_value = "'" + sbean.getDataValue() + "', ";
                } else if ("W01".equals(sbean.getSensorNo())) {
                    w01_level = "'" + sbean.getAlarmLevel() + "', ";
                    w01_value = "'" + sbean.getDataValue() + "', ";
                } else if ("W02".equals(sbean.getSensorNo())) {
                    w02_level =  "'" + sbean.getAlarmLevel() + "', ";
                    w02_value = "'" + sbean.getDataValue() + "', ";
                } else if ("E12".equals(sbean.getSensorNo())) {
                    e12_value = "'" + sbean.getDataValue() + "', ";
                }
            }
    
    

    之前看到加号连接我都会告知用StringBuffer,避免产生临时字符串,但没有给出具体依据,不能完全让人信服,

    特别是jdk5 以后 +会被编译器自动优化成 StringBuilder,所以有必要深究一下
    抛开其他逻辑不管,只针对这段代码的String 加号连接部分,问这样几个问题:

    1, 这里面加号会被转化成什么形式?
    2,放在循环里 加号连接为什么不好?
    

    所以单独写个小例子,然后javap 查看字节码

    左侧代码,右侧是对应的字节码

    第一个在循环内new StringBuilder


    justAdd.jpg

    第二个仅仅是StringBuffer.append


    stringAppend.jpg

    总结

    1. 如果只是局部变量,+加号连接可以接受,会被编译器优化成StringBuilder 局部非线程安全
    2. 如果是循环中则要用循环外定义好的StringBuffer,然后逐一append
    3. 如果循环中 用String + 的后果是什么?
      每加一个字符串都会生成一个新字符串,然后丢弃原有,
      生成大量临时字符串,给GC造成压力

    参考

    Java8字符串连接:
    http://www.pellegrino.link/2015/08/22/string-concatenation-with-java-8.html

    Oracle 官方 String 问答, benchMark评测(大致浏览下,没细看...)
    https://shipilev.net/talks/joker-Oct2014-string-catechism.pdf

    相关文章

      网友评论

        本文标题:String 连接 ,修正别人代码要有理有据

        本文链接:https://www.haomeiwen.com/subject/izzpiqtx.html