使用 + 符号连接字符串

2024-04-21

今天我在读书Antonio 关于 toString() 性能的博客 https://antoniogoncalves.org/2015/06/30/who-cares-about-tostring-performance/还有一段话:

昨天曾经被认为是邪恶的东西(“不要用+连接字符串!!!”),已经变得很酷而且高效!今天,JVM 将 + 符号编译成字符串生成器(在大多数情况下)。所以,不要犹豫,使用它。

现在我很困惑,因为他说今天,JVM 将 + 符号编译成字符串生成器(在大多数情况下),但我以前从未听说过或见过(代码)这样​​的东西。

有人可以举个例子吗JVM 在哪里执行此操作以及在什么条件下发生?


The rule

“不要用 + 连接字符串!!!”

是错误的,因为它不完整,因此具有误导性。

规则是

不要用 + 连接字符串循环中

这条规则仍然有效。最初的规则从来不打算应用于循环之外!

一个简单的循环

String s = "";
for (int i = 0; i < 10000; i++) { s += i; }
System.out.println(s);

仍然比

StringBuilder sb = new StringBuilder();
for (int i = 0; i < 10000; i++) { sb.append(i); }
System.out.println(sb.toString());

因为 Java 编译器必须将第一个循环翻译为

String s = "";
for (int i = 0; i < 1000; i++) { s = new StringBuilder(s).append(i).toString(); }
System.out.println(s);

还有索赔

如今,JVM 将 + 符号编译为字符串生成器(在大多数情况下)。

至少是有误导性的,因为这个翻译已经用Java 1.0完成了(好吧,不是用StringBuilder而是用StringBuffer,因为StringBuilder只是在Java5中添加的)。


人们还可以争辩说,这一主张

如今,JVM 将 + 符号编译为字符串生成器(在大多数情况下)。

根本就是错误的,因为编译不是由 JVM 完成的。它是由 Java 编译器完成的。


对于问题:Java编译器什么时候使用StringBuilder.append()它什么时候使用其他机制?

Java编译器(版本1.8)的源代码包含两个地方,通过+运算符被处理。

  • 第一个地方是字符串常量折叠(http://grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/8u40-b25/com/sun/tools/javac/comp/ConstFold.java?av=f#314 http://grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/8u40-b25/com/sun/tools/javac/comp/ConstFold.java?av=f#314)。在这种情况下,编译器可以计算结果字符串并使用结果字符串。
  • 第二个地方是编译器创建赋值操作代码的地方(http://grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/8u40-b25/com/sun/tools/javac/jvm/Gen.java?av=f#2056 http://grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/8u40-b25/com/sun/tools/javac/jvm/Gen.java?av=f#2056)。在这种情况下,编译器总是发出代码来创建StringBuilder

结论是,对于 OpenJDK 的 Java 编译器(这意味着 Oracle 分发的编译器),这句话在多数情况下 means always。 (尽管 Java 9 可能会改变这种情况,或者可能是另一个 Java 编译器(例如 Eclipse 中包含的编译器)使用某种其他机制)。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

使用 + 符号连接字符串 的相关文章

随机推荐