Java 字符串、StringBuffer 和 StringBuilder
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/2971315/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
String, StringBuffer, and StringBuilder
提问by JavaUser
Please tell me a real time situation to compare String
, StringBuffer
, and StringBuilder
?
请告诉我要比较的实时情况String
,StringBuffer
, 和StringBuilder
?
采纳答案by bakkal
Mutability Difference:
可变性差异:
String
is immutable, if you try to alter their values, another object gets created, whereas StringBuffer
and StringBuilder
are mutableso they can change their values.
String
是不可变的,如果您尝试更改它们的值,则会创建另一个对象,而StringBuffer
和StringBuilder
是可变的,因此它们可以更改它们的值。
Thread-Safety Difference:
线程安全差异:
The difference between StringBuffer
and StringBuilder
is that StringBuffer
is thread-safe. So when the application needs to be run only in a single thread then it is better to use StringBuilder
. StringBuilder
is more efficient than StringBuffer
.
之间的区别StringBuffer
,并StringBuilder
是StringBuffer
是线程安全的。因此,当应用程序只需要在单个线程中运行时,最好使用StringBuilder
. StringBuilder
比 更有效率StringBuffer
。
Situations:
情况:
- If your string is not going to change use a String class because a
String
object is immutable. - If your string can change (example: lots of logic and operations in the construction of the string) and will only be accessed from a single thread, using a
StringBuilder
is good enough. - If your string can change, and will be accessed from multiple threads, use a
StringBuffer
becauseStringBuffer
is synchronous so you have thread-safety.
- 如果您的字符串不会更改,请使用 String 类,因为
String
对象是不可变的。 - 如果您的字符串可以更改(例如:字符串构造中的许多逻辑和操作)并且只能从单个线程访问,则使用 a
StringBuilder
就足够了。 - 如果您的字符串可以更改,并且可以从多个线程访问,请使用 a
StringBuffer
因为StringBuffer
是同步的,因此您具有线程安全性。
回答by OscarRyz
Do you mean, for concatenation?
你的意思是,为了串联?
Real world example: You want to create a new string out of many others.
现实世界示例: 您想从许多其他字符串中创建一个新字符串。
For instance to send a message:
例如发送消息:
String
细绳
String s = "Dear " + user.name + "<br>" +
" I saw your profile and got interested in you.<br>" +
" I'm " + user.age + "yrs. old too"
StringBuilder
字符串生成器
String s = new StringBuilder().append.("Dear ").append( user.name ).append( "<br>" )
.append(" I saw your profile and got interested in you.<br>")
.append(" I'm " ).append( user.age ).append( "yrs. old too")
.toString()
Or
或者
String s = new StringBuilder(100).appe..... etc. ...
// The difference is a size of 100 will be allocated upfront as fuzzy lollipop points out.
StringBuffer ( the syntax is exactly as with StringBuilder, the effects differ )
StringBuffer(语法与StringBuilder完全一样,效果不同)
About
关于
StringBuffer
vs. StringBuilder
StringBuffer
对比 StringBuilder
The former is synchonized and later is not.
前者是同步的,而后者不是。
So, if you invoke it several times in a single thread ( which is 90% of the cases ), StringBuilder
will run muchfaster because it won't stop to see if it owns the thread lock.
因此,如果您在单个线程中多次调用它(占 90% 的情况), StringBuilder
它将运行得更快,因为它不会停下来查看它是否拥有线程锁。
So, it is recommendable to use StringBuilder
( unless of course you have more than one thread accessing to it at the same time, which is rare )
因此,建议使用StringBuilder
(当然,除非您有多个线程同时访问它,这种情况很少见)
String
concatenation ( using the + operator) may be optimized by the compiler to use StringBuilder
underneath, so, it not longer something to worry about, in the elder days of Java, this was something that everyone says should be avoided at all cost, because every concatenation created a new String object. Modern compilers don't do this anymore, but still it is a good practice to use StringBuilder
instead just in case you use an "old" compiler.
String
连接(使用 + 运算符)可能会被编译器优化以在StringBuilder
下面使用,因此,不再需要担心,在 Java 的旧时代,这是每个人都说应该不惜一切代价避免的事情,因为每个连接创建了一个新的 String 对象。现代编译器不再这样做了,但StringBuilder
如果您使用“旧”编译器,使用它仍然是一个好习惯。
edit
编辑
Just for who is curious, this is what the compiler does for this class:
对于好奇的人来说,这就是编译器为这个类所做的:
class StringConcatenation {
int x;
String literal = "Value is" + x;
String builder = new StringBuilder().append("Value is").append(x).toString();
}
javap -c StringConcatenation
javap -c 字符串连接
Compiled from "StringConcatenation.java"
class StringConcatenation extends java.lang.Object{
int x;
java.lang.String literal;
java.lang.String builder;
StringConcatenation();
Code:
0: aload_0
1: invokespecial #1; //Method java/lang/Object."<init>":()V
4: aload_0
5: new #2; //class java/lang/StringBuilder
8: dup
9: invokespecial #3; //Method java/lang/StringBuilder."<init>":()V
12: ldc #4; //String Value is
14: invokevirtual #5; //Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
17: aload_0
18: getfield #6; //Field x:I
21: invokevirtual #7; //Method java/lang/StringBuilder.append:(I)Ljava/lang/StringBuilder;
24: invokevirtual #8; //Method java/lang/StringBuilder.toString:()Ljava/lang/String;
27: putfield #9; //Field literal:Ljava/lang/String;
30: aload_0
31: new #2; //class java/lang/StringBuilder
34: dup
35: invokespecial #3; //Method java/lang/StringBuilder."<init>":()V
38: ldc #4; //String Value is
40: invokevirtual #5; //Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
43: aload_0
44: getfield #6; //Field x:I
47: invokevirtual #7; //Method java/lang/StringBuilder.append:(I)Ljava/lang/StringBuilder;
50: invokevirtual #8; //Method java/lang/StringBuilder.toString:()Ljava/lang/String;
53: putfield #10; //Field builder:Ljava/lang/String;
56: return
}
Lines numbered 5 - 27 are for the String named "literal"
编号为 5 - 27 的行用于名为“literal”的字符串
Lines numbered 31-53 are for the String named "builder"
编号为 31-53 的行用于名为“builder”的字符串
Ther's no difference, exactly the samecode is executed for both strings.
疗法没有区别,完全一样的代码为两个字符串执行。
回答by Lars Andren
Also, StringBuffer
is thread-safe, which StringBuilder
is not.
此外,StringBuffer
是线程安全的,但StringBuilder
不是。
So in a real-time situation when different threads are accessing it, StringBuilder
could have an undeterministic result.
因此,在不同线程访问它的实时情况下,StringBuilder
可能会产生不确定的结果。
回答by Artefacto
- You use
String
when an immutable structure is appropriate; obtaining a new character sequence from aString
may carry an unacceptable performance penalty, either in CPU time or memory (obtaining substrings is CPU efficient because the data is not copied, but this means a potentially much larger amount of data may remain allocated). - You use
StringBuilder
when you need to create a mutable character sequence, usually to concatenate several character sequences together. - You use
StringBuffer
in the same circumstances you would useStringBuilder
, but when changes to the underlying string must be synchronized (because several threads are reading/modifyind the string buffer).
- 您可以使用
String
,当一个不变的结构是合适的; 从 a 中获取新的字符序列String
可能会带来不可接受的性能损失,无论是在 CPU 时间还是内存中(获取子字符串是 CPU 效率高的,因为数据没有被复制,但这意味着可能会有更多的数据被分配)。 - 您可以使用
StringBuilder
,当你需要创建一个可变的字符序列,通常是连接几个字符序列在一起。 - 您
StringBuffer
在与使用相同的情况下使用StringBuilder
,但是当对基础字符串的更改必须同步时(因为多个线程正在读取/修改字符串缓冲区)。
See an example here.
请参阅此处的示例。
回答by bakkal
The Basics:
基础知识:
String
is an immutable class, it can't be changed.
StringBuilder
is a mutable class that can be appended to, characters replaced or removed and ultimately converted to a String
StringBuffer
is the original synchronized version of StringBuilder
String
是一个不可变的类,它不能被改变。
StringBuilder
是一个可变类,可以附加、替换或删除字符并最终转换为 aString
StringBuffer
是原始同步版本StringBuilder
You should prefer StringBuilder
in all cases where you have only a single thread accessing your object.
StringBuilder
在只有一个线程访问您的对象的所有情况下,您应该更喜欢。
The Details:
细节:
Also note that StringBuilder/Buffers
aren't magic, they just use an Array as a backing object and that Array has to be re-allocated when ever it gets full. Be sure and create your StringBuilder/Buffer
objects large enough originally where they don't have to be constantly re-sized every time .append()
gets called.
还要注意,StringBuilder/Buffers
这不是魔术,它们只是使用一个 Array 作为支持对象,并且该 Array 必须在它变满时重新分配。一定要创建StringBuilder/Buffer
足够大的对象,这样它们就不必每次.append()
被调用时都不断地重新调整大小。
The re-sizing can get very degenerate. It basically re-sizes the backing Array to 2 times its current size every time it needs to be expanded. This can result in large amounts of RAM getting allocated and not used when StringBuilder/Buffer
classes start to grow large.
重新调整大小可能会变得非常退化。每次需要扩展时,它基本上都会将支持数组的大小重新调整为其当前大小的 2 倍。当StringBuilder/Buffer
类开始变大时,这可能导致大量 RAM 被分配而未被使用。
In Java String x = "A" + "B";
uses a StringBuilder
behind the scenes. So for simple cases there is no benefit of declaring your own. But if you are building String
objects that are large, say less than 4k, then declaring StringBuilder sb = StringBuilder(4096);
is much more efficient than concatenation or using the default constructorwhich is only 16 characters. If your String
is going to be less than 10k then initialize it with the constructor to 10k to be safe. But if it is initialize to 10k then you write 1 character more than 10k, it will get re-allocated and copied to a 20k array. So initializing high is better than to low.
在 Java 中String x = "A" + "B";
使用了一个StringBuilder
幕后。因此,对于简单的情况,声明您自己的情况没有任何好处。但是,如果您要构建的String
对象很大,比如小于 4k,那么声明StringBuilder sb = StringBuilder(4096);
比串联或使用只有 16 个字符的默认构造函数更有效。如果您String
将小于 10k,则使用构造函数将其初始化为 10k 以确保安全。但是如果它被初始化为 10k,那么你写了 1 个超过 10k 的字符,它将被重新分配并复制到一个 20k 的数组中。所以初始化高比低好。
In the auto re-size case, at the 17th character the backing Array gets re-allocated and copied to 32 characters, at the 33th character this happens again and you get to re-allocated and copy the Array into 64 characters. You can see how this degenerates to lotsof re-allocations and copies which is what you really are trying to avoid using StringBuilder/Buffer
in the first place.
在自动调整大小的情况下,在第 17 个字符时,支持数组被重新分配并复制到 32 个字符,在第 33 个字符时再次发生这种情况,您可以重新分配并将数组复制到 64 个字符。您可以看到这如何退化为大量的重新分配和副本,而这正是您StringBuilder/Buffer
首先要避免使用的。
This is from the JDK 6 Source code for AbstractStringBuilder
这是来自 AbstractStringBuilder 的 JDK 6 源代码
void expandCapacity(int minimumCapacity) {
int newCapacity = (value.length + 1) * 2;
if (newCapacity < 0) {
newCapacity = Integer.MAX_VALUE;
} else if (minimumCapacity > newCapacity) {
newCapacity = minimumCapacity;
}
value = Arrays.copyOf(value, newCapacity);
}
A best practice is to initialize the StringBuilder/Buffer
a little bit larger than you think you are going to need if you don't know right off hand how big the String
will be but you can guess. One allocation of slightly more memory than you need is going to be better than lots of re-allocations and copies.
最佳做法是将 初始化StringBuilder/Buffer
比您认为需要的大一点,如果您不知道String
将有多大,但您可以猜测。一次分配比您需要的稍多的内存将比大量重新分配和复制要好。
Also beware of initializing a StringBuilder/Buffer
with a String
as that will only allocated the size of the String + 16 characters, which in most cases will just start the degenerate re-allocation and copy cycle that you are trying to avoid. The following is straight from the Java 6 source code.
还要注意StringBuilder/Buffer
用 a初始化 a ,String
因为它只会分配 String + 16 个字符的大小,在大多数情况下,这只会启动您试图避免的退化重新分配和复制周期。以下内容直接来自 Java 6 源代码。
public StringBuilder(String str) {
super(str.length() + 16);
append(str);
}
If you by chance do end up with an instance of StringBuilder/Buffer
that you didn't create and can't control the constructor that is called, there is a way to avoid the degenerate re-allocate and copy behavior. Call .ensureCapacity()
with the size you want to ensure your resulting String
will fit into.
如果您碰巧得到了一个StringBuilder/Buffer
不是您创建的实例并且无法控制被调用的构造函数,则有一种方法可以避免退化的重新分配和复制行为。.ensureCapacity()
以您想要的尺寸致电以确保您的结果String
适合。
The Alternatives:
替代方案:
Just as a note, if you are doing really heavyString
building and manipulation, there is a much more performance oriented alternative called Ropes.
请注意,如果您正在进行非常繁重的String
构建和操作,则有一种更加注重性能的替代方案,称为Ropes。
Another alternative, is to create a StringList
implemenation by sub-classing ArrayList<String>
, and adding counters to track the number of characters on every .append()
and other mutation operations of the list, then override .toString()
to create a StringBuilder
of the exact size you need and loop through the list and build the output, you can even make that StringBuilder
an instance variable and 'cache' the results of .toString()
and only have to re-generate it when something changes.
另一种选择是StringList
通过 sub-classing创建一个实现ArrayList<String>
,并添加计数器来跟踪.append()
列表的每个和其他变异操作上的字符数,然后覆盖.toString()
以创建StringBuilder
您需要的确切大小并循环遍历列表并构建输出,您甚至可以将StringBuilder
其.toString()
设为实例变量并“缓存”结果,并且只有在发生变化时才需要重新生成它。
Also don't forget about String.format()
when building fixed formatted output, which can be optimized by the compiler as they make it better.
也不要忘记String.format()
在构建固定格式的输出时,编译器可以对其进行优化,因为它们会变得更好。
回答by Jesper
Note that if you are using Java 5 or newer, you should use StringBuilder
instead of StringBuffer
. From the API documentation:
请注意,如果您使用的是 Java 5 或更新版本,则应使用StringBuilder
代替StringBuffer
。来自 API 文档:
As of release JDK 5, this class has been supplemented with an equivalent class designed for use by a single thread,
StringBuilder
. TheStringBuilder
class should generally be used in preference to this one, as it supports all of the same operations but it is faster, as it performs no synchronization.
从 JDK 5 版本开始,这个类已经补充了一个设计用于单线程的等效类,
StringBuilder
. 所述StringBuilder
类通常应优先使用这一个,因为它支持所有相同的操作,但它是快的,因为它不执行同步。
In practice, you will almost never use this from multiple threads at the same time, so the synchronization that StringBuffer
does is almost always unnecessary overhead.
在实践中,您几乎不会同时在多个线程中使用它,因此这样做的同步StringBuffer
几乎总是不必要的开销。
回答by fredoverflow
Personally, I don't think there is any real world use for StringBuffer
. When would I ever want to communicate between multiple threads by manipulating a character sequence? That doesn't sound useful at all, but maybe I have yet to see the light :)
就个人而言,我认为StringBuffer
. 我什么时候想要通过操作字符序列在多个线程之间进行通信?这听起来一点用处都没有,但也许我还没有看到曙光:)
回答by rajat ghai
In java, Stringis immutable. Being immutable we mean that once a String is created, we can not change its value. StringBufferis mutable. Once a StringBuffer object is created, we just append the content to the value of object instead of creating a new object. StringBuilderis similar to StringBuffer but it is not thread-safe. Methods of StingBuilder are not synchronized but in comparison to other Strings, the Stringbuilder runs fastest. You can learn difference between String, StringBuilder and StringBufferby implementing them.
在java中,String是不可变的。不可变意味着一旦创建了一个字符串,我们就不能改变它的值。 StringBuffer是可变的。一旦创建了 StringBuffer 对象,我们只需将内容附加到 object 的值中,而不是创建一个新对象。 StringBuilder类似于 StringBuffer 但它不是线程安全的。StingBuilder 的方法不同步,但与其他字符串相比,Stringbuilder 运行速度最快。您可以通过实现它们来了解String、StringBuilder 和 StringBuffer之间的区别。
回答by Hitesh Garg
Difference between String and the other two classes is that String is immutable and the other two are mutable classes.
String 和另外两个类的区别在于 String 是不可变的,另外两个是可变类。
But why we have two classes for same purpose?
但是为什么我们有两个类用于相同的目的?
Reason is that StringBuffer
is Thread safe and StringBuilder
is not.
StringBuilder
is a new class on StringBuffer Api
and it was introduced in JDK5
and is always recommended if you are working in a Single threaded environment as it is much Faster
原因是这StringBuffer
是线程安全的,StringBuilder
而不是。
StringBuilder
是一个新类StringBuffer Api
,它被引入JDK5
并且如果您在单线程环境中工作,总是推荐它,因为它很多Faster
For complete Details you can read http://www.codingeek.com/java/stringbuilder-and-stringbuffer-a-way-to-create-mutable-strings-in-java/
有关完整的详细信息,您可以阅读http://www.codingeek.com/java/stringbuilder-and-stringbuffer-a-way-to-create-mutable-strings-in-java/
回答by Abhijit Maity
---------------------------------------------------------------------------------- String StringBuffer StringBuilder ---------------------------------------------------------------------------------- Storage Area | Constant String Pool Heap Heap Modifiable | No (immutable) Yes( mutable ) Yes( mutable ) Thread Safe | Yes Yes No Performance | Fast Very slow Fast ----------------------------------------------------------------------------------