字符串、StringBuffer 和 StringBuilder

发布于 2024-09-04 04:06:08 字数 94 浏览 6 评论 0原文

比较 StringStringBufferStringBuilder 的实时情况是什么?

What is some real time situation to compare String, StringBuffer, and StringBuilder?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(12

╭⌒浅淡时光〆 2024-09-11 04:06:08

可变性差异:

字符串不可变的。如果您尝试更改它们的值,则会创建另一个对象,而 StringBufferStringBuilder可变的,因此它们可以更改其值。

线程安全差异:

StringBufferStringBuilder 之间的差异在于 StringBuffer 是线程安全的。因此,当应用程序只需要在单线程中运行时,最好使用StringBuilderStringBuilderStringBuffer 更高效。

情况:

  • 如果您的字符串不会更改,请使用 String 类,因为 String 对象是不可变的。
  • 如果您的字符串可以更改(例如:字符串构造中的大量逻辑和操作)并且只能从单个线程访问,那么使用 StringBuilder 就足够了。
  • 如果您的字符串可以更改,并且可以从多个线程访问,请使用 StringBuffer,因为 StringBuffer 是同步的,因此您具有线程安全性。

Mutability Difference:

String is immutable. If you try to alter their values, another object gets created, whereas StringBuffer and StringBuilder are mutable, so they can change their values.

Thread-Safety Difference:

The difference between StringBuffer and StringBuilder is that StringBuffer is threadsafe. 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.

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 because StringBuffer is synchronous so you have thread-safety.
三五鸿雁 2024-09-11 04:06:08
  • 您使用 String 当不可变结构合适时;从 String 获取新的字符序列可能会带来不可接受的性能损失,无论是 CPU 时间还是内存(获取子字符串是 CPU 高效的,因为数据没有被复制,但这意味着可能需要大量的数据)数据可能仍保持分配状态)。
  • 您使用 StringBuilder 当您需要创建可变字符序列时,通常将多个字符序列连接在一起。
  • 您使用 StringBuffer 在相同的情况下,您将使用 StringBuilder,但是当对底层字符串的更改必须同步时(因为多个线程正在读取/修改字符串缓冲区)。

请参阅此处的示例。

  • You use String when an immutable structure is appropriate; obtaining a new character sequence from a String 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 use StringBuilder, but when changes to the underlying string must be synchronized (because several threads are reading/modifyind the string buffer).

See an example here.

双马尾 2024-09-11 04:06:08

基础知识:

String 是一个不可变类;它无法改变。
StringBuilder是一个可变类,可以附加、替换或删除字符并最终转换为 String
StringBufferStringBuilder 的原始同步版本。

在只有一个线程访问对象的所有情况下,您应该更喜欢 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 源代码:

   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);
    }

如果您偶然得到了一个不是您创建的 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 a String
StringBuffer is the original synchronized version of StringBuilder

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 your StringBuilder/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 a StringBuilder behind the scenes. So for simple cases there isn't any 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 constructor which 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 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:

   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 reallocations and copies.

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 reallocation and copy cycle that you are trying to avoid. The following is straight from the Java 6 source code.

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 reallocate and copy behavior. Call .ensureCapacity() with the size you want to ensure your resulting String 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 subclassing 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 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.

べ繥欢鉨o。 2024-09-11 04:06:08

您可能指的是串联。

真实示例:您想要从许多其他字符串中创建一个新字符串

例如,要发送消息:

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 的运行速度将快得多,因为它不会停下来查看如果它拥有线程锁。

因此,建议使用 StringBuilder (当然,除非您有多个线程同时访问它,但这种情况很少见)。

String 连接(使用 + 运算符)可能会被编译器优化以在下面使用 StringBuilder,因此,不再需要担心。在 Java 的早期,每个人都说应该不惜一切代价避免这种情况,因为每次连接都会创建一个新的 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”的字符串

第 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:

    String s = "Dear " + user.name + "<br>" +
    " I saw your profile and got interested in you.<br>" +
    " I'm  " + user.age + "yrs. old too"

StringBuilder version:

    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.

