字符串、StringBuffer 和 StringBuilder
比较 String
、StringBuffer
和 StringBuilder
的实时情况是什么?
What is some real time situation to compare String
, StringBuffer
, and StringBuilder
?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(12)
可变性差异:
字符串
是不可变的。如果您尝试更改它们的值,则会创建另一个对象,而StringBuffer
和StringBuilder
是可变的,因此它们可以更改其值。线程安全差异:
StringBuffer
和StringBuilder
之间的差异在于StringBuffer
是线程安全的。因此,当应用程序只需要在单线程中运行时,最好使用StringBuilder
。StringBuilder
比StringBuffer
更高效。情况:
String
对象是不可变的。StringBuilder
就足够了。Mutability Difference:
String
is immutable. If you try to alter their values, another object gets created, whereasStringBuffer
andStringBuilder
are mutable, so they can change their values.Thread-Safety Difference:
The difference between
StringBuffer
andStringBuilder
is thatStringBuffer
is threadsafe. So when the application needs to be run only in a single thread, then it is better to useStringBuilder
.StringBuilder
is more efficient thanStringBuffer
.Situations:
String
object is immutable.StringBuilder
is good enough.StringBuffer
becauseStringBuffer
is synchronous so you have thread-safety.String
当不可变结构合适时;从String
获取新的字符序列可能会带来不可接受的性能损失,无论是 CPU 时间还是内存(获取子字符串是 CPU 高效的,因为数据没有被复制,但这意味着可能需要大量的数据)数据可能仍保持分配状态)。StringBuilder
当您需要创建可变字符序列时,通常将多个字符序列连接在一起。StringBuffer
在相同的情况下,您将使用StringBuilder
,但是当对底层字符串的更改必须同步时(因为多个线程正在读取/修改字符串缓冲区)。请参阅此处的示例。
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).StringBuilder
when you need to create a mutable character sequence, usually to concatenate several character sequences together.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).See an example here.
基础知识:
String
是一个不可变类;它无法改变。StringBuilder
是一个可变类,可以附加、替换或删除字符并最终转换为String
StringBuffer
是StringBuilder
的原始同步版本。在只有一个线程访问对象的所有情况下,您应该更喜欢
StringBuilder
。详细信息:
另请注意,
StringBuilder/Buffers
并不是魔法。他们只是使用数组作为支持对象,并且每当数组变满时就必须重新分配该数组。确保创建的StringBuilder/Buffer
对象最初足够大,这样就不必在每次调用.append()
时不断调整它们的大小。调整大小可能会变得非常退化。每次需要扩展时,它基本上都会将支持数组的大小调整为其当前大小的两倍。当 StringBuilder/Buffer 类开始变大时,这可能会导致大量 RAM 被分配但未被使用。
在 Java 中,
String x = "A" + "B";
在幕后使用StringBuilder
。因此,对于简单的情况,声明自己的情况没有任何好处。但是,如果您要构建很大的String
对象,例如小于 4k,则声明StringBuilder sb = StringBuilder(4096);
比串联或使用 < a href="http://docs.oracle.com/javase/8/docs/api/java/lang/StringBuilder.html#StringBuilder--" rel="nofollow noreferrer">默认构造函数 16 个字符。如果您的String
将小于 10k,那么为了安全起见,请使用构造函数将其初始化为 10k。但如果它初始化为 10k,那么您写入的字符超过 10k,它将被重新分配并复制到 20k 数组。所以初始化高比初始化低好。在自动调整大小的情况下,在第 17 个字符处,支持数组被重新分配并复制到 32 个字符,在第 33 个字符处,这种情况再次发生,您需要重新分配数组并将其复制到 64 个字符。您可以看到这如何退化为大量重新分配和复制,这正是您首先要避免使用
StringBuilder/Buffer
的情况。这是来自 AbstractStringBuilder 的 JDK 6 源代码:
如果您不知道如何立即初始化,则最佳实践是初始化
StringBuilder/Buffer
,其大小比您认为需要的大一点。String
将会很大,但你可以猜到。一次分配比您需要的稍多的内存将比大量重新分配和复制更好。还要注意用
String
初始化StringBuilder/Buffer
,因为这只会分配 String + 16 个字符的大小,在大多数情况下,这只会开始退化重新分配,您试图避免的复制周期。以下直接来自 Java 6 源代码。如果您偶然得到了一个不是您创建的 StringBuilder/Buffer 实例,并且无法控制所调用的构造函数,则有一种方法可以避免退化的重新分配和复制行为。调用
.ensureCapacity( )
以及您想要确保生成的String
适合的大小。替代方案:
请注意,如果您确实进行繁重
字符串
构建和操作,那么有一个更加注重性能的替代方案,称为绳索。另一种选择是通过子类化
ArrayList
来创建StringList
实现,并添加计数器来跟踪每个.append()
上的字符数。 code> 和列表的其他突变操作,然后重写.toString()
以创建所需大小的StringBuilder
并循环列表并构建输出,您甚至可以将StringBuilder
设为实例变量并“缓存”.toString()
的结果,并且只需在发生更改时重新生成它。另外,在构建固定格式输出时,不要忘记 String.format() ,编译器可以对其进行优化,使其变得更好。
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 aString
StringBuffer
is the original synchronized version ofStringBuilder
You should prefer
StringBuilder
in all cases where you have only a single thread accessing your object.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 reallocated whenever it gets full. Be sure and create yourStringBuilder/Buffer
objects large enough originally where they don't have to be constantly resized every time.append()
gets called.The resizing can get very degenerate. It basically resizes the backing Array to two 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.In Java,
String x = "A" + "B";
uses aStringBuilder
behind the scenes. So for simple cases there isn't any benefit of declaring your own. But if you are buildingString
objects that are large, say less than 4k, then declaringStringBuilder sb = StringBuilder(4096);
is much more efficient than concatenation or using the default constructor which is only 16 characters. If yourString
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 one character more than 10k, it will get reallocated and copied to a 20k array. So initializing high is better than to low.In the auto resize case, at the 17th character the backing Array gets reallocated and copied to 32 characters, at the 33th character this happens again and you get to reallocated and copy the Array into 64 characters. You can see how this degenerates to lots of re-allocations and copies which is what you really are trying to avoid using
StringBuilder/Buffer
in the first place.This is from the JDK 6 source code for AbstractStringBuilder:
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 theString
will be, but you can guess. One allocation of slightly more memory than you need is going to be better than lots of reallocations and copies.Also beware of initializing a
StringBuilder/Buffer
with aString
as that will only allocated the size of the String + 16 characters, which in most cases will just start the degenerate reallocation and copy cycle that you are trying to avoid. The following is straight from the Java 6 source code.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 reallocate and copy behavior. Call.ensureCapacity()
with the size you want to ensure your resultingString
will fit into.The Alternatives:
Just as a note, if you are doing really heavy
String
building and manipulation, there is a much more performance-oriented alternative called Ropes.Another alternative, is to create a
StringList
implementation by subclassingArrayList<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 aStringBuilder
of the exact size you need and loop through the list and build the output, you can even make thatStringBuilder
an instance variable and 'cache' the results of.toString()
and only have to regenerate it when something changes.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
版本:StringBuilder
版本:或
StringBuffer
版本看起来像StringBuilder
但效果有所不同。关于
StringBuffer
与StringBuilder
前者是同步的,后者不是。
因此,如果您在单个线程中多次调用它(这是 90% 的情况),
StringBuilder
的运行速度将快得多,因为它不会停下来查看如果它拥有线程锁。因此,建议使用
StringBuilder
(当然,除非您有多个线程同时访问它,但这种情况很少见)。String
连接(使用 + 运算符)可能会被编译器优化以在下面使用StringBuilder
,因此,不再需要担心。在 Java 的早期,每个人都说应该不惜一切代价避免这种情况,因为每次连接都会创建一个新的 String 对象。现代编译器不再这样做,但使用 StringBuilder 仍然是一个很好的做法,以防万一您使用“旧”编译器。对于那些好奇的人来说,这就是编译器对此类所做的操作:
javap -c StringConcatenation
输出:
第 5 - 27 行用于名为“literal”的字符串
第 31-53 行用于名为“builder”的字符串。
没有任何区别;对两个字符串执行完全相同的代码。
You may mean for concatenation.
Real-world example: You want to create a new string out of many others.
For instance, to send a message:
String
version:StringBuilder
version:or
The
StringBuffer
version looks like theStringBuilder
but the effects differ.About
StringBuffer
vs.StringBuilder
The former is synchronized and later is not.
So, if you invoke it several times in a single thread (which is 90% of the cases),
StringBuilder
will run much faster, because it won't stop to see if it owns the thread lock.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).String
concatenation (using the + operator) may be optimized by the compiler to useStringBuilder
underneath, so, it is 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 useStringBuilder
instead just in case you use an "old" compiler.Just for those who are curious, this is what the compiler does for this class:
javap -c StringConcatenation
Output:
Lines numbered 5 - 27 are for the String named "literal"
Lines numbered 31-53 are for the String named "builder".
There isn't any difference; exactly the same code is executed for both strings.
字符串
String类
表示字符串。 Java 程序中的所有字符串文字,例如"abc"
都是作为此类的实例实现的。字符串对象一旦创建就不可变,我们无法更改。 (字符串是常量)
如果使用构造函数或方法创建字符串,那么这些字符串将存储在堆内存以及
SringConstantPool
。但在保存到池中之前,它会调用intern()
方法,使用 equals 方法检查池中具有相同内容的对象可用性。 如果字符串复制在池中可用,则返回引用。否则,String 对象将被添加到池中并返回引用。+
) 以及将其他对象转换为字符串提供了特殊支持。字符串连接是通过StringBuilder(或StringBuffer)类及其append方法实现的。字符串文字存储在
StringConstantPool
中。StringBuilder 和 StringBuffer 是可变的字符序列。这意味着人们可以改变这些对象的值。 StringBuffer 与 StringBuilder 具有相同的方法,但 StringBuffer 中的每个方法都是同步的,因此它是线程安全的。
StringBuffer 和 StringBuilder 数据只能使用 new 运算符创建。因此,它们存储在堆内存中。
StringBuilder 的实例对于多线程使用是不安全的。如果需要这样的同步,那么建议使用StringBuffer。
StringBuffer 和 StringBuilder 有一个特殊的方法,例如:
replace(int start, int end, String str)
和reverse()
。<块引用>
注意:StringBuffer 和 SringBuilder 是可变的,因为它们提供了
Appendable Interface
的实现。什么时候用哪个。
如果您不打算每次都更改该值,那么最好使用
String Class
。作为泛型的一部分,如果您想要排序Comparable
或比较值,那么请转到对于字符串类
。如果您要每次修改值,请选择比 StringBuffer 更快的 StringBuilder。如果多个线程正在修改该值,请选择 StringBuffer。
String
The
String class
represents character strings. All string literals in Java program, such as"abc"
are implemented as instances of this class.String objects are immutable once they are created we can't change. (Strings are constants)
If a String is created using constructor or method then those strings will be stored in Heap Memory as well as
SringConstantPool
. But before saving in pool it invokesintern()
method to check object availability with same content in pool using equals method. If String-copy is available in the Pool then returns the reference. Otherwise, String object is added to the pool and returns the reference.+
), and for conversion of other objects to strings. String concatenation is implemented through the StringBuilder(or StringBuffer) class and its append method.String literals are stored in
StringConstantPool
.StringBuilder and StringBuffer are mutable sequence of characters. That means one can change the value of these object's. StringBuffer has the same methods as the StringBuilder, but each method in StringBuffer is synchronized so it is thread safe.
StringBuffer and StringBuilder data can only be created using new operator. So, they get stored in Heap memory.
Instances of StringBuilder are not safe for use by multiple threads. If such synchronization is required then it is recommended that StringBuffer be used.
StringBuffer and StringBuilder are having a Special methods like.,
replace(int start, int end, String str)
andreverse()
.When to use which one.
If a you are not going to change the value every time then its better to Use
String Class
. As part of Generics if you want to SortComparable<T>
or compare a values then go forString Class
.If you are going to modify the value every time the go for StringBuilder which is faster than StringBuffer. If multiple threads are modifying the value the go for StringBuffer.
另外,
StringBuffer
是线程安全的,而StringBuilder
则不是。因此,在实时情况下,当不同线程访问它时,
StringBuilder
可能会产生不确定的结果。Also,
StringBuffer
is thread-safe, whichStringBuilder
is not.So in a real-time situation when different threads are accessing it,
StringBuilder
could have an undeterministic result.请注意,如果您使用的是 Java 5 或更高版本,则应使用
StringBuilder
而不是StringBuffer
。来自 API 文档:实际上,您几乎永远不会同时在多个线程中使用它,因此
StringBuffer
所做的同步几乎总是不必要的开销。Note that if you are using Java 5 or newer, you should use
StringBuilder
instead ofStringBuffer
. From the API documentation: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
没有任何实际用途。我什么时候想要通过操作字符序列在多个线程之间进行通信?这听起来一点用也没有,但也许我还没有看到曙光:)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 :)String 与其他两个类的区别在于 String 是不可变的,而其他两个是可变的类。
但是为什么我们有两个用于相同目的的类?
原因是
StringBuffer
是线程安全的,而StringBuilder
不是。StringBuilder
是 StringBuffer` API 中的一个新类,它是在 中引入的JDK 5,如果您使用单线程,则始终建议您使用环境,因为它更快。有关完整的详细信息,您可以阅读 http://www.codingeek.com/java/stringbuilder-and-stringbuffer-a-way-to-create-mutable-strings-in-java/
The difference between String and the other two classes is that String is immutable and the other two are mutable classes.
But why do we have two classes for the same purpose?
The reason is that
StringBuffer
is threadsafe andStringBuilder
is not.StringBuilder
is a new class in the StringBuffer` API and it was introduced in JDK 5 and is always recommended if you are working in a singlethreaded environment as it is much faster.For complete details, you can read http://www.codingeek.com/java/stringbuilder-and-stringbuffer-a-way-to-create-mutable-strings-in-java/
在 Java 中,String 是不可变的。不可变意味着一旦创建了字符串,我们就无法更改它的值。
StringBuffer 是可变的。一旦创建了 StringBuffer 对象,我们只需将内容追加到对象的值中,而不是创建一个新对象。
StringBuilder与StringBuffer类似,但它不是线程安全的。 StingBuilder 的方法不是同步的,但与其他 String 相比,Stringbuilder 运行速度最快。
您可以通过实现来了解 String、StringBuilder 和 StringBuffer 之间的区别他们。
In Java, String is immutable. Being immutable we mean that once a String is created, we can not change its value.
StringBuffer is mutable. Once a StringBuffer object is created, we just append the content to the value of object instead of creating a new object.
StringBuilder is similar to StringBuffer, but it is not thread-safe. Methods of StingBuilder are not synchronized, but in comparison to other Strings, the Stringbuilder runs the fastest.
You can learn the difference between String, StringBuilder and StringBuffer by implementing them.
下面是一个小代码片段,说明了如何在异步环境中中断 StringBuilder:
本质上,我们将字符串附加到构建器,并且我们期望所有字符串都等于“我刚刚附加了这个!”。但事实并非如此;其中一些以空字符为前缀,因为构建器的内部字符缓冲区未同步并且错误地调整了大小。在这种情况下使用 StringBuffer 可以解决这个问题。更详细的信息位于此处。
Here is a small code snippet illustrating how you can break StringBuilder in an asynchronous environment:
Essentially, we append strings to the builder and we expect that all of them are equal to "I just appended this!". But they are not; some of them are prefixed with null characters, because the internal character buffer of the builder is not synchronized and it gets wrongly resized. Using StringBuffer in this situation solves the problem. More detailed information is here.