字符串拼接问题应该是每个Java程序员都熟知的事情了,几乎每个Java程序员都读过关于StringBuffer/StringBuilder来拼接字符串。

在大多数的教程中,也许你会看到用+号拼接字符串会生成多个String,导致性能过差,建议使用StringBuffer/StringBuilder来拼接。

可是真的是这样的吗?

本文在JDK8中做了如下实验:

public static void main(String[] args) {
String result = "";
result += "some more data";
System.out.println(result);
}

  

通过javap -c来反编译得到:

Code:
0: aload_0 // Push 'this' on to the stack
1: invokespecial #1 // Invoke Object class constructor
// pop 'this' ref from the stack
4: return // Return from constructor public static void main(java.lang.String[]);
Code:
0: ldc #2 // Load constant #2 on to the stack
2: astore_1 // Create local var from stack (pop #2)
3: new #3 // Push new StringBuilder ref on stack
6: dup // Duplicate value on top of the stack
7: invokespecial #4 // Invoke StringBuilder constructor
// pop object reference
10: aload_1 // Push local variable containing #2
11: invokevirtual #5 // Invoke method StringBuilder.append()
// pop obj reference + parameter
// push result (StringBuilder ref)
14: ldc #6 // Push "some more data" on the stack
16: invokevirtual #5 // Invoke StringBuilder.append
// pop twice, push result
19: invokevirtual #7 // Invoke StringBuilder.toString:();
22: astore_1 // Create local var from stack (pop #6)
23: getstatic #8 // Push value System.out:PrintStream
26: aload_1 // Push local variable containing #6
27: invokevirtual #9 // Invoke method PrintStream.println()
// pop twice (object ref + parameter)
30: return // Return void from method

  

可以看到Java编译器优化了生成的字节码,自动创建了一个StringBuilder,并进行append操作。

由于构建最终字符串的子字符串在编译时已经已知了,在这种情况下Java编译器才会进行如上的优化。这种优化称为a static string concatenation optimization,自JDK5时就开始启用。

那是否就能说明在JDK5以后,我们不再需要手动生成StringBuilder,通过+号也能达到同样的性能?

我们尝试下动态拼接字符串:

动态拼接字符串指的是仅在运行时才知道最终字符串的子字符串。比如在循环中增加字符串:

public static void main(String[] args) {
String result = "";
for (int i = 0; i < 10; i++) {
result += "some more data";
}
System.out.println(result);
}

  

同样反编译:

Code:
0: aload_0 // Push 'this' on to the stack
1: invokespecial #1 // Invoke Object class constructor
// pop 'this' ref from the stack
4: return // Return from constructor public static void main(java.lang.String[]);
Code:
0: ldc #2 // Load constant #2 on to the stack
2: astore_1 // Create local var from stack, pop #2
3: iconst_0 // Push value 0 onto the stack
4: istore_2 // Pop value and store it in local var
5: iload_2 // Push local var 2 on to the stack
6: i2d // Convert int to double on
// top of stack (pop + push)
7: ldc2_w #3 // Push constant 10e6 on to the stack
10: dcmpg // Compare two doubles on top of stack
// pop twice, push result: -1, 0 or 1
11: ifge 40 // if value on top of stack is greater
// than or equal to 0 (pop once)
// branch to instruction at code 40
14: new #5 // Push new StringBuilder ref on stack
17: dup // Duplicate value on top of the stack
18: invokespecial #6 // Invoke StringBuilder constructor
// pop object reference
21: aload_1 // Push local var 1 (empty String)
// on to the stack
22: invokevirtual #7 // Invoke StringBuilder.append
// pop obj ref + param, push result
25: ldc #8 // Push "some more data" on the stack
27: invokevirtual #7 // Invoke StringBuilder.append
// pop obj ref + param, push result
30: invokevirtual #9 // Invoke StringBuilder.toString
// pop object reference
33: astore_1 // Create local var from stack (pop)
34: iinc 2, 1 // Increment local variable 2 by 1
37: goto 5 // Move to instruction at code 5
40: getstatic #10 // Push value System.out:PrintStream
43: aload_1 // Push local var 1 (result String)
44: invokevirtual #11 // Invoke method PrintStream.println()
// pop twice (object ref + parameter)
47: return // Return void from method

  

可以看到在14的时候new了StringBuilder,但是在37的时候goto到了5,在循环过程中,并没有达到最优化,不断在生成新的StringBuilder。

所以上述代码类似:

String result = "";
for (int i = 0; i < 10; i++) {
StringBuilder tmp = new StringBuilder();
tmp.append(result);
tmp.append("some more data");
result = tmp.toString();
}
System.out.println(result);

  

可以看到不断生成新的StringBuilder,并且通过tostring,原来的StringBuilder将不再引用,作为垃圾,也增加了GC成本。

所以,在实际的使用中,当你无法区分字符串是静态拼接还是动态拼接的时候,还是使用StringBuilder吧。

Reference:
http://www.pellegrino.link/2015/08/22/string-concatenation-with-java-8.html

来源:开源中国---Hosee
链接:https://my.oschina.net/hosee/blog/1786130

