谈谈JDK8中的字符串拼接
字符串拼接问题应该是每个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中的字符串拼接的更多相关文章
- Java中的字符串拼接
Java中的字符串拼接 1.设计源码 /** * @Title:IndexOf.java * @Package:com.you.freemarker.model * @Description: * @ ...
- ||在oracle数据库中起到字符串拼接的作用
例子:select org.id from org where inner_code like '12011601001' || '%' ||在oracle数据库中起到字符串拼接的作用,上面等同于'1 ...
- 从源代码的角度聊聊java中StringBuffer、StringBuilder、String中的字符串拼接
长久以来,我们被教导字符串的连接最好用StringBuffer.StringBuilder,但是我们却不知道这两者之间的区别.跟字符串相关的一些方法中总是有CharSequence.StringBuf ...
- golang中的字符串拼接
go语言中支持的字符串拼接的方法有很多种,这里就来罗列一下 常用的字符串拼接方法 1.最常用的方法肯定是 + 连接两个字符串.这与python类似,不过由于golang中的字符串是不可变的类型,因此用 ...
- sql中的字符串拼接
转载自:https://www.cnblogs.com/rainman/p/6203065.html 1. 概述 在SQL语句中经常需要进行字符串拼接,以sqlserver,oracle,mysql三 ...
- C#中的字符串拼接@,$
转载自:https://blog.csdn.net/qq_40666620/article/details/101695138 一:@ @的意思是以@标注的字符出,其中所有的符号均为字符串符号,没有什 ...
- oracle存储过程中使用字符串拼接
1.使用拼接符号“||” v_sql := 'SELECT * FROM UserInfo WHERE ISDELETED = 0 AND ACCOUNT =''' || vAccount || '' ...
- javascript中字符串拼接详解
字符串拼接是所有程序设计语言都需要的操作.当拼接结果较长时,如何保证效率就成为一个很重要的问题.本文介绍的是Javascript中的字符串拼接,希望对你有帮助,一起来看. 最近在研究<jav ...
- 阿里巴巴Java开发手册_不建议在循环体中使用+进行字符串拼接
18. [推荐]循环体内,字符串的连接方式,使用StringBuilder的append方法进行扩展. 说明:下例中,反编译出的字节码文件显示每次循环都会new出一个StringBuilder对象,然 ...
随机推荐
- python + selenium 练习篇 - 定位元素的方法
1.利用ID定位元素(能直接通过ID来定位的元素比较少) # coding=utf-8from selenium import webdriverdriver = webdriver.Chrome() ...
- Windows64bit-plsqldeveloper-install the easiest way
The easiest way to add a 32 Bit Oracle Client: 1.Download the Oracle 11g or 12c Instant Client(http: ...
- Tips In C
C语言中的使用操作 宏定义时使用do while防止语句的分离, 但是不使用与需要有返回值的语句, 这个时候可以参考第二条 宏定义时使用({}), ()加上{}的方式, 在代码中填写逻辑算法, 最后的 ...
- 在C#.net中如何操作XML
在C#.net中如何操作XML 需要添加的命名空间: using System.Xml; 定义几个公共对象: XmlDocument xmldoc ; XmlNode xmlnode ; XmlEle ...
- 文件上传PHP
<?php $targetIp = GetIP(); $fileUpload = 'fileUpload'; $frameCount = 'frameCount'; $fileName = $_ ...
- [总结]SHAREPOINT - CAML列表查询(上)
首先要了解的是CAML(Collaboration Application Markup Language)不仅仅是用在对列表.文档库的查询,字段的定义,站点定义等处处使用的都是CAML. 简单的提一 ...
- dell omsa管理工具
dell服务器raid管理工具 lsiutil dell sas6i/r MegaCli dell prec omsa管理raid分区 显示物理硬盘信息 omreport storage pdisk ...
- python定义class
python也是面向对象的语言,类的重要性不言而喻. class Animal: def __init__(self,voice='hello'): self.voice=voice def __de ...
- System Center Configuration Manager 2016 配置安装篇(Part1)
SCCM 2016 配置管理系列(Part 1- 4) 介绍AD01上配置了Active Directory域服务(ADDS),然后将Configuration Manager服务器(CM16)加入到 ...
- StringBuffer和StringBuilder区别?
1. String是不可变类,改变String变量中的值,相当于开辟了新的空间存放新的string变量 2. StringBuffer 可变的类,可以通过append方法改变变量的值,且StringB ...