使用+符号进行字符串连接

Meh*_*lik 3 java performance stringbuilder jvm tostring

今天我正在阅读Antonio的博客关于toString()的表现,还有一段:

曾经被认为是邪恶的昨天("不要用+ !!!连接字符串"),已经变得很酷和高效!今天,JVM将+符号编译为字符串构建器(在大多数情况下).所以,不要犹豫,使用它.

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

有人可以举例说明JVM是做什么的,以及它在什么条件下发生

Tho*_*ger 13

规则

"不要用+ !!!连接字符串"

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

规则是

不要在循环中将字符串与+连接

这条规则仍然有效.最初的规则从未打算在循环之外应用!

一个简单的循环

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

仍然比...慢得多

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

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

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

索赔

今天,JVM将+符号编译为字符串构建器(在大多数情况下).

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


人们也可以争辩说这个说法

今天,JVM将+符号编译为字符串构建器(在大多数情况下).

是完全错误的,因为编译不是由JVM完成的.它由Java编译器完成.


对于这个问题:Java编译器StringBuilder.append()何时使用以及何时使用其他机制?

Java编译器(版本1.8)的源代码包含两个+处理字符串通过运算符进行处理的地方.

结论是,对于来自OpenJDK的Java编译器(这意味着由Oracle分发的编译器),在大多数情况下,该短语总是意味着.(虽然这可能会随着Java 9而改变,或者可能是另一个像Eclipse中包含的Java编译器使用其他机制的Java编译器).

  • @MehrajMalik我目前只知道字符串连接的情况:两个操作数都是常量字符串(然后编译器用字符串文字替换它)或者至少一个操作数不是常量字符串(然后编译器使用StringBuilder) .但我会尝试查看其他情况下的java编译器. (2认同)

Eug*_*ene 5

霍尔格是正确的,他的评论在Java中,9 +为字符串连接将会从改变StringBuilder由JRE选择的策略通过invokedynamicString concatenationjdk-9 有6种可能的策略:

  private enum Strategy {
    /**
     * Bytecode generator, calling into {@link java.lang.StringBuilder}.
     */
    BC_SB,

    /**
     * Bytecode generator, calling into {@link java.lang.StringBuilder};
     * but trying to estimate the required storage.
     */
    BC_SB_SIZED,

    /**
     * Bytecode generator, calling into {@link java.lang.StringBuilder};
     * but computing the required storage exactly.
     */
    BC_SB_SIZED_EXACT,

    /**
     * MethodHandle-based generator, that in the end calls into {@link java.lang.StringBuilder}.
     * This strategy also tries to estimate the required storage.
     */
    MH_SB_SIZED,

    /**
     * MethodHandle-based generator, that in the end calls into {@link java.lang.StringBuilder}.
     * This strategy also estimate the required storage exactly.
     */
    MH_SB_SIZED_EXACT,

    /**
     * MethodHandle-based generator, that constructs its own byte[] array from
     * the arguments. It computes the required storage exactly.
     */
    MH_INLINE_SIZED_EXACT
}
Run Code Online (Sandbox Code Playgroud)

并且默认的是不使用StringBuilder,它是MH_INLINE_SIZED_EXACT。实际上,实现的工作原理非常疯狂,并且正在高度优化。

因此,据我所知,那里没有任何建议是不好的。顺便说一句,这是Aleksey Shipilev由jdk所做的主要努力。他还对jdk-9中的String内部进行了很大的更改,因为它们现在由a byte[]代替char[]。之所以需ISO_LATIN_1要这样做,是因为可以将字符串编码为单个字节(一个字符-一个字节),从而减少了很多空间。