一)简介
字符串拼接在程序中是很常用的,关键是需要了解各种字符串拼接方式原理,优先选择最好的字符串拼接方式。Java程序中提供了几种不同的拼接方式。
二)“+”号字符串拼接
“+”号字符串拼接是最简单方便的方式,刚学编程的时候,几乎都是用此方式。
1)字符串拼接方式
String s1 = "ouyangjun";
String s2 = "p812438109";
System.out.println(s1 + s2); // ouyangjunp812438109
2)反编译之后的源码
System.out.println(new StringBuilder(String.valueOf(s1)).append(s2).toString());
结论:编译时,先new一个StringBuilder对象,再把参数append到对象中,最后再toString。
3)字符串拼接方式
String s1 = "ouyangjun";
String s2 = "p812438109";
String s3 = "";
for (int i = 0; i < 10000; i++) {
s3 += s1 + s2;
System.out.println(s3);
}
4)反编译之后的源码
String s1 = "ouyangjun";
String s2 = "p812438109";
String s3 = "";
for (int i = 0; i < 10000; i++) {
s3 = new StringBuilder(String.valueOf(s3)).append(s1).append(s2).toString();
System.out.println(s3);
}
结论:在用"+"号拼接时,不管是什么方式拼接,都是会不断new StringBuilder对象。如循环次数越多,该拼接方式性能会越低,最终可能导致内存溢出等问题。现在程序中都不建议用该方式拼接字符串了。
三)StringBuffer字符串拼接
1)StringBuffer字符串拼接和反编译之后的源码是一样,没有太大的区别,如下。
StringBuffer buffer = new StringBuffer();
buffer.append("ouyangjun");
buffer.append("p812438109");
System.out.println(buffer); // ouyangjunp812438109
StringBuffer buffer = new StringBuffer();
for (int i = 0; i < 10000; i++) {
buffer.append("ouyangjun").append("p812438109");
System.out.println(buffer);
}
2)StringBuffer中append源码
@Override
public synchronized StringBuffer append(String str) {
toStringCache = null;
super.append(str); // 调用了父类AbstractStringBuilder的append方法
return this;
}
3)AbstractStringBuilder中append源码
public AbstractStringBuilder append(String str) {
if (str == null) // 如果str是null, 就返回空
return appendNull();
int len = str.length(); // 获取字符串的长度
ensureCapacityInternal(count + len); // 判断是否需要扩容
str.getChars(0, len, value, count); // 获取一个新的char[]数组
count += len; // 累加字符串的长度
return this; // 返回append之后的字符串
}
结论:StringBuffer有synchronized修饰,说明是线程安全的,在程序中强调线程安全性,选择该方式。
四)StringBuilder字符串拼接
1)StringBuilder字符串拼接和反编译之后的源码是一样,没有太大的区别,如下。
StringBuilder builder = new StringBuilder();
builder.append("ouyangjun");
builder.append("p812438109");
System.out.println(builder); // ouyangjunp812438109
StringBuilder builder = new StringBuilder();
for (int i = 0; i < 10000; i++) {
builder.append("ouyangjun").append("p812438109");
System.out.println(builder);
}
2)StringBuilder中append源码
@Override
public StringBuilder append(String str) {
super.append(str); // 调用了父类AbstractStringBuilder的append方法
return this;
}
3)AbstractStringBuilder中append源码
public AbstractStringBuilder append(String str) {
if (str == null) // 如果str是null, 就返回空
return appendNull();
int len = str.length(); // 获取字符串的长度
ensureCapacityInternal(count + len); // 判断是否需要扩容
str.getChars(0, len, value, count); // 获取一个新的char[]数组
count += len; // 累加字符串的长度
return this; // 返回append之后的字符串
}
结论:StringBuilder由于不是原子性的操作,也没有线程安全修饰符,说明不是线程安全的,在程序中不强调线程安全的情况,可选该方式。
五)StringJoiner字符串拼接
1)StringJoiner字符串拼接和反编译之后的源码是一样,区别在于该方式是用一个连接符把字符串拼接,如下。
StringJoiner joiner = new StringJoiner("-");
joiner.add("ouyangjun");
joiner.add("p812438109");
System.out.println(joiner); // 输出: ouyangjun-p812438109
StringJoiner joiner = new StringJoiner("-");
for (int i = 0; i < 10000; i++) {
joiner.add("ouyangjun").add("p812438109");
System.out.println(joiner);
}
2)StringJoiner中add源码
public StringJoiner add(CharSequence newElement) {
prepareBuilder().append(newElement); // 调用父类StringBuilder的append方法
return this;
}
private StringBuilder prepareBuilder() {
if (value != null) {
value.append(delimiter); // 在现有的StringBuilder基础上拼接字符串
} else {
value = new StringBuilder().append(prefix); // 字符串为null,直接new一个StringBuilder
}
return value;
}
结论:StringJoiner是实现了StringBuilder的append方法,也是一种线程不安全的字符串拼接方式。在程序中不强调线程安全,又需要通过某种连接符拼接字符串的时候,可选用该方式。
六)String中concat字符串拼接
1)concat字符串拼接方式,和反编译之后的源码差不多
String s1 = "ouyangjun";
String s2 = "p812428109";
System.out.println(s1.concat(s2));
String s3 = "";
for (int i = 0; i < 10000; i++) {
s3 = s3.concat(s1).concat(s2);
System.out.println(s3);
}
2)concat源码
public String concat(String str) {
int otherLen = str.length();
if (otherLen == 0) {
return this;
}
int len = value.length;
char buf[] = Arrays.copyOf(value, len + otherLen); // 创建一个新的char[]数组存储str
str.getChars(buf, len); // 把数组内容复制到str中
return new String(buf, true); // 创建一个新的String对象返回
}
结论:String中concat拼接方式,会不断创建数组,和复制数据,再返回一个新的String对象,性能不是很好。
7)String中join字符串拼接
1)join字符串拼接方式
String s1 = "ouyangjun";
String s2 = "p812428109";
System.out.println(String.join("-", s1, s2));
2)反编译之后的源码
String s1 = "ouyangjun";
String s2 = "p812428109";
System.out.println(String.join("-", new CharSequence[]{s1, s2}));
结论:会先把字符串转换成一个CharSequence[]数组,再用连接符拼接字符串。
3)join字符串拼接方式
String s1 = "ouyangjun";
String s2 = "p812428109";
String s3 = "";
for (int i = 0; i < 10000; i++) {
s3 = String.join("-", s1, s2, s3);
System.out.println(s3);
}
4)反编译之后的源码
String s1 = "ouyangjun";
String s2 = "p812428109";
String s3 = "";
for (int i = 0; i < 10000; i++) {
s3 = String.join("-", new CharSequence[]{s1, s2, s3});
System.out.println(s3);
}
结论:在循环中使用String的join方式拼接字符串,也会不断创建String对象,性能不是很好。
八)字符串拼接方式总结
1)String中“+”号、concat、join这几种字符串拼接方式在循环中的场景下,都可能存在性能。如果只是单纯两两拼接的话,还可以选择使用该方式。
2)StringBuffer字符串拼接方式,适用于程序中强调线程安全的场景下。
3)StringBuilder字符串拼接方式,适用于程序中不强调线程安全的场景下。
4)StringJoiner字符串拼接方式,适用于程序中不强调线程安全,并需要把字符串用连接符连接场景下。
识别二维码关注个人微信公众号
本章完结,待续、欢迎转载!
本文说明:该文章属于原创,如需转载,请标明文章转载来源!