一、字符串拼接
重点注意:对象
特别是String对象的使用,出现字符串拼接时应该使用StringBuilder/StringBuffer代替。由于Java虚拟机不仅要花时间生成对象,以后可能还需要花时间对这些对象进行垃圾回收和处理,因此,生成过多的对象将会给程序的性能带来很大的影响。
字符串的拼接在开发过程中使用是非常频繁的,常用的方式有三种:
(1)、+ 号拼接: str+"456"
(2)、StringBuilder 拼接
(3)、StringBuffer拼接
StringBuffer是保证线程安全的,效率是比较低的,我们更多的是使用场景是不会涉及到线程安全的问题的,所以更多的时候会选择StringBuilder,效率会高一些。
那么,问题来了,StringBuilder和“+”号拼接,哪个效率高呢?接下来我们通过字节码的方式进行探究。
public class Test3 { public static void main(String[] args) { new Test3().m1(); new Test3().m2(); } public void m1(){ String s1 = "123"; String s2 = "456"; String s3 = s1 + s2; System.out.println(s3); } public void m2(){ String s1 = "123"; String s2 = "456"; StringBuilder sb = new StringBuilder(); sb.append(s1); sb.append(s2); String s3 = sb.toString(); System.out.println(s3); } }
查看 Test3.class的字节码,从解字节码中可以看出, m1()方法源码中是使用+号拼接,但是在字节码中也被编译成了StringBuilder方式。
所以,可以得出结论,字符串拼接,+号和StringBuilder是相等的,效率一样。
接下来,我们看一个案例:
public class Test4 {
public static void main(String[] args) {
new Test4().m1();
new Test4().m2();
}
public void m1(){
String str = "";
for (int i = 0; i < 5; i++) {
str = str + i;
}
System.out.println(str);
}
public void m2(){
StringBuilder sb = new StringBuilder();
for (int i = 0; i < 5; i++) {
sb.append(i);
}
System.out.println(sb.toString());
}
}
m1() 与 m2() 哪个方法的效率高?
m1()方法中的循环体内,每一次循环都会创建StringBuilder对象,效率低于m2()方法。当用+号进行一次字符串拼接的时候都会new一个StringBuilder,循环5次就会new 5个StringBuilder对象。m2()方法中在循环体内并没有new StringBuilder对象,而是每次都是调用append方法,即在循环体外new了一次,在循环体内一直append,而new对象和销毁对象(垃圾回收)都会占用系统资源。
总结:for循环中字符串拼接用StringBuilder。
二、StringJoiner
1、StringJoiner入门
StringJoiner是Java 8新增的一个API,他是基于StringBuilder实现,用于实现对字符串之间通过分隔符拼接的场景。
有些字符串拼接场景,使用StringBuilder或StringBuffer会显得比较繁琐。
这种字符串有前缀后缀并且由 “,” 分隔的字符串,在 Java 8 之前要使用 StringBuilder/ StringBuffer 进行拼接,如下:
StringBuilder sb = new StringBuilder();
sb.append("(");
sb.append("hello");
sb.append(",");
sb.append("guys");
sb.append(",");
sb.append("欢迎大家");
sb.append(")");
String str = sb.toString();
上述代码显得十分难看又略显繁琐。
Java 8使用StringJonier来实现,如下:
StringJoiner stringJoiner = new StringJoiner(",", "(", ")");
stringJoiner.add("hello");
stringJoiner.add("guys");
stringJoiner.add("欢迎大家");
StringJonier实现就显得比较优雅!
2、StringJoiner详解
1)、成员变量
prefix:拼接后的字符串前缀
delimiter:拼接时的字符串分隔符
suffix:拼接后的字符串后缀
value:拼接后的值
emptyValue:空值的情况,value为 null 时返回
构造方法:
StringJoiner有两个构造方法
一个是要求传入分隔符、前缀和后缀
public StringJoiner(CharSequence delimiter,
CharSequence prefix,
CharSequence suffix) {
Objects.requireNonNull(prefix, "The prefix must not be null");
Objects.requireNonNull(delimiter, "The delimiter must not be null");
Objects.requireNonNull(suffix, "The suffix must not be null");
// make defensive copies of arguments
this.prefix = prefix.toString();
this.delimiter = delimiter.toString();
this.suffix = suffix.toString();
this.emptyValue = this.prefix + this.suffix;
}
另一个是只需要传入分隔符(前缀和后缀默认是"")
public StringJoiner(CharSequence delimiter) {
this(delimiter, "", "");
}
方法:
setEmptyValue:设置空值
toString:转换成 String
add:添加字符串
merge:从另一个 StringJoiner 合并
length:长度(包括前缀后缀)
主要看add()源码:
public StringJoiner add(CharSequence newElement) {
prepareBuilder().append(newElement);
return this;
}
private StringBuilder prepareBuilder() {
if (value != null) {
value.append(delimiter);
} else {
value = new StringBuilder().append(prefix);
}
return value;
}
可以看到内部其实就是用的StringBuilder进行封装的,首次创建会先拼接前缀,后续先添加分隔符,再添加字符串。
toString()源码
public String toString() {
if (value == null) {
return emptyValue;
} else {
if (suffix.equals("")) {
return value.toString();
} else {
int initialLength = value.length();
String result = value.append(suffix).toString();
// reset value to pre-append initialLength
value.setLength(initialLength);
return result;
}
}
}
可以看到内部其实就是用的StringBuilder进行封装的,首次创建会先拼接前缀,后续先添加分隔符,再添加字符串。
主要就通过上述两个方法,实现前缀、后缀以及分隔符的拼接。(最后输出才进行后缀的拼接)
另外一点,add 方法就是返回 StringJoiner 本身,所以可以像StringBuilder/ StringBuffer 一样进行流式处理。如下:
StringJoiner stringJoiner = new StringJoiner(",", "(", ")").add("hello").add("guys").add("欢迎大家");
System.out.println(stringJoiner);
2)、空值处理
没有拼接任何字符串的几个空值处理场景。
输出空白字符串
StringJoiner stringJoiner = new StringJoiner(","); System.out.println(stringJoiner.toString());
输出前后缀
StringJoiner stringJoiner = new StringJoiner(",", "[", "]"); System.out.println(stringJoiner.toString());
结果:[]
输出指定字符串
StringJoiner stringJoiner = new StringJoiner(",", "[", "]"); stringJoiner.setEmptyValue("likelong"); System.out.println(stringJoiner.toString());
结果:likelong