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

1. 前言

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

2. 场景分析

2.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");
    }
}

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

bc7df7417fce2a89b8842aec35bc4ad4.png

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

  • 首先看标记为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的区别。

1.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);
	}
}

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

a8d693ee375403dfa5415910a0b7a05f.png

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

  • 从0标记的位置到3标记的位置,代表着我们定义了a和b的变量,并且值为"1"和"2",然后就到了我们String c = a + b,可以看到在反编译内容中的6标记的位置,是初始化了一个StringBuilder,然后使用了append方法进行拼接了,从这里就可以很清楚直白的看出,
    原来java把我们的String + 号优化成StringBuilder的append了
  • StringBuilder部分跟之前分析的一样
我相信看到这里,可以很明显的知道了,当我们使用String拼接变量的时候,jvm会帮我们优化成StringBuilder来进行拼接,所以如果是像上面这样的场景使用拼接,两者性能是没有差异的。

1.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");
		}

	}
}

我们继续来看反编译后的内容:

966f5f6b7cd6d4a1e43cf8fad6f6f594.png

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

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

3. 尾语

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

4、公众号

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

5. QQ 群

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

e7296820ac692b2b9a173935d002bed0.png

5. 相关说明

转载本文,记得附上本文地址链接!
  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值