Java 赋值上的字符串连接有效吗?
我知道使用“+”连接运算符来构建字符串效率很低,这就是为什么建议使用StringBuilder类的原因,但我想知道这种模式是否也很低效率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;
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也可以很好地处理变量,对吗。其他一些优化可能不起作用,但我们讨论的是什么样的优化?问题陈述中没有“优化到文字”。编译器将优化字符串连接到