Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/351.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/performance/5.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/gwt/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 字符串与+;符号_Java_Performance_Jvm_Tostring_Stringbuilder - Fatal编程技术网

Java 字符串与+;符号

Java 字符串与+;符号,java,performance,jvm,tostring,stringbuilder,Java,Performance,Jvm,Tostring,Stringbuilder,今天我在读,有一段: 昨天曾经被认为是邪恶的东西(“不要将字符串与+!!!”连接起来”)已经变得酷而高效了!今天JVM将+符号编译成一个字符串生成器(在大多数情况下)。因此,不要犹豫,使用它吧 现在我很困惑,因为他说今天JVM将+符号编译成一个字符串生成器(在大多数情况下),但我以前从未听说过或见过这样的(代码) 有人能举例说明JVM在哪里做这件事,以及在什么情况下做这件事吗 “不要将字符串连接到+!!!” 是错误的,因为它是不完整的,因此具有误导性 规则是 不要在循环中将字符串与+连接起来 这

今天我在读,有一段:

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

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

有人能举例说明JVM在哪里做这件事,以及在什么情况下做这件事吗

“不要将字符串连接到+!!!”

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

规则是

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

这条规则仍然有效。原来的规则从来就不应该应用于循环之外

简单的循环

String s = "";
for (int i = 0; i < 10000; i++) { s += i; }
System.out.println(s);
String s=”“;
对于(inti=0;i<10000;i++){s+=i;}
系统输出打印项次;
仍然比以前慢很多

StringBuilder sb = new StringBuilder();
for (int i = 0; i < 10000; i++) { sb.append(i); }
System.out.println(sb.toString());
StringBuilder sb=新建StringBuilder();
对于(inti=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);
String s=”“;
对于(int i=0;i<1000;i++){s=new StringBuilder(s).append(i).toString();}
系统输出打印项次;
还有索赔

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

至少有误导性,因为这个转换已经用Java1.0完成了(好的,不是用StringBuilder,而是用StringBuffer,因为StringBuilder只是用Java5添加的)


人们还可以说,这种说法

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

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


对于以下问题:Java编译器何时使用
StringBuilder.append()
,何时使用其他机制

Java编译器(1.8版)的源代码包含两个地方,在这两个地方通过
+
操作符处理字符串连接

  • 首先是字符串常量折叠()。在这种情况下,编译器可以计算结果字符串并处理结果字符串
  • 第二个地方是编译器为赋值操作()创建代码的地方。在这种情况下,编译器总是发出代码来创建
    StringBuilder

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

当您使用+运算符连接字符串时,编译器会将连接代码转换为使用
StringBuffer
以获得更好的性能。为了提高性能
StringBuffer
是更好的选择

使用+运算符连接两个字符串的最快方法

String str = "Java";
str = str + "Tutorial";
编译器将此代码翻译为:

String s1 = "Java";
StringBuffer sb = new StringBuffer(s1);
sb.append("Tutorial");
s1 = sb.toString();
因此,最好使用
StringBuffer
String.format
进行连接

使用
String.format

String s = String.format("%s %s", "Java", "Tutorial");

这种形式的声明完全是错误的,它符合这样一种情况:链接的博客继续写废话,就像你必须用
对象包装引用。toString(…)
来处理
null
,例如
“att1=”+“Objects.toString(att1)+”\'
,而不仅仅是
“att1=”“+att1+'\''
。没有必要这样做,显然,作者从未重新检查这些声明

JVM不负责编译
+
操作符,因为该操作符只是一个源代码工件。负责编译的是编译器,例如
javac
,虽然对编译后的表单没有任何保证,但以下方面鼓励编译器使用生成器:

实现可以选择在一个步骤中执行转换和连接,以避免创建然后丢弃中间字符串对象。为了提高重复字符串连接的性能,Java编译器可以使用StringBuffer类或类似技术来减少cre的中间字符串对象数通过对表达式的求值来定义

请注意,即使编译器不执行此优化,字节码级别上仍然没有
+
运算符,因此编译器必须选择JVM理解的操作,例如使用
String.concat
,如果您只是concat,这可能比使用
StringBuilder
更快恰好启用两个字符串

即使假设字符串连接的编译策略最差(仍在规范范围内),说永远不要将字符串与
+
连接是错误的,因为在定义编译时常量时,使用
+
是唯一的选择,当然,编译时常量通常比在运行时使用
StringBuilder
更有效

在实践中,应用于非常量字符串的
+
运算符在Java 5之前被编译成
StringBuffer
用法,在Java 5到Java 8中被编译成
StringBuilder
用法。当编译的代码与手动使用
StringBuffer
对应的
StringBuilder
相同时,就不会有性能差异

十多年前,向Java 5的过渡是第一次,通过
+
进行字符串连接明显优于手动
StringBuffer
使用,因为只需重新编译连接代码
  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
}