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


当前回答

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 fastest. You can learn difference between String, StringBuilder and StringBuffer by implementing them.

其他回答

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 fastest. You can learn difference between String, StringBuilder and StringBuffer by implementing them.

你是说为了串联吗?

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

例如,发送消息:

字符串

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

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

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

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

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

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