The StringBuffer version looks like the StringBuilder 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 use StringBuilder 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 use StringBuilder instead just in case you use an "old" compiler.

Just for those who are 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

Output:

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"

Lines numbered 31-53 are for the String named "builder".

There isn't any difference; exactly the same code is executed for both strings.

Hello爱情风 2024-09-11 04:06:08

字符串系列

字符串

String类表示字符串。 Java 程序中的所有字符串文字,例如 "abc" 都是作为此类的实例实现的。

字符串对象一旦创建就不可变,我们无法更改。 (字符串是常量

  • 如果使用构造函数或方法创建字符串,那么这些字符串将存储在堆内存以及SringConstantPool。但在保存到池中之前,它会调用 intern() 方法,使用 equals 方法检查池中具有相同内容的对象可用性。 如果字符串复制在池中可用,则返回引用。否则,String 对象将被添加到池中并返回引用。

    • Java 语言为字符串连接运算符 (+) 以及将其他对象转换为字符串提供了特殊支持。字符串连接是通过StringBuilder(或StringBuffer)类及其append方法实现的。
    String heapSCP = new String("Yash");
    heapSCP.concat(".");
    heapSCP = heapSCP + "M";
    堆SCP = 堆SCP + 777;
    
    // 例如:字符串源代码 
    公共字符串连接(字符串str){
        int otherLen = str.length();
        if (otherLen == 0) {
            返回这个;
        }
        int len = 值.长度;
        char buf[] = Arrays.copyOf(value, len + otherLen);
        str.getChars(buf, len);
        返回新字符串(buf,true);
    }
    
  • 字符串文字存储在StringConstantPool中。

    String onlyPool = "Yash";
    

StringBuilderStringBuffer 是可变的字符序列。这意味着人们可以改变这些对象的值。 StringBuffer 与 StringBuilder 具有相同的方法,但 StringBuffer 中的每个方法都是同步的,因此它是线程安全的。

  • StringBuffer 和 StringBuilder 数据只能使用 new 运算符创建。因此,它们存储在堆内存中。

  • StringBuilder 的实例对于多线程使用是不安全的。如果需要这样的同步,那么建议使用StringBuffer。

    StringBuffer threadSafe = new StringBuffer("Yash");
    threadSafe.append(".M");
    threadSafe.toString();
    
    StringBuilder nonSync = new StringBuilder("Yash");
    nonSync.append(".M");
    nonSync.toString();
    
  • StringBuffer 和 StringBuilder 有一个特殊的方法,例如:
    replace(int start, int end, String str)reverse()

    <块引用>

    注意:StringBuffer 和 SringBuilder 是可变的,因为它们提供了Appendable Interface 的实现。


什么时候用哪个。

  • 如果您不打算每次都更改该值,那么最好使用String Class。作为泛型的一部分,如果您想要排序 Comparable或比较值,那么请转到对于字符串类

    //ClassCastException: java.lang.StringBuffer 无法转换为 java.lang.Comparable
    设置 set = new TreeSet();
    set.add( 线程安全 );
    System.out.println("设置:"+设置);
    
  • 如果您要每次修改值,请选择比 StringBuffer 更快的 StringBuilder。如果多个线程正在修改该值,请选择 StringBuffer。

String Family

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 invokes intern() 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.

    • The Java language provides special support for the string concatenation operator (+), and for conversion of other objects to strings. String concatenation is implemented through the StringBuilder(or StringBuffer) class and its append method.
    String heapSCP = new String("Yash");
    heapSCP.concat(".");
    heapSCP = heapSCP + "M";
    heapSCP = heapSCP + 777;
    
    // For Example: String Source Code 
    public String concat(String str) {
        int otherLen = str.length();
        if (otherLen == 0) {
            return this;
        }
        int len = value.length;
        char buf[] = Arrays.copyOf(value, len + otherLen);
        str.getChars(buf, len);
        return new String(buf, true);
    }
    
  • String literals are stored in StringConstantPool.

    String onlyPool = "Yash";
    

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 threadSafe = new StringBuffer("Yash");
    threadSafe.append(".M");
    threadSafe.toString();
    
    StringBuilder nonSync = new StringBuilder("Yash");
    nonSync.append(".M");
    nonSync.toString();
    
  • StringBuffer and StringBuilder are having a Special methods like.,
    replace(int start, int end, String str) and reverse().

    NOTE: StringBuffer and SringBuilder are mutable as they provides the implementation of Appendable Interface.


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 Sort Comparable<T> or compare a values then go for String Class.

    //ClassCastException: java.lang.StringBuffer cannot be cast to java.lang.Comparable
    Set<StringBuffer> set = new TreeSet<StringBuffer>();
    set.add( threadSafe );
    System.out.println("Set : "+ set);
    
  • 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.

忘东忘西忘不掉你 2024-09-11 04:06:08
-----------------------------------------------------------------
               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
-----------------------------------------------------------------
-----------------------------------------------------------------
               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
-----------------------------------------------------------------
混浊又暗下来 2024-09-11 04:06:08

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

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

Also, StringBuffer is thread-safe, which StringBuilder is not.

So in a real-time situation when different threads are accessing it, StringBuilder could have an undeterministic result.

故笙诉离歌 2024-09-11 04:06:08

请注意,如果您使用的是 Java 5 或更高版本,则应使用 StringBuilder 而不是 StringBuffer。来自 API 文档:

从 JDK 5 版本开始,此类已补充了一个专为单线程使用而设计的等效类 StringBuilder。通常应优先使用 StringBuilder 类,因为它支持所有相同的操作,但速度更快,因为它不执行同步。

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

Note that if you are using Java 5 or newer, you should use StringBuilder instead of StringBuffer. From the API documentation:

As of release JDK 5, this class has been supplemented with an equivalent class designed for use by a single thread, StringBuilder. The StringBuilder 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.

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.

_蜘蛛 2024-09-11 04:06:08

就我个人而言,我认为 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 :)

蓝戈者 2024-09-11 04:06:08

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 and StringBuilder 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/

一场春暖 2024-09-11 04:06:08

在 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.

烟织青萝梦 2024-09-11 04:06:08

下面是一个小代码片段,说明了如何在异步环境中中断 StringBuilder:

public static void main(String[] args) throws InterruptedException {
    StringBuilder builder = new StringBuilder();

    ExecutorService executorService = Executors.newFixedThreadPool(50);
    for (int i = 0; i < 1000 * 1000; i++) {
        executorService.submit(new AppendRunnable(builder));
    }

    executorService.shutdown();
    executorService.awaitTermination(1, TimeUnit.MINUTES);

    Stream.of(builder.toString().split(System.lineSeparator()))
        .filter(line -> !line.equals("I just appended this!"))
        .forEach(System.out::println);
}

record AppendRunnable(StringBuilder stringBuilder) implements Runnable {

    @Override
    public void run() {
        stringBuilder.append("I just appended this!\n");
    }
}

本质上,我们将字符串附加到构建器,并且我们期望所有字符串都等于“我刚刚附加了这个!”。但事实并非如此;其中一些以空字符为前缀,因为构建器的内部字符缓冲区未同步并且错误地调整了大小。在这种情况下使用 StringBuffer 可以解决这个问题。更详细的信息位于此处

Here is a small code snippet illustrating how you can break StringBuilder in an asynchronous environment:

public static void main(String[] args) throws InterruptedException {
    StringBuilder builder = new StringBuilder();

    ExecutorService executorService = Executors.newFixedThreadPool(50);
    for (int i = 0; i < 1000 * 1000; i++) {
        executorService.submit(new AppendRunnable(builder));
    }

    executorService.shutdown();
    executorService.awaitTermination(1, TimeUnit.MINUTES);

    Stream.of(builder.toString().split(System.lineSeparator()))
        .filter(line -> !line.equals("I just appended this!"))
        .forEach(System.out::println);
}

record AppendRunnable(StringBuilder stringBuilder) implements Runnable {

    @Override
    public void run() {
        stringBuilder.append("I just appended this!\n");
    }
}

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.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文