欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

关于 Java 字符串拼接的那点事

程序员文章站 2022-06-23 14:57:54
...

一、前言

分享下关于字符串拼接,应该在什么场景使用什么样的最适合,性能最好,
这也是一个很基础的以及面试或者笔试经常会遇到的问题。Ok,let’s go !


二、场景分析

1. 场景1
public class Main {
    public static void main(String[] args) {
        String a = "1" + "2";
        StringBuilder sb = new StringBuilder();
        sb.append("1");
        sb.append("2");
        StringBuffer buffer = new StringBuffer();
        buffer.append("1");
        buffer.append("2");
    }
}

为了很清晰的看出它们的区别,最好的方式就是直接去反编译这段代码,下面就是反编译出来的内容

关于 Java 字符串拼接的那点事

下面让我们分析上反编译出来的内容:

  • 首先看标记为0的地,后面有个String 12,其实这里对应着我们的第一行String a = “1” + “2”;从这里可以看到java在编译期就已经把它拼接成"12"了。
  • 我们看下面,可以看到初始化了一个StringBuilder对象,并且调用append方法,其实StringBuilder是在里面维护了一个char[]类型数组用来存储我们的字符串,具体是如何的呢,建立可以看下源码
  • 最后就是初始化了一个StringBuffer对象,调用append方法,其实StringBuffer是在StringBuilder的基础上保证了线程安全,append方法加了synchronized,那这里肯定会影响性能,感兴趣的可以看下源码

通过上面简单的分析,相信都知道了,上面这个场景直接使用String效率是最高的,因为这个是在编译器就已经确定好value了,
可以看出StringBuffer是个线程安全,所以相对会牺牲掉一些性能,当然jdk1.6后对于synchronized进行了很大的优化,所以性能也还不错。
所以下面重点分析String和StringBuilder的区别。


2. 场景2
public class Main {

	public static void main(String[] args) {
		String a = "1";
		String b = "2";
		String c = a + b;
		StringBuilder sb = new StringBuilder();
		sb.append(a);
		sb.append(b);
	}
}


一样的,我们来看看反编译后的内容:

关于 Java 字符串拼接的那点事


然后再分析下上面反编译的内容:

  • 从0标记的位置到3标记的位置,代表着我们定义了a和b的变量,并且值为"1"和"2",然后就到了我们String c = a + b,可以看到在
    反编译内容中的6标记的位置,是初始化了一个StringBuilder,然后使用了append方法进行拼接了,从这里就可以很清楚直白的看出,
    原来java把我们的String + 号优化成StringBuilder的append了

  • StringBuilder部分跟之前分析的一样


我相信看到这里,可以很明显的知道了,当我们使用String拼接变量的时候,jvm会帮我们优化成StringBuilder来进行拼接,
所以如果是像上面这样的场景使用拼接,两者性能是没有差异的。

3. 场景3
public class Main {

	public static void main(String[] args) {
		String a = "";
		StringBuilder sb = new StringBuilder();
		for (int i = 0; i < 10; i ++) {
			a += "hello";
			sb.append("hello");
		}

	}
}

我们继续来看反编译后的内容:
关于 Java 字符串拼接的那点事

同样的套路,我们来分析下:

  • 首先在写的代码中是循环十次,每次都进行累加拼接"hello"这个字符串,我们可以看到在反编译内容中,
    在 a += "hello"这个位置是初始化了一个StringBuilder对象,可能会疑惑了,为什么我拼接的是常量"hello"啊,
    为什么会jvm会优化成StringBuilder,不应该是编译就确定好才对吗?其实这里因为a += "hello"其实就是a = a + “hello”,
    这里可以看到a是个变量,所以java无法提前预知,所以就转换成了StringBuilder。
  • 然后我们看反编译的19标记的地方到35的地方,在for循环内,每次都会创建一个StringBuilder对象,这里就很明显了,
    每次创建对象,浪费了很大的空间,并且创建需要开销,所以,可以看出这里使用String拼接,性能就会很低。

三、尾语

相信通过上面的三个场景分析,可以很明显的看出在什么情况下,使用哪个进行拼接性能最好,最合适,最优雅。
最后我们在总结下,在拼接都是常量的时候,使用String性能最高,在有变量的时候使用StringBuilder性能比较好,
在多线程安全情况下,使用StringBuffer是最合适的。切记不要在循环里面使用String拼接变量。

四、公众号

欢迎大家加入到我的公众号。公众号: MonarchCode,如果你想学习更多的关于分布式、微服务、k8s、docker 等等干货,那赶紧关注获取一波学习文章,更是有我录播的免费视频观看,只要关注即可哦!

五. QQ 群

欢迎大家加入我创建的 QQ 群,QQ 群号: 963643807 或者扫描二维码入群,会不定期分享资源,分享技术、视频,让大家在技术成长、进阶的路上更加畅通无阻!

关于 Java 字符串拼接的那点事