String,StringBuffer,StringBuilder,StringJoiner有什么区别?项目中什么时候用?
先做一个简介:
- String : 是java.lang包中的immutable类,String里面所有的属性几乎也是final,由于它的不可变性,类似拼接,裁剪字符串等动作都会产生大量无用的中间对象。由于字符串操作在项目中很常见,所以对String的操作对项目的性能往往有很明显的影响。
- StringBuffer : 这个类是为了解决String拼接产生多余对象的问题而提供的一个类。StringBuffer保证了线程的安全,也带来了多余的开销。
- StringBuilder : StringBuilder的功能与StringBuffer一样。但是区别是StringBuilder没有处理线程安全,减少了开销。
- StringJoiner:StringJoiner也是用来拼接字符的。不过它是用来分割字符,拼接前缀和后缀的,拼接实现也是使用StringBuilder, 可以说它是StringBuilder的升级版,所以它也是线程不安全的。
区别总结:
1.StringBuffer算是String的敷生的一个类,而StringBuilder却又是Oracle公司为了减少线程开销,而诞生的一个类(这个区别有点扯…),StringJoiner是为了更加方便分割字符,精炼代码?
2.字符串的主要操作还是String。StringBuffer,StringJoiner与StringBuilder主要还是用来拼接字符串的。
3.StringBuffer与StringBuilder的长度是可以定义的,而String不能(因为String是个对象)。StringJoiner也不行,它的长度是主体字符串,字符串前缀,字符串后缀组成
4.这几种主要用的地方都不一样,下面会有介绍。
然后就是使用:
- String:它被用于裁剪,拼接。(当然如果拼接过多的话还是建议用StringBuffer,或者> StringBuild)搜索字符串,比较字符串,截取字符串,转换大小写等。在项目中不经常发生变化的业务场景中,优先使用String
- StringBuffer:用于拼接,替换,删除。在项目多线程环境下运行,如:XML解析,HTTP参数解析与封装等。
- StringBuilder:它同StringBuffer使用方式一样,不过在项目中使用的地方建议是单线程的环境下,如:SQL拼接,JSON封装等。
- StringJoiner:用来封装前缀后缀以及间隔符都是一样的字符串,将集合数据拼接为字符串等(StringBuilder也可以进行这样的操作,只是麻烦些)
// StringJoiner使用方式
public void stringJoinerTest() {
StringJoiner sj = new StringJoiner(":", "[", "]");
sj.add("George").add("Sally").add("Fred");
String desiredString = sj.toString();
// 输出字符串:[George:Sally:Fred]
System.out.println(desiredString);
List<Integer> numbers = Arrays.asList(1, 2, 3, 4);
String commaSeparatedNumbers = numbers.stream()
.map(i -> i.toString())
.collect(Collectors.joining(", "));
// 输出字符串:1, 2, 3, 4
System.out.println(commaSeparatedNumbers);
}
public void stringBuildTest() {
StringBuilder stringBuilder = new StringBuilder();
String stringBuilderToString = stringBuilder.append("[").append("George")
.append(":").append("Sally")
.append(":").append("Fred")
.append("]").toString();
// 输出字符串:[George:Sally:Fred]
System.out.println(stringBuilderToString);
StringBuilder stringBuilderNumbers = new StringBuilder();
for (int i = 0; i < numbers.size(); i++) {
stringBuilderNumbers.append(numbers.get(i));
if (i != numbers.size() - 1) {
stringBuilderNumbers.append(", ");
}
}
// 输出字符串:1, 2, 3, 4
System.out.println(stringBuilderNumbers.toString());
}
拓展>>
1.String JDK9后大改:将数据存储方式从char[]数组修改为byte[]数组在加上一个标示编码,然后重写所有相关的类,以保证没有任何性能上的损失。
2.StringBuffer与StringBuilder两者都是由byte[]数组(在JDK 9 以后),所以能定义长度,但是如果不定义的话那默认为16。如果当前对象操作,使得数组长度超过了16,那么数组就会创建新的,还要进行arraycopy,丢弃原来数组。
3.讲String的时候必须得讲一下字符串的缓存。字符串的缓存核心方法就是intern();这个方法了。这个方法主要逻辑是判断当前字符串是否存在于StringTable,如果存在则取出来,如果不存在则添加进去。具体详细使用与解析对比还请看http://www.importnew.com/21836.html,这篇博客,个人认为是极好的。通俗易懂。
4.如果看完链接想使用字符串的intern();这个方法。然而每次都要调用,这未免太过于麻烦,考虑到这个因素,博主给诸位提供一个不用掉用也能使用intern();的方法。那就是配置GC,且要使用G1 GC,GC配置是 ‘-XX:+UseStringDeduplication’ 。
5.在使用了intern();方法的情况下,尽量不要使用new 方法来创建新的字符串,因为new 方法是直接在堆中创建一个对象,不会去字符串常量池中,进行操作。
6.看下面代码块吧~
//.java文件:
public static void main(String args[]){
String c = "12241241242";
String b = UUID.randomUUID().toString().intern();
String a = "sda"+"123"+b+"sss"+c;
}
//.class文件反编译后
public static void main(String[] args) {
String c = "12241241242";
String b = UUID.randomUUID().toString().intern();
(new StringBuilder()).append("sda123").append(b).append("sss").append(c).toString();
}
博文部分资料来源于:java核心技术36讲。
如果博文有什么错误的地方欢迎指出,非常感谢。如果有相互交流的欢迎交流。最后,感谢每一位程序猿对代码的辛勤付出。