繁体   English   中英

更新字符串的有效方法是什么?

[英]What is the efficient way to update a String?

假设我需要启动一个String,然后将其更新几次,就像在这个伪代码中一样:

String s = "first";
if (<some condition>) { s += "second"; }
if (<some condition>) { s += "third"; }
if (<some condition>) { s += "fourth"; }

如果我最多有4次,那么以这种方式使用它还是只使用StringBuffer / StringBuilder更好?

实际上我要问的是,在哪种情况下,字符串(这是一种可变类型)的更新时间是使用上述选项的有效方式?

首先,String不是一个可变类。 每次使用+= ,都会返回另一个对象。

其次,除非你在紧密循环中使用它,否则它无论如何都不是很重要。

第三,虽然它可能不是类似计算机科学的方法,但如果我尝试使用的话

    StringBuilder s = new StringBuilder("first");
    s.append( "second" );
    s.append( "third" );
    s.append( "fourth" );

Intellij建议用String替换它,并且只有在使用简单的String时至少同样有效才会出现该建议(尽管由于条件可能不完全相同)

根据Java:String concat vs StringBuilder - 优化,那我该怎么办? Java编译器确实用String构建器替换了一系列String连接:

public static void main(String[] args) {
    String s = "first";

    s+=" second" ;
    if(args.length >0)
    s+=" third";

    System.out.println("s, = " + s);
}

使用JDK 1.8.0_66并使用javap -c SbTest.class生成以下输出。 虽然我不是字节代码的专家,似乎的多个实例StringBuilder创建( 328 )。 因此,在链接的答案中建议,编译的代码似乎是这样的:

    String s = "first";
    s = new StringBuilder().append(s).append(" second") ;
    if(args.length >0)
        s = new StringBuilder().append(s).append(" third") ;

因此,除非JIT正在优化它,否则自己使用StringBuilder可能仍然更有效。

 public static void main(java.lang.String[]);
    Code:
       0: ldc           #2                  // String first
       2: astore_1
       3: new           #3                  // class java/lang/StringBuilder
       6: dup
       7: invokespecial #4                  // Method java/lang/StringBuilder."<init>":()V
      10: aload_1
      11: invokevirtual #5                  // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
      14: ldc           #6                  // String  second
      16: invokevirtual #5                  // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
      19: invokevirtual #7                  // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
      22: astore_1
      23: aload_0
      24: arraylength
      25: ifle          48
      28: new           #3                  // class java/lang/StringBuilder
      31: dup
      32: invokespecial #4                  // Method java/lang/StringBuilder."<init>":()V
      35: aload_1
      36: invokevirtual #5                  // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
      39: ldc           #8                  // String  third
      41: invokevirtual #5                  // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
      44: invokevirtual #7                  // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
      47: astore_1
      48: getstatic     #9                  // Field java/lang/System.out:Ljava/io/PrintStream;
      51: new           #3                  // class java/lang/StringBuilder
      54: dup
      55: invokespecial #4                  // Method java/lang/StringBuilder."<init>":()V
      58: ldc           #10                 // String s, =
      60: invokevirtual #5                  // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
      63: aload_1
      64: invokevirtual #5                  // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
      67: invokevirtual #7                  // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
      70: invokevirtual #11                 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
      73: return
String s = "first";
if (<some condition>) { s += "second"; }
if (<some condition>) { s += "third"; }
if (<some condition>) { s += "fourth"; }

是正确的方法,因为编译器会把它变成一个StringBuilderJDK 1.6及以上版本 ),除非你在循环中使用它,否则优化是相同的。

有关详细信息,请参阅此链接

如果你使用合理大小的字符串(比如你在那里的单词),使用字符串类就完全没问题了,使用字符串构建器类并不比使用普通字符串快得多。 当你可能处理大字符串(想想许多段落)并反复更改它们时,你想要替换它。 StringBuilder和StringBuffer应该大致相同,但StringBuffer是线程安全的,所以如果你要编写多线程代码,那么使用StringBuffer。

要知道的唯一方法是进行基准测试。

package com.example;

import static org.junit.Assert.*;

import java.time.Duration;
import java.time.Instant;

import org.junit.Test;

public class ExampleTest {

    @Test
    public void test() {
        for (int j = 0; j < 4; j++) {
            Instant start = Instant.now();
            for (int i = 0; i < 10000; i++) {

                // Try various implementations here...
                String s = "first";
                if (true) {
                    s += "second";
                }
                if (true) {
                    s += "third";
                }
                if (true) {
                    s += "fourth";
                }
            }
            System.out.println("Took: " + Duration.between(start, Instant.now()).toMillis() + " millis");
        }
    }

}

如果性能不是一个问题,那么优化人类并使其尽可能可读和可维护。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM