String,StringBuffer和StringBuilder

请告诉我一个实时的情况来比较StringStringBufferStringBuilder

可变性差异:

String不可变的 ,如果你试图改变它们的值,另一个对象被创build,而StringBufferStringBuilder可变的,所以他们可以改变它们的值。

线程安全差异:

StringBufferStringBuilder的区别在于StringBuffer是线程安全的。 所以当应用程序只需要在一个线程中运行时,最好使用StringBuilderStringBuilderStringBuffer更高效。

情况:

  • 如果你的string不会改变,使用一个String类,因为一个String对象是不可变的。
  • 如果你的string可以改变(例如:string构造中的大量逻辑和操作)并且只能从单个线程访问,那么使用StringBuilder就足够了。
  • 如果您的string可以更改,并且将从多个线程访问,请使用StringBuffer因为StringBuffer是同步的,所以您具有线程安全性。
  • 当一个不可变的结构是适当的时候你使用String ; 从一个String获取一个新的字符序列可能会在CPU时间或内存中获得不可接受的性能损失(因为数据不被复制而获得子系统的CPU效率,但这意味着可能保留更多数量的数据)。
  • 当你需要创build一个可变的字符序列时,你可以使用StringBuilder ,通常是将多个字符序列连接在一起。
  • 在使用StringBuffer的情况下使用StringBuilder ,但是当对底层string的改变必须同步时(因为有多个线程正在读/修改string缓冲区)。

在这里看到一个例子。

基础:

String是一个不可变的类,它不能被改变。 StringBuilder是一个可以附加到可变类,字符被replace或删除并最终转换为String StringBufferStringBuffer的原始同步版本

在所有只有一个线程访问您的对象的情况下,您应该更喜欢StringBuilder

细节:

另外请注意, StringBuilder/Buffers不是魔术,它们只是使用一个数组作为支持对象,并且该数组在满满时必须重新分配。 一定要创build足够大的StringBuilder/Buffer对象,在每次调用.append()时都不需要经常重新resize。

重新调整可能变得非常堕落。 每次需要扩展时,基本上将后端数组的大小重新调整为当前大小的2倍。 这可能会导致大量的RAM分配,并且在StringBuilder/Buffer类开始变大时不使用。

在Java String x = "A" + "B"; 在幕后使用了一个StringBuilder 。 所以对于简单的情况来说,宣布你自己没有任何好处。 但是,如果你正在build立大的String对象,比如小于4k,那么声明StringBuilder sb = StringBuilder(4096); 比串联或使用只有16个字符的默认构造函数效率更高。 如果你的String将小于10K,那么使用构造函数将它初始化为10k是安全的。 但是,如果它初始化为10k,那么你写了10k以上的1个字符,它将被重新分配并复制到一个20k数组。 所以初始化高于低于。

在自动重新设置大小写的情况下,在第17个字符后面的数组被重新分配并复制到32个字符,在第33个字符处会再次发生,您将重新分配并将该数组复制为64个字符。 你可以看到这是如何退化到大量的重新分配和复制,这是你真正试图避免使用StringBuilder/Buffer的第一位。

这是来自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); } 

最好的做法是初始化StringBuilder/Buffer比你想象的要大一点,如果你不知道String有多大,但你可以猜到。 比你需要更多的内存分配将比大量的重新分配和复制更好。

另外要小心用String来初始化一个StringBuilder/Buffer ,因为这只会分配String + 16个字符的大小,在大多数情况下,它只会启动您试图避免的简并重新分配和复制循环。 以下是直接从Java 6源代码。

 public StringBuilder(String str) { super(str.length() + 16); append(str); } 

如果偶然发生了一个没有创build的StringBuilder/Buffer的实例,并且无法控制被调用的构造函数,那么有一种方法可以避免退化的重新分配和复制行为。 调用.ensureCapacity()以确保您的结果String适合的大小。

替代品:

正如一个笔记,如果你正在做非常重的 Stringbuild设和操纵,还有一个更多的性能导向的替代品称为绳索 。

