请告诉我一个实时情况比较字符串,StringBuffer,和StringBuilder?


当前回答

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

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

其他回答

基础知识:

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

在只有一个线程访问对象的所有情况下,您都应该使用StringBuilder。

细节:

还要注意,StringBuilder/Buffers并不是魔法,它们只是使用一个数组作为支持对象,当数组满时必须重新分配。确保在初始时创建足够大的StringBuilder/Buffer对象,这样就不必在每次调用.append()时不断地调整它们的大小。

调整大小会变得非常糟糕。基本上,每次需要扩展时,它都会将支持数组的大小调整为当前大小的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 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 1 character more than 10k, it will get re-allocated and copied to a 20k array. So initializing high is better than to low.

在自动调整大小的情况下,在第17个字符时,后面的数组被重新分配并复制为32个字符,在第33个字符时,同样发生这种情况,你需要重新分配并将数组复制为64个字符。你可以看到这是如何退化为大量的重新分配和复制,这是你真正试图避免使用StringBuilder/Buffer在第一个地方。

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

一个最好的做法是初始化StringBuilder/Buffer,如果你不知道String会有多大,但你可以猜测,比你认为你需要的要大一点。分配比您需要的稍微多一点的内存比大量的重新分配和复制要好。

另外,要注意用String初始化StringBuilder/Buffer,因为这样只会分配String + 16个字符的大小,在大多数情况下,这只会开始退化的重新分配和复制周期,而这是您试图避免的。下面是直接来自Java 6的源代码。

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

如果碰巧得到了一个不是自己创建的StringBuilder/Buffer实例,并且不能控制所调用的构造函数,有一种方法可以避免恶化的重新分配和复制行为。调用. ensurecapacity(),并设置你想要确保生成的字符串适合的大小。

的选择:

需要注意的是,如果您正在进行非常繁重的字符串构建和操作,有一种更面向性能的替代方法,称为rope。

另一种替代方法是通过子类化ArrayList<String>来创建一个StringList实现,并添加计数器来跟踪每个.append()和列表的其他突变操作上的字符数,然后重写. tostring()来创建一个你需要的精确大小的StringBuilder,并循环遍历列表并构建输出,你甚至可以使该StringBuilder成为一个实例变量并“缓存”. tostring()的结果,只有在发生变化时才需要重新生成它。

在构建固定格式化输出时也不要忘记String.format(),编译器可以优化它,因为它们使它更好。

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

这里有一个例子。

可变性的区别:

String是不可变的,如果你试图改变它们的值,就会创建另一个对象,而StringBuffer和StringBuilder是可变的,所以它们可以改变它们的值。

线程安全的区别:

StringBuffer和StringBuilder的区别在于StringBuffer是线程安全的。因此,当应用程序只需要在一个线程中运行时,最好使用StringBuilder。StringBuilder比StringBuffer更有效。

情况:

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

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

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

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