LeetCode 中使用 StringBuilder 连接字符串为什么会比用+号连接快? - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
kuretru
V2EX    LeetCode

LeetCode 中使用 StringBuilder 连接字符串为什么会比用+号连接快?

  •  
  •   kuretru
    kuretru 2021-01-10 11:05:18 +08:00 3499 次点击
    这是一创建于 1742 天前的主题,其中的信息可能已经有所发展或是发生改变。

    今日 LeetCode 的每日一题,代码很简单,官方的题解如下:

    class Solution { public List<String> summaryRanges(int[] nums) { List<String> ret = new ArrayList<String>(); int i = 0; int n = nums.length; while (i < n) { int low = i; i++; while (i < n && nums[i] == nums[i - 1] + 1) { i++; } int high = i - 1; StringBuffer temp = new StringBuffer(Integer.toString(nums[low])); if (low < high) { temp.append("->"); temp.append(Integer.toString(nums[high])); } ret.add(temp.toString()); } return ret; } } 

    可以看到官方使用 StringBuffer 来连接字符串,在不需要考虑线程安全的环境,毫无疑问可以使用 StringBuilder 来代替,但是问题在于,为什么使用+号来连接的效果会比 StringBuilder 及 StringBuffer 差?

    String temp = Integer.toString(nums[low]); if (low < high) { temp += "->" + Integer.toString(nums[high]); } ret.add(temp); 

    两者的差别为:
    StringBuilder/StringBuffer:执行用时:0 ms, 在所有 Java 提交中击败了 100.00%的用户
    +号连接:执行用时:8 ms, 在所有 Java 提交中击败了 70.02%的用户
    同样的代码在本地各循环 1000 万次的结果为
    JDK 1.8(与 LeetCode 相同):7708ms vs 7287ms
    JDK 11:7320ms vs 4511ms

    9 条回复    2021-01-10 15:00:38 +08:00
    snw
        1
    snw  
       2021-01-10 11:23:24 +08:00
    我记得大致上是因为用 + 时,内部会创建一个新的 string,然后把连接的值赋给这个新的 string 。
    用 StringBuilder 的话是直接把增加的字符 append 到原字符串后面,省去了创建新 string 、删除旧 string 的消耗。
    kuretru
        2
    kuretru  
    OP
       2021-01-10 11:26:16 +08:00
    @snw #1
    你说的是循环内的情况把
    ```java
    String text = "";
    for(){
    test += something;
    }
    ```
    这种情况下,使用 StringBuilder 和 StringBuffer 无疑
    vincentxue
        3
    vincentxue  
       2021-01-10 11:57:31 +08:00
    这个和循环没关系,循环只是进一步放大了性能问题,字符串只要是拼接变量,不管放在哪里,编译器都会给你换成 StringBuilder 的。最直接的办法就是把你两份代码转成字节码一对比你就能看明白里面的原因。
    Merlini
        4
    Merlini  
       2021-01-10 12:08:49 +08:00
    正好最近在入门 java

    > 有些时候 , 需要由较短的字符串构建字符串 , 例如 , 按键或来自文件中的单词。 采用字符串连接的方式达到此目的效率比较低。 每次连接字符串 ,都会构建一个新的 String 对象 ,既耗时 , 又浪费空间。 使用 StringBuilder 类就可以避免这个问题的发生。
    取自 java 核心卷 1
    micean
        5
    micean  
       2021-01-10 12:09:13 +08:00 via Android
    这是 java 的基础问题啊……加号在不可优化的情况下每使用一次相当于拷贝了一次旧串 byte[]和新增串 byte[],性能当然就低了
    AllenHua
        6
    AllenHua  
       2021-01-10 12:13:14 +08:00
    如果只是简单的字符串拼接 使用 concat 比 使用 + 效率更高

    但是 concat 只能 concat String 类型的数据

    + 可以 拼接其他基础类型的数据

    老生常谈 如果大量操作 String 务必使用封装类 StringBuffer 或 StringBuilder 或 StringJoiner
    hoyixi
        7
    hoyixi  
       2021-01-10 12:25:24 +08:00
    这是 N 年前面试官爱问的问题,已经被问烂了
    Jooooooooo
        8
    Jooooooooo  
       2021-01-10 14:49:08 +08:00
    String 的 + 每次都 new 对象

    非常大的循环记得用 StringBuilder
    340244120w
        9
    340244120w  
       2021-01-10 15:00:38 +08:00 via iPhone
    楼上大部分都看的 java 核心思想吧。其实现在 8 之后,循环里直接拼字符串,相当于每次循环都创建了一个 stringbuilder,相对于循环外面只创建一个,自然就慢了
    关于     帮助文档     自助推广系统     博客     API     FAQ     Solana     1317 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 25ms UTC 17:16 PVG 01:16 LAX 10:16 JFK 13:16
    Do have faith in what you'redoing.
    ubao msn snddm index pchome yahoo rakuten mypaper meadowduck bidyahoo youbao zxmzxm asda bnvcg cvbfg dfscv mmhjk xxddc yybgb zznbn ccubao uaitu acv GXCV ET GDG YH FG BCVB FJFH CBRE CBC GDG ET54 WRWR RWER WREW WRWER RWER SDG EW SF DSFSF fbbs ubao fhd dfg ewr dg df ewwr ewwr et ruyut utut dfg fgd gdfgt etg dfgt dfgd ert4 gd fgg wr 235 wer3 we vsdf sdf gdf ert xcv sdf rwer hfd dfg cvb rwf afb dfh jgh bmn lgh rty gfds cxv xcv xcs vdas fdf fgd cv sdf tert sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf shasha9178 shasha9178 shasha9178 shasha9178 shasha9178 liflif2 liflif2 liflif2 liflif2 liflif2 liblib3 liblib3 liblib3 liblib3 liblib3 zhazha444 zhazha444 zhazha444 zhazha444 zhazha444 dende5 dende denden denden2 denden21 fenfen9 fenf619 fen619 fenfe9 fe619 sdf sdf sdf sdf sdf zhazh90 zhazh0 zhaa50 zha90 zh590 zho zhoz zhozh zhozho zhozho2 lislis lls95 lili95 lils5 liss9 sdf0ty987 sdft876 sdft9876 sdf09876 sd0t9876 sdf0ty98 sdf0976 sdf0ty986 sdf0ty96 sdf0t76 sdf0876 df0ty98 sf0t876 sd0ty76 sdy76 sdf76 sdf0t76 sdf0ty9 sdf0ty98 sdf0ty987 sdf0ty98 sdf6676 sdf876 sd876 sd876 sdf6 sdf6 sdf9876 sdf0t sdf06 sdf0ty9776 sdf0ty9776 sdf0ty76 sdf8876 sdf0t sd6 sdf06 s688876 sd688 sdf86