另一种方法是通过对ArrayList<String>进行子分类来创build一个StringList实现,并添加计数器来跟踪列表中每个.append()和其他变异操作上的字符数,然后覆盖.toString()以创build一个您需要的确切大小的StringBuilder并循环遍历列表并构build输出,甚至可以使该StringBuilder成为实例variables,并“caching” .toString()的结果,并且只有在某些更改时才能重新生成结果。

当编译固定的格式化输出的时候也不要忘记String.format() ,编译器可以使它更好的进行优化。

你的意思是连接?

真实世界的例子: 你想创build一个新的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() 

要么

 String s = new StringBuilder(100).appe..... etc. ... // The difference is a size of 100 will be allocated upfront as fuzzy lollipop points out. 

StringBuffer(语法与StringBuilder完全一样,效果不同)

关于

StringBufferStringBuilder

前者是同步的,后来不是。

所以,如果你在单个线程(这是90%的情况)中多次调用它, StringBuilder将运行更快,因为它不会停止查看它是否拥有线程锁。

所以,build议使用StringBuilder (除非你有多个线程同时访问,这很less见)

String连接( 使用+运算符 )可能会被编译器优化,以便在下面使用StringBuilder ,因此,不再需要担心,在Java的前几天,这是所有人都应该避免的代价,因为每个连接都创build一个新的String对象。 现代编译器不再这样做了,但是,如果使用“旧”编译器,使用StringBuilder是一个好习惯。

编辑

对于好奇的人来说,这是编译器为这个类所做的:

 class StringConcatenation { int x; String literal = "Value is" + x; String builder = new StringBuilder().append("Value is").append(x).toString(); } 

javap -c StringConcatenation

 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 } 

编号为5-27的行用于名为“literal”的string

编号为31-53的行用于名为“builder”的string

Ther没有什么区别,两个string的执行完全相同。

此外, StringBuffer是线程安全的,而StringBuilder不是。

因此,在不同线程访问它的实时情况下, StringBuilder可能具有不确定的结果。

请注意,如果您使用Java 5或更新版本,则应该使用StringBuilder而不是StringBuffer 。 从API文档:

从版本JDK 5开始,这个类已经补充了一个为单个线程StringBuilderdevise的等价类。 由于StringBuilder类支持所有相同的操作,所以通常会优先使用StringBuilder类,但速度更快,因为它不执行同步操作。

实际上,你几乎不会同时在多个线程中使用它,所以StringBuffer所做的同步几乎总是不必要的开销。

String和其他两个类的区别在于String是不可变的,另外两个是可变类。

但是为什么我们有两个同样的目的?

原因是StringBuffer是线程安全的, StringBuilder不是。 StringBuilderStringBuffer Api上的一个新类,它在JDK5中引入,如果您在单线程环境中工作,则总是推荐使用它,因为它的Faster要快得多

有关完整的详细信息,请阅读http://www.codingeek.com/java/stringbuilder-and-stringbuffer-a-way-to-create-mutable-strings-in-java/

就个人而言,我不认为有任何真正的世界用于StringBuffer 。 我什么时候想通过操纵字符序列来在多个线程之间进行通信? 这听起来没有用处,但也许我还没有看到光:)

在Java中, string是不可变的。 作为不可变的,我们的意思是一旦创build了一个string,我们不能改变它的值。 StringBuffer是可变的。 一旦创build了一个StringBuffer对象,我们只需将内容追加到对象的值而不是创build一个新的对象。 StringBuilder类似于StringBuffer,但它不是线程安全的。 StingBuilder的方法不同步,但与其他string相比,Stringbuilder运行速度最快。 你可以通过实现它们来学习String,StringBuilder和StringBuffer之间的区别。

 -------------------------------------------------- --------------------------------
                   String StringBuffer StringBuilder
 -------------------------------------------------- --------------------------------                 
存储区| 常量string池堆堆 
可修改| 否(不可变)是(可变)是(可变)
线程安全| 是是不是
 性能| 快速非常慢速
 -------------------------------------------------- --------------------------------