Java 字符串、StringBuffer和StringBuilder之间的性能和简单性权衡
您是否想过Java编程语言中这种变化的含义 String类被认为是一个不可变的类(这个决定是经过深思熟虑的)。但是字符串连接非常慢,我自己也做过基准测试。于是,字符串缓冲区诞生了。非常棒的课程,同步,速度非常快。但有些人对某些同步块的性能成本不满意,于是引入了StringBuilder 但是,当使用字符串连接不太多的对象时,类的不变性使它成为实现线程安全的一种非常自然的方式。当我们想要管理多个字符串时,我可以理解StringBuffer的用法。但是,这是我的第一个问题:Java 字符串、StringBuffer和StringBuilder之间的性能和简单性权衡,java,architecture,string,Java,Architecture,String,您是否想过Java编程语言中这种变化的含义 String类被认为是一个不可变的类(这个决定是经过深思熟虑的)。但是字符串连接非常慢,我自己也做过基准测试。于是,字符串缓冲区诞生了。非常棒的课程,同步,速度非常快。但有些人对某些同步块的性能成本不满意,于是引入了StringBuilder 但是,当使用字符串连接不太多的对象时,类的不变性使它成为实现线程安全的一种非常自然的方式。当我们想要管理多个字符串时,我可以理解StringBuffer的用法。但是,这是我的第一个问题: 例如,如果您有10个或更
(重要提示:我知道它们之间的区别;这是一个与平台架构和一些设计决策相关的问题。)StringBuffer在Java 1.0中;这不是对缓慢性或不变性的任何反应。它也不会比字符串连接更快或更好;事实上,Java编译器编译
String s1 = s2 + s3;
变成
String s1 = new StringBuilder(s2).append(s3).toString();
如果你不相信我的话,你可以自己用反汇编程序(比如javap-c)试试
“StringBuffer比串联快”指的是重复串联。在这种情况下,显式地创建yoir自己的StringBuffer并反复使用它比让编译器创建其中的许多要更好
正如您所说,Java 5中引入StringBuilder是出于性能原因。之所以有意义,是因为StringBuffer/Builder实际上从未在创建它们的方法之外共享过:它们99%的使用率与上述类似,它们是在上面创建的,用于将几个字符串附加在一起,然后被丢弃。仅是对“StringBuffers和线程”的评论备注:即使在多线程程序中,要跨多个线程构建字符串是非常罕见的。通常,每个线程都会有一些数据集并从中创建一个字符串,通常是通过将多个字符串连接在一起。然后,他们将把StringBuilder
转换为一个字符串,该字符串可以在线程之间安全地共享
我认为我从未见过由于线程之间共享StringBuilder
而导致的bug
我个人希望StringBuffer
不存在-它处于Java的“让我们同步一切”阶段,导致Vector
和Hashtable
几乎被Java2中未同步的ArrayList
和HashMap
类淘汰。只是花了一点时间,非同步等价的StringBuffer
才到达
所以基本上:
- 当您不想执行操作,并且希望确保其他操作不会执行时,请使用字符串
- 使用
执行操作,通常在短时间内执行StringBuilder
- 避免使用
,除非您真的、真的需要它——正如我所说,我不记得曾经见过这样的情况:当两者都可用时,我会使用StringBuffer
而不是StringBuffer
StringBuilder
StringBuilder(String str) {
super(str.length() + 16);
append(str);
}
因此,如果第二个字符串的长度超过16个字符,它将获得基础字符串的另一个副本
字符[]。很不酷
这可能是在32位操作系统上尝试将StringBuilder/Buffer和char[]安装到同一缓存线(在x86上)的副作用。。。但我不确定
至于调试时间等的评论,根据你的判断,我个人不记得e
package java.lang;
public class FastConcat {
public static String concat(String s1, String s2){
s1=String.valueOf(s1);//null checks
s2=String.valueOf(s2);
return s1.concat(s2);
}
public static String concat(String s1, String s2, String s3){
s1=String.valueOf(s1);//null checks
s2=String.valueOf(s2);
s3=String.valueOf(s3);
int len = s1.length()+s2.length()+s3.length();
char[] c = new char[len];
int idx=0;
idx = copy(s1, c, idx);
idx = copy(s2, c, idx);
idx = copy(s3, c, idx);
return newString(c);
}
public static String concat(String s1, String s2, String s3, String s4){
s1=String.valueOf(s1);//null checks
s2=String.valueOf(s2);
s3=String.valueOf(s3);
s4=String.valueOf(s4);
int len = s1.length()+s2.length()+s3.length()+s4.length();
char[] c = new char[len];
int idx=0;
idx = copy(s1, c, idx);
idx = copy(s2, c, idx);
idx = copy(s3, c, idx);
idx = copy(s4, c, idx);
return newString(c);
}
private static int copy(String s, char[] c, int idx){
s.getChars(c, idx);
return idx+s.length();
}
private static String newString(char[] c){
return new String(0, c.length, c);
//return String.copyValueOf(c);//if not in java.lang
}
}
private int testcount = 1000;
private int elementCount = 50000;
public void testStringBuilder() {
long total = 0;
int counter = 0;
while (counter++ < testcount) {
total += doStringBuilder();
}
float f = (total/testcount)/1000;
System.out.printf("StringBuilder build & output duration= %f µs%n%n", f);
}
private long doStringBuilder(){
long start = System.nanoTime();
StringBuilder buffer = new StringBuilder("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n");
buffer.append("<root>");
for (int i =0; i < elementCount; i++) {
buffer.append("<data/>");
}
buffer.append("</root>");
//System.out.println(buffer.toString());
output = buffer.toString();
long end = System.nanoTime();
return end - start;
}
public void testStringBuffer(){
long total = 0;
int counter = 0;
while (counter++ < testcount) {
total += doStringBuffer();
}
float f = (total/testcount)/1000;
System.out.printf("StringBuffer build & output duration= %f µs%n%n", f);
}
private long doStringBuffer(){
long start = System.nanoTime();
StringBuffer buffer = new StringBuffer("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n");
buffer.append("<root>");
for (int i =0; i < elementCount; i++) {
buffer.append("<data/>");
}
buffer.append("</root>");
//System.out.println(buffer.toString());
output = buffer.toString();
long end = System.nanoTime();
return end - start;
}
On OSX machine:
StringBuilder build & output duration= 1047.000000 µs
StringBuffer build & output duration= 1844.000000 µs
On Win7 machine:
StringBuilder build & output duration= 1869.000000 µs
StringBuffer build & output duration= 2122.000000 µs
StringBuffer build & output duration= 4282,000000 µs
StringBuilder build & output duration= 4226,000000 µs
StringBuffer build & output duration= 4439,000000 µs
StringBuilder build & output duration= 3961,000000 µs
StringBuffer build & output duration= 4801,000000 µs
StringBuilder build & output duration= 4210,000000 µs