首页
学习
活动
专区
圈层
工具
发布

为什么 idea 建议去掉 StringBuilder,使用“+”拼接字符串

说实话,刚看到 IDEA 提示我把StringBuilder换成+号拼接字符串的时候,我内心是拒绝的。毕竟我们这些“老兵”从小就被教育:字符串拼接要用StringBuilder,+性能差、内存浪费、GC 压力大... 那时候用+拼接可是要被师傅敲脑壳的。

结果现在 IDEA 突然改口让我用+,我真有点怀疑这货是不是喝多了

但冷静一想,IDEA 再怎么说也是个“智能”工具,它不会无缘无故做这种推荐吧?于是我决定撸起袖子,手动跑一下 benchmark,看看到底谁更快,谁是背锅侠。

我先写了两个方法,一个是用传统StringBuilder拼接,另一个是直接用+:

public String concatWithPlus(int count) {

  String result = "";

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

      result += i;

  }

  return result;

}

public String concatWithBuilder(int count) {

  StringBuilder sb = new StringBuilder();

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

      sb.append(i);

  }

  return sb.toString();

}

然后我用System.nanoTime()简单测了一下在拼接 10 万次的情况下,两者的耗时:

concatWithPlus: 33501ms

concatWithBuilder: 36128ms

嗯?这玩意儿还真的是+更快??这就离谱了啊!我赶紧反编译了一下 class 文件,用javap -c看了眼字节码,结果一看才明白,原来在普通的非循环拼接场景下,编译器其实已经偷偷帮我们把+转成了StringBuilder,就像这样:

new StringBuilder().append("abc").append("123").toString();

也就是说,在非循环的场景里,用+和用StringBuilder编译出来压根就是一回事,性能几乎没差,但代码却可以简洁不少。IDEA 的建议,其实是基于这种优化来的——也就是说,它没喝多,是我们还活在 JDK 1.4 的世界里 🤯

不过注意哈,这优化仅限于“编译期可确定的拼接”,像这样:

String s = "Hello" + name + ", welcome!";

只要name不是循环变量,基本都能被优化掉。

那问题来了——是不是以后我们都该扔掉StringBuilder,一律用+呢?当然不是!别急着把 StringBuilder 拉黑,它还是有一席之地的。

比如我把拼接操作放到循环里:

public String loopConcatWithPlus() {

  String result = "";

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

      result += i;

  }

  return result;

}

再对比一下StringBuilder版本:

public String loopConcatWithBuilder() {

  StringBuilder sb = new StringBuilder();

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

      sb.append(i);

  }

  return sb.toString();

}

这下结果就非常刺激了:

loopConcatWithPlus: 46285ms

loopConcatWithBuilder: 1317ms

注意,是将近35倍的性能差距,用 IDEA 自带的 profiler 都能看到内存分配飙升得像坐火箭一样。为啥差这么多?因为在循环里每次result += i都会创建一个新的StringBuilder实例,再转成字符串,根本没法复用,性能自然扑街

所以,在循环拼接里用+就是性能灾难,IDEA 可不会给你背这个锅

你以为这就完了?还有一类同学特别爱写这种模式:

String s = "";

for (...) {

  s += someFunction(i);

}

然后问题还不出在他们机器上,因为他们只测了 100 次,没感觉出差距,一上线就拉了全公司后腿... 这就是典型的“用法没错,场景不对”。

那总结下来说

如果你只是在方法里简单拼接几个字符串,比如拼个日志、URL、字段之类的,不用多想,直接用+,省事又清爽,编译器会替你兜底。

但如果你在循环里疯狂拼接,请一定用StringBuilder,不然性能就跟 PPT 一样“流畅”。

至于那些为了性能强行用StringBuilder的场景,如果不是循环,其实真没必要。写得复杂,还不如让编译器帮你干脏活。

哦对了,有同学说那是不是可以用StringJoiner,我只能说除非你真的需要定制 separator 或者 prefix/suffix,否则也挺鸡肋。说到底,性能和可读性之间的平衡,不是哪个 API 更先进,而是你是不是在对的场景用对了方法。

其实我们这一代人对+的偏见,说白了就是对编译器的不信任,但 Java 编译器这几年真的越来越聪明了,连 lambda、stream 的优化都能搞定,不该再活在“+拼接都是傻子”那种旧观念里了。

你说 IDEA 为啥老提示我们用+?人家不是为了节省你那点性能,而是为了提升代码可读性、降低维护成本。如果你每次为了拼接两三个字段都祭出StringBuilder,那不是高级程序员,是“仪式感程序员”。

所以最后的建议就是:别用惯性写代码,用脑子写。看到 IDEA 提示,先别怒删,要想一想,它背后的逻辑是不是比我们先入为主的印象更靠谱。

不过话说回来,现在 IDEA 连 switch 写错都能自动 refactor,有时候我还真挺担心:未来我们是不是都会变成“代码搬砖工”,一切全靠提示...

那你呢?你会相信 IDEA 的提示,还是坚持祖传的手艺?

最后,我为大家打造了一份deepseek的入门到精通教程,完全免费:https://www.songshuhezi.com/deepseek

  • 发表于:
  • 原文链接https://page.om.qq.com/page/Or87zm9hSmD0nLXTYGFGeGGg0
  • 腾讯「腾讯云开发者社区」是腾讯内容开放平台帐号(企鹅号)传播渠道之一,根据《腾讯内容开放平台服务协议》转载发布内容。
  • 如有侵权,请联系 cloudcommunity@tencent.com 删除。
领券