为什么阿里巴巴Java开发手册中不建议在循环体中使用+进行字符串拼接?

/**

  • @author wupx

  • @date 2019/10/23

*/

public class StringConcatDemo {

public static void main(String[] args) {

long s1 = System.currentTimeMillis();

new StringConcatDemo().addMethod();

System.out.println(“使用 + 拼接:” + (System.currentTimeMillis() - s1));

s1 = System.currentTimeMillis();

new StringConcatDemo().stringBuilderMethod();

System.out.println(“使用 StringBuilder 拼接:” + (System.currentTimeMillis() - s1));

}

public String addMethod() {

String result = “”;

for (int i = 0; i < 100000; i++) {

result += (i + “武培轩”);

}

return result;

}

public String stringBuilderMethod() {

StringBuilder result = new StringBuilder();

for (int i = 0; i < 100000; i++) {

result.append(i).append(“武培轩”);

}

return result.toString();

}

}

执行结果如下:

使用 + 拼接:29282

使用 StringBuilder 拼接:4

为什么这两种方法的时间会差这么多呢?接下来让我们一起进一步研究。

1、为什么 StringBuilder 比 + 快这么多?

=================================

从字节码层面来看下,为什么循环体中字符串拼接 StringBuilder 比 + 快这么多?

使用 javac StringConcatDemo.java 命令编译源文件,使用 javap -c StringConcatDemo 命令查看字节码文件的内容。

其中 addMethod() 方法的字节码如下:

public java.lang.String addMethod();

Code:

0: ldc #16 // String

2: astore_1

3: iconst_0

4: istore_2

5: iload_2

6: ldc #17 // int 100000

8: if_icmpge 41

11: new #7 // class java/lang/StringBuilder

14: dup

15: invokespecial #8 // Method java/lang/StringBuilder.“”😦)V

18: aload_1

19: invokevirtual #10 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;

22: iload_2

23: invokevirtual #18 // Method java/lang/StringBuilder.append:(I)Ljava/lang/StringBuilder;

26: ldc #19 // String wupx

28: invokevirtual #10 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;

31: invokevirtual #12 // Method java/lang/StringBuilder.toString:()Ljava/lang/String;

34: astore_1

35: iinc 2, 1

38: goto 5

41: aload_1

42: areturn

可以看出,第 8 行到第 38 行构成了一个循环体:在第 8 行的时候做条件判断,如果不满足循环条件,则跳转到 41 行。编译器做了一定程度的优化,在 11 行 new 了一个 StringBuilder 对象,然后再 19 行、23 行、28 行进行了三次 append() 方法的调用,不过每次循环都会重新 new 一个 StringBuilder 对象。

再来看 stringBuilderMethod() 方法的字节码:

public java.lang.String stringBuilderMethod();

Code:

0: new #7 // class java/lang/StringBuilder

3: dup

4: invokespecial #8 // Method java/lang/StringBuilder.“”😦)V

7: astore_1

8: iconst_0

9: istore_2

10: iload_2

11: ldc #17 // int 100000

13: if_icmpge 33

16: aload_1

17: iload_2

18: invokevirtual #18 // Method java/lang/StringBuilder.append:(I)Ljava/lang/StringBuilder;

21: ldc #19 // String wupx

23: invokevirtual #10 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;

26: pop

27: iinc 2, 1

30: goto 10

33: aload_1

34: invokevirtual #12 // Method java/lang/StringBuilder.toString:()Ljava/lang/String;

37: areturn

13 行到 30 行构成了循环体,可以看出,在第4行(循环体外)就构建好了 StringBuilder 对象,然后再循环体内只进行 append() 方法的调用。

由此可以看出,在 for 循环中,使用 + 进行字符串拼接,每次都是 new 了一个 StringBuilder,然后再把 String 转成 StringBuilder,再进行 append,而频繁的新建对象不仅要耗费很多时间,还会造成内存资源的浪费。这就从字节码层面解释了为什么不建议在循环体内使用 + 去进行字符串的拼接。

接下来再来让我们看下使用 + 或者 StringBuilder 拼接字符串的原理吧。

2、使用 + 拼接字符串

================

在 Java 开发中,最简单常用的字符串拼接方法就是直接使用 + 来完成:

String boy = “wupx”;

String girl = “huxy”;

String love = boy + girl;

反编译后的内容如下:(使用的反编译工具为 jad)

String boy = “wupx”;

String girl = “huxy”;

String love = (new StringBuilder()).append(boy).append(girl).toString();

通过查看反编译以后的代码,可以发现,在字符串常量在拼接过程中,是将 String 转成了 StringBuilder 后,使用其 append() 方法进行处理的。

那么也就是说,Java中的 + 对字符串的拼接,其实现原理是使用 StringBuilder 的 append() 来实现的,使用 + 拼接字符串,其实只是 Java 提供的一个语法糖。