更多干货可关注公众号,回复“文档”获取

 

谈谈JDK8中的字符串拼接的更多相关文章

  1. Java中的字符串拼接

    Java中的字符串拼接 1.设计源码 /** * @Title:IndexOf.java * @Package:com.you.freemarker.model * @Description: * @ ...

  2. ||在oracle数据库中起到字符串拼接的作用

    例子:select org.id from org where inner_code like '12011601001' || '%' ||在oracle数据库中起到字符串拼接的作用,上面等同于'1 ...

  3. 从源代码的角度聊聊java中StringBuffer、StringBuilder、String中的字符串拼接

    长久以来,我们被教导字符串的连接最好用StringBuffer.StringBuilder,但是我们却不知道这两者之间的区别.跟字符串相关的一些方法中总是有CharSequence.StringBuf ...

  4. golang中的字符串拼接

    go语言中支持的字符串拼接的方法有很多种,这里就来罗列一下 常用的字符串拼接方法 1.最常用的方法肯定是 + 连接两个字符串.这与python类似,不过由于golang中的字符串是不可变的类型,因此用 ...

  5. sql中的字符串拼接

    转载自:https://www.cnblogs.com/rainman/p/6203065.html 1. 概述 在SQL语句中经常需要进行字符串拼接,以sqlserver,oracle,mysql三 ...

  6. C#中的字符串拼接@,$

    转载自:https://blog.csdn.net/qq_40666620/article/details/101695138 一:@ @的意思是以@标注的字符出,其中所有的符号均为字符串符号,没有什 ...

  7. oracle存储过程中使用字符串拼接

    1.使用拼接符号“||” v_sql := 'SELECT * FROM UserInfo WHERE ISDELETED = 0 AND ACCOUNT =''' || vAccount || '' ...

  8. javascript中字符串拼接详解

    字符串拼接是所有程序设计语言都需要的操作.当拼接结果较长时,如何保证效率就成为一个很重要的问题.本文介绍的是Javascript中的字符串拼接,希望对你有帮助,一起来看.   最近在研究<jav ...

  9. 阿里巴巴Java开发手册_不建议在循环体中使用+进行字符串拼接

    18. [推荐]循环体内,字符串的连接方式,使用StringBuilder的append方法进行扩展. 说明:下例中,反编译出的字节码文件显示每次循环都会new出一个StringBuilder对象,然 ...

随机推荐

  1. inventor安装失败怎样卸载安装inventor 2015?

    AUTODESK系列软件着实令人头疼,安装失败之后不能完全卸载!!!(比如maya,cad,3dsmax等).有时手动删除注册表重装之后还是会出现各种问题,每个版本的C++Runtime和.NET f ...

  2. 使用WindowsAPI播放PCM音频

    这一篇文章同上一篇<使用WindowsAPI获取录音音频>原理具有相似之处,不再详细介绍函数与结构体的参数 1. waveOutGetNumDevs 2. waveOutGetDevCap ...

  3. LeetCode 167.两数之和(C++)

    给定一个已按照升序排列 的有序数组,找到两个数使得它们相加之和等于目标数. 函数应该返回这两个下标值 index1 和 index2,其中 index1 必须小于 index2. 说明: 返回的下标值 ...

  4. LeetCode 860.柠檬水找零(C++)

    在柠檬水摊上,每一杯柠檬水的售价为 5 美元. 顾客排队购买你的产品,(按账单 bills 支付的顺序)一次购买一杯. 每位顾客只买一杯柠檬水,然后向你付 5 美元.10 美元或 20 美元.你必须给 ...

  5. Collections练习之对字符串先折半,再取最长的一个

    不多说,直接上干货! 代码需求 由 [aa, abcde, cba, cba, nbaa, zzz] 变成 max=abcde CollectionsDemo.java package zhouls. ...

  6. iOS开发实践之多线程(单例模式)

    单例模式的作用:可以保证在程序运行过程,一个类只有一个实例,而且该实例易于供外界访问,从而方便地控制了实例个数,并节约系统资源. 单例模式的使用场合:在这个应用程序中,共享一份资源(这份资源只需要创建 ...

  7. Mincost

    The cost of taking a taxi in Hangzhou is not a constant for each kilometer you travel: the first 4 k ...

  8. css取消a标签在移动端点击时的背景颜色

    一.取消a标签在移动端点击时的蓝色 -webkit-tap-highlight-color: rgba(255, 255, 255, 0);-webkit-user-select: none;-moz ...

  9. sharepoint2007就地升级2010系列(五)升级到sharepoint2010

    ---恢复内容结束--- 大家下午好 今天我们来完成最后一步,sharepoint2007升级2010.其实我反倒没有那么紧张了,因为我最担心的数据库升级,已经过了. OK,话不多说,让我们直接开始吧 ...

  10. 从刷票了解如何获得客户端IP

    我的个人博客,源地址:http://www.woniubi.cn/get_client_ip/ 前两个星期帮一个朋友的亲戚的孩子刷票,谁让咱们是程序员呢.这当中也遇到过重装系统,除灰尘,淘宝购物,盗Q ...