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


当前回答

字符串

String类表示字符串。Java程序中的所有字符串字面值,例如“abc”,都被实现为该类的实例。

字符串对象是不可变的,一旦创建就不能改变。(字符串是常量)

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和StringBuffer是可变的字符序列。这意味着可以改变这些对象的值。StringBuffer具有与StringBuilder相同的方法,但是StringBuffer中的每个方法都是同步的,因此它是线程安全的。

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.


什么时候用哪一个。

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.

其他回答

你是说为了串联吗?

真实世界的例子:您希望从许多其他字符串中创建一个新字符串。

例如,发送消息:

字符串

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(语法与StringBuilder完全相同,只是效果不同)

关于

StringBuffer vs. StringBuilder

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

因此,如果在一个线程中多次调用它(90%的情况下),StringBuilder将运行得更快,因为它不会停下来查看它是否拥有线程锁。

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

字符串连接(使用+操作符)可能会被编译器优化以在下面使用StringBuilder,因此,它不再是需要担心的事情,在Java的早期,这是每个人都说应该不惜一切代价避免的事情,因为每个连接都会创建一个新的String对象。现代编译器不再这样做了,但使用StringBuilder代替它仍然是一个很好的实践,以防您使用“旧”编译器。

edit

对于那些好奇的人来说,这是编译器为这个类做的事情:

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”的字符串

没有区别,对两个字符串执行的代码完全相同。

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

下面是一个小代码片段,演示了如何在异步环境中破坏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可以解决问题。更多详细信息请点击这里

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是同步的,因此具有线程安全性。