**3、**使用 StringBuilder 拼接字符串

==================================

StringBuilder 的 append 方法就是第二个常用的字符串拼接姿势了。

和 String 类类似,StringBuilder 类也封装了一个字符数组,定义如下:

char[] value;

与 String 不同的是,它并不是 final 的,所以是可以修改的。另外,与 String 不同,字符数组中不一定所有位置都已经被使用,它有一个实例变量,表示数组中已经使用的字符个数,定义如下:
自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数Java工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则几千的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

因此收集整理了一份《2024年Java开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。img

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Java开发知识点,真正体系化!

由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!

如果你觉得这些内容对你有帮助,可以扫码获取!!(备注Java获取)

img

总结

其他的内容都可以按照路线图里面整理出来的知识点逐一去熟悉,学习,消化,不建议你去看书学习,最好是多看一些视频,把不懂地方反复看,学习了一节视频内容第二天一定要去复习,并总结成思维导图,形成树状知识网络结构,方便日后复习。

这里还有一份很不错的《Java基础核心总结笔记》,特意跟大家分享出来

目录:

部分内容截图:


《互联网大厂面试真题解析、进阶开发核心学习笔记、全套讲解视频、实战项目源码讲义》点击传送门即可获取!
识网络结构,方便日后复习。

这里还有一份很不错的《Java基础核心总结笔记》,特意跟大家分享出来

目录:

[外链图片转存中…(img-Kakbi9Am-1713461849469)]

部分内容截图:

[外链图片转存中…(img-57Z9354s-1713461849470)]

[外链图片转存中…(img-P1IIjY8R-1713461849470)]
《互联网大厂面试真题解析、进阶开发核心学习笔记、全套讲解视频、实战项目源码讲义》点击传送门即可获取!

  • 8
    点赞
  • 25
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 非常感谢您的提问。我了解到您使用的是CSDN上开发的C知道,并且我是一个类似于ChatGPT的AI模型,我们之间没有直接的联系。 关于您的问题,使用引号将空格括起来是一种常见的字符串表示方法,它可以将一个由多个单词组成的字符串表示为一个整体。在某些情况下,这种表示方法可以方便地处理字符串,但并不是所有情况都适用。在for循环使用引号括起来的字符串可能会引起语法错误,因为编译器无法识别它们。因此,使用for循环时,通常建议不要使用引号来表示空格。 如果您有其他问题,我很乐意尝试回答它们。请随时向我提问! ### 回答2: 在for循环使用“+”进行字符串拼接耗费大量的时间和资源。这是因为每次拼接字符串时,都会创建一个新的字符串对象,并且将原始字符串和要拼接的部分复制到新的字符串。由于字符串是不可变的,每次拼接都需要创建一个新的字符串对象,这将导致频繁的内存分配和复制操作,严重影响性能。 相比之下,使用“+”进行字符串拼接的时间复杂度为O(n^2),其n是要拼接的字符串的长度。在for循环进行重复的字符串拼接操作时,会导致时间复杂度呈指数级增长,非常低效。 为了避免这种性能问题,推荐使用StringBuilder类或StringBuffer类来进行字符串拼接。这两个类都提供了高效的字符串拼接方法,通过追加字符串的方式来实现拼接,避免了创建新的字符串对象和频繁的复制操作。StringBuilder相比于StringBuffer具有更高的性能,但是不是线程安全的。 综上所述,为了提高性能,避免不必要的内存分配和复制操作,不建议在for循环使用“+”进行字符串拼接,而是应该使用StringBuilder或StringBuffer类来进行字符串拼接。 ### 回答3: 在使用 for 循环时,不建议使用“+”进行字符串拼接的主要原因是字符串是不可变的。每次进行字符串拼接时,都会创建一个新的字符串对象,而且字符串对象无法修改,只能重新创建一个包含新内容的字符串对象。 这样的操作会消耗大量的系统资源和时间。当循环次数较多时,每次拼接字符串都会引发一次创建对象的开销,导致性能下降,程序执行时间变长。 相比之下,在大量字符串拼接的情况下,使用“+”运算符拼接字符串效率较低。而使用StringBuilder类或StringBuffer类来进行字符串拼接,会更高效。这两个类都是基于可变字符序列的,可以直接在原来的字符串上进行修改和添加,避免了创建多个字符串对象的开销。 因此,在循环如果需要进行字符串拼接操作,建议使用StringBuilder类或StringBuffer类,先创建一个StringBuilder(或StringBuffer)对象,然后在循环通过调用其append()方法来添加字符串,最后使用toString()方法转换为String类型输出。 总之,不建议在for循环使用“+”进行字符串拼接,应该使用StringBuilder或StringBuffer类来提高程序性能。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值