java sb.append_Java又被喷了 String的append

501a80c0a902

开吵的缘由

姐夫说

看到群里有人贴这个。Java编译器真的会把普通的字符串拼接操作“优化”为StringBuilder?有这么糟蹋性能的做法吗? ​​​​

嗯... 小萌新表示 还好吧. 否则每次在常量空间中创建一个中间值 这样子多不值当. (虽然的在新的JVM标准中 已经把String 从常量空间挪到新生区域了

这是个严重影响性能的做法不是吗?明明目标字符串长度也可以知道,你搞个SB需要额外字符数组翻几次倍最后再复制一份,怪不得总是要和GC作斗争,这么个基础操作都这么浪费。

原来Java出了二十几年,.NET出了十五年了,到现在还有那么多人连如何高效地拼接字符串,什么时候该使用StringBuilder什么时候不该使用都不清楚。还有人说一万个字符串拼接用SB就快了等等,当然不是。SB的使用场景是目标字符串长度不确定的情况,和到底是十个还是十万个字符串,到底最终长度是一百还是一百万都没有关系。比如之前的场景,每个字符串都是确定的,最终长度自然也是确定的,这根本就不应该动用SB。假如你不知道应该怎么做,那只能让你去看下十五年前开始.NET就采取的做法。在目标字符串长度确定的情况下,出现目标字符串外任意一个额外的内存分配都是不及格。

另外有人说“一个”StringBuilder对象,好像没多少开销一样。但是SB不是一个对象,而是一串对象啊。你append过程中随时就会分配一个长度翻倍的新的char数组,然后还要复制一遍。多少人以为用SB就够了一样,都不知道需要指定一个capacity。

比如那段所谓被Java编译器“优化”的代码,capacity也没指定,翻倍和复制几乎肯定发生。当然假如他们知道指定capacity,也不会使用SB这么低效的做法了吧。

刚才忘记切换jdk了,java9 已经不是这样了,会使用makeConcatWithConstants 进行拼接

至于非final时用append来搞,从JDK 1.1时代就是这么玩了。当然,还是写javac的人偷懒,先确定长度再生成SB会好一些,但是碰到为null时怎么调用xxx.length(),搞到最后变成这样: 网页链接

正确的字符串拼接方式 网页链接 算出总长,分配目标字符串内存,把输入的字符串复制到正确的位置。出现任意额外的StringBuilder啊char数组分配什么的都是不及格。 ​​​​

我是真不知道直到 Java 9 才有 StringConcatFactory 这种东西的,所以才没能理解为什么 Java 程序员普遍觉得除了 .append 就只有 StringBuilder 一途

至于为什么 .NET 这边不鼓励滥用 StringBuilder,我觉得就算想一下为什么 Java 9 会有 StringConcatFactory 也该明白了。

多说一句,其实StringBuilder在拼接字符串时也不一定是最优的,因为它其实是把每次Append进去的东西复制展开,因此内存占用是和目标字符串长度相关的。有时候,你拿一个字符串数组/List保留输入字符串,最后用自己写的Concat(string[] input, beginIndex, length)拼起来,此时额外的内存占用就是和字符串数量相关,就远小于目标字符串长度了。而这个临时字符串数组甚至都可以复用,最终效果便又是零(额外)分配了。当然,这种方法并不是没有值得讨论的地方。一是实际开发时,复用一个巨型的StringBuilder,每线程一个(ThreadStatic),这可能也够了,开发起来也更方便(效果相对略差)。二是用StringBuilder时,每次Append的字符串可能可以被立即回收,而用上边描述的方法会导致字符串被长时间引用而被升代(假如它们本身就会被其他地方引用着那么自然就没这方面问题了)。总之内存优化时很多时候就是围绕字符串来的,毕竟字符串代表的是一大块连续内存,而且太容易生成新字符串(Split,ToUpper,Substring等等),操作起来要么浪费要么麻烦。更有甚者是,它很容易/已经被滥用了,例如目标函数就是要接受一个字符串时,你除了生成一个新的就没其他办法了。用Span可以解决部分问题,但它一是太新用不上,二是也不能解决所有问题。收起全文

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值