Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/320.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_String_Java 8_String Concatenation - Fatal编程技术网

Java 赋值上的字符串连接有效吗?

Java 赋值上的字符串连接有效吗?,java,string,java-8,string-concatenation,Java,String,Java 8,String Concatenation,我知道使用“+”连接运算符来构建字符串效率很低,这就是为什么建议使用StringBuilder类的原因,但我想知道这种模式是否也很低效率 String some = a + "\t" + b + "\t" + c + "\t" + d + "\t" + e; 我想在这里,编译器会优化赋值吗?编译器将内联此特定示例: String a = "a"; String b = "bb"; String c = "ccc"; String some = a + "\t" + b + "\t" + c;

我知道使用“+”连接运算符来构建字符串效率很低,这就是为什么建议使用StringBuilder类的原因,但我想知道这种模式是否也很低效率

String some = a + "\t" + b + "\t" + c + "\t" + d + "\t" + e;

我想在这里,编译器会优化赋值吗?

编译器将内联此特定示例:

String a = "a";
String b = "bb";
String c = "ccc";
String some = a + "\t" + b + "\t" + c;
Java9+将使用内联技术使其高效。根据
javap-v
输出:

Code:
  stack=3, locals=5, args_size=1
     0: ldc           #2                  // String a
     2: astore_1
     3: ldc           #3                  // String bb
     5: astore_2
     6: ldc           #4                  // String ccc
     8: astore_3
     9: aload_1
    10: aload_2
    11: aload_3
    12: invokedynamic #5,  0              // InvokeDynamic #0:makeConcatWithConstants:(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;
    17: astore        4
    19: return
但是,如果
a
b
c
是编译时常数,编译器将进一步优化代码:

final String a = "a";
final String b = "bb";
final String c = "ccc";
String some = a + "\t" + b + "\t" + c;
某些
将加载一个常量值:

Code:
  stack=1, locals=5, args_size=1
     0: ldc           #2                  // String a
     2: astore_1
     3: ldc           #3                  // String bb
     5: astore_2
     6: ldc           #4                  // String ccc
     8: astore_3
     9: ldc           #5                  // String a\tbb\tccc
    11: astore        4
    13: return

在其他情况下,例如
for
循环,编译器可能无法生成优化的代码,因此
StringBuilder
可能会更快。

在一般情况下,使用
+
StringBuilder
进行字符串连接是绝对正确和有效的。但是在不同的情况下,使用
+
进行连接比使用
StringBuilder
效率低

String some = a + "\t" + b + "\t" + c + "\t" + d + "\t" + e;
字符串连接不在循环中-有效!!! 这会带来很好的性能,因为JVM使用
StringBuilder
进行转换

String some = a + "\t" + b + "\t" + c + "\t" + d + "\t" + e;
这是可以的,因为JVM在内部将此代码更改为以下代码:

String some = new StringBuilder().append(a).append('\t').append(c).append('\t')
                                 .append(d).append('\t').append(e).toString();
p.S.
StringBuilder
具有内部缓冲区
char[]
。如果您知道结果字符串的长度,那么最好在开始时保留整个缓冲区。例如,如果最终字符串最多为1024个字符,则您可以执行
新建StringBuilder(1024)

循环中的字符串连接-无效!!! 这会导致性能下降,因为JVM无法使用一个
StringBuilder
进行while循环,如下所示:

StringBuilder buf = new StringBuilder();

for (int i = 0; i < 10; i++)
    buf.append(a).append('\t').append(c).append('\t')
       .append(d).append('\t').append(e).append('t');

String some = buf.toString();
String some = "";

for (int i = 0; i < 10; i++) {
    some = new StringBuilder(some).append(a).append('\t').append(c).append('\t')
                               .append(d).append('\t').append(e).append('t');
}
StringBuilder buf=new StringBuilder();
对于(int i=0;i<10;i++)
buf.append(a).append('\t').append(c).append('\t'))
.append(d).append('\t')。append(e).append('t');
字符串some=buf.toString();
但是JVM仍然能够优化每个循环迭代中的所有连接;像这样:

StringBuilder buf = new StringBuilder();

for (int i = 0; i < 10; i++)
    buf.append(a).append('\t').append(c).append('\t')
       .append(d).append('\t').append(e).append('t');

String some = buf.toString();
String some = "";

for (int i = 0; i < 10; i++) {
    some = new StringBuilder(some).append(a).append('\t').append(c).append('\t')
                               .append(d).append('\t').append(e).append('t');
}
String some=”“;
对于(int i=0;i<10;i++){
some=新的StringBuilder(some).append(a).append('\t').append(c).append('\t'))
.append(d).append('\t')。append(e).append('t');
}

正如您所看到的,在循环中使用字符串连接有一些缺点。

您的前提“使用“+”连接运算符构建字符串效率非常低”,这是不正确的。首先,字符串连接本身不是一个廉价的操作,因为它意味着创建一个包含所有连接字符串的新字符串,因此需要复制字符内容。但不管你怎么做,这总是适用的

当你使用
+
操作符时,你在告诉你想做什么,而没有说怎么做。甚至Java语言规范也不需要特定的实现策略,只是编译时常量的串联必须在编译时完成。因此,对于编译时常量,
+
运算符是最有效的解决方案

实际上,从Java 5到Java 8的所有常用编译器都在后台使用
StringBuilder
生成代码(在Java 5之前,他们使用
StringBuffer
)。这适用于像您这样的语句,因此将其替换为手动
StringBuilder
使用不会有多大好处。通过提供合理的初始容量,您可以比典型的编译器生成的代码稍微好一点,但仅此而已

从Java 9开始,编译器生成一条
invokedynamic
指令,允许运行时提供执行串联的实际代码。这可能是一个类似于过去使用的
StringBuilder
代码,但也可能是完全不同的代码。最值得注意的是,运行时提供的代码可以访问特定于实现的功能,而应用程序代码不能访问这些功能。现在,通过
+
进行字符串连接比基于
StringBuilder
的代码更快

由于这仅适用于单个串联表达式,因此当使用多个语句甚至循环执行字符串构造时,在整个构造过程中一致使用
StringBuilder
可能比多个串联操作更快。然而,由于代码在优化环境中运行,JVM可以识别其中的一些模式,甚至不能肯定这一点

这是记住旧规则的时候了,只有在性能出现实际问题时才尝试优化性能。并始终使用公正的测量工具验证尝试的优化是否真正提高了性能。关于性能优化技巧,有很多广为流传的神话,错误的或过时的


除非您有重复的部分,并且希望减小类文件的大小

,这很好。编译器可以优化它。另请看,我会谨慎地说@khelwood,我们不知道
a
/
b
/etc都是常量(这是它将优化为文本的地方)。否则,我们在这里可能看到的唯一优化就是编译器完全独立地将串联与
StringBuilder
交换。在一个循环中,可能会有很多不必要的StringBuilder被解析。这取决于a、b、c、d是否是常量。。。。如果编译器能够解析值(在编译时)为什么它们必须是常量,那么它将对其进行优化?为什么正态变量会有问题?StringBuilder也可以很好地处理变量,对吗。其他一些优化可能不起作用,但我们讨论的是什么样的优化?问题陈述中没有“优化到文字”。编译器将优化字符串连接到