在Java中使用String.format而不是字符串连接是更好的做法吗?

Oma*_*eji 252 java string string.format concatenation

String.format在Java中使用和字符串连接之间是否存在明显的差异?

我倾向于使用,String.format但偶尔会滑倒并使用concat.我想知道一个人是否比另一个好.

我看到它的方式,String.format给你"格式化"字符串更多的权力; 和连接意味着您不必担心意外地添加额外的%s或丢失一个%s.

String.format 也更短.

哪一个更具可读性取决于你的头部如何工作.

wor*_*ad3 226

我建议使用它是更好的做法String.format().主要原因是String.format()可以更容易地使用从资源文件加载的文本进行本地化,而如果不为每种语言生成具有不同代码的新可执行文件,则无法对连接进行本地化.

如果您计划将应用程序设置为可本地化,那么您还应养成为格式标记指定参数位置的习惯:

"Hello %1$s the time is %2$t"
Run Code Online (Sandbox Code Playgroud)

然后可以对其进行本地化,并且可以交换名称和时间令牌,而无需重新编译可执行文件以考虑不同的顺序.使用参数位置,您还可以重复使用相同的参数,而不将其传递给函数两次:

String.format("Hello %1$s, your name is %1$s and the time is %2$t", name, time)
Run Code Online (Sandbox Code Playgroud)

  • 随机Java版本迟到总比:http://docs.oracle.com/javase/1.5.0/docs/api/java/util/Formatter.html#syntax (13认同)
  • 您能给我指出一些有关如何在 Java 中使用参数位置/顺序的文档(即如何按参数的位置引用参数)吗?谢谢。 (2认同)

Ica*_*aro 158

关于表现:

public static void main(String[] args) throws Exception {      
  long start = System.currentTimeMillis();
  for(int i = 0; i < 1000000; i++){
    String s = "Hi " + i + "; Hi to you " + i*2;
  }
  long end = System.currentTimeMillis();
  System.out.println("Concatenation = " + ((end - start)) + " millisecond") ;

  start = System.currentTimeMillis();
  for(int i = 0; i < 1000000; i++){
    String s = String.format("Hi %s; Hi to you %s",i, + i*2);
  }
  end = System.currentTimeMillis();
  System.out.println("Format = " + ((end - start)) + " millisecond");
}
Run Code Online (Sandbox Code Playgroud)

时间结果如下:

  • 连接= 265毫秒
  • 格式= 4141毫秒

因此,连接比String.format快得多.

  • @AmirRaminar:编译器将"+"转换为自动调用StringBuilder. (100认同)
  • @MartinSchröder:如果你运行`javap -c StringTest.class`,你会看到如果你不在循环中,编译器会自动将"+"转换为StringBuilder**.如果连接都是在一行上完成的,那就和使用'+'一样,但是如果你在多行上使用`myString + ="morechars";`或`myString + = anotherString;`你会注意到可能会创建一个StringBuilder,因此使用"+"并不总是像StringBuilder一样高效. (36认同)
  • 他们都是不好的做法.使用StringBuilder. (13认同)
  • StringBuilder超出了范围(OP问题是关于比较String.format而不是字符串连接)但是你有关于String Builder的数据吗? (7认同)
  • @Joffrey:我的意思是for循环`+`没有转换为`StringBuilder.append()`而是在每次迭代时都会发生`new StringBuilder()`. (6认同)

Tec*_*rip 37

由于有关性能的讨论,我想我会添加一个包含StringBuilder的比较.它实际上比concat更快,自然是String.format选项.

为了使这成为一种苹果与苹果的比较,我在循环中而不是在外部实例化一个新的StringBuilder(这实际上比仅进行一次实例化更快,这很可能是由于在结束时为循环附加重新分配空间的开销.一个建设者).

    String formatString = "Hi %s; Hi to you %s";

    long start = System.currentTimeMillis();
    for (int i = 0; i < 1000000; i++) {
        String s = String.format(formatString, i, +i * 2);
    }

    long end = System.currentTimeMillis();
    log.info("Format = " + ((end - start)) + " millisecond");

    start = System.currentTimeMillis();

    for (int i = 0; i < 1000000; i++) {
        String s = "Hi " + i + "; Hi to you " + i * 2;
    }

    end = System.currentTimeMillis();

    log.info("Concatenation = " + ((end - start)) + " millisecond");

    start = System.currentTimeMillis();

    for (int i = 0; i < 1000000; i++) {
        StringBuilder bldString = new StringBuilder("Hi ");
        bldString.append(i).append("; Hi to you ").append(i * 2);
    }

    end = System.currentTimeMillis();

    log.info("String Builder = " + ((end - start)) + " millisecond");
Run Code Online (Sandbox Code Playgroud)
  • 2012-01-11 16:30:46,058 INFO [TestMain] - 格式= 1416毫秒
  • 2012-01-11 16:30:46,190 INFO [TestMain] - 连接= 134毫秒
  • 2012-01-11 16:30:46,313 INFO [TestMain] - String Builder = 117毫秒

  • StringBuilder测试不会调用toString(),因此这不是一个公平的比较.我怀疑如果你修复了这个bug,你会发现它在连接性能的测量误差范围内. (21认同)
  • 在连接和格式测试中,您要求使用`String`.总而言之,StringBuilder测试需要最后一步,将StringBuilder的内容转换为String.你可以通过调用`bldString.toString()`来做到这一点.我希望能解释一下吗? (15认同)
  • 你们怎么知道代码是否被执行了?变量永远不会被读取或使用,您无法确定 JIT 不会首先删除此代码。 (6认同)
  • Jamey Sharp完全正确.如果不比字符串连接慢,则调用bldString.toString()大致相同. (4认同)
  • `String s = bldString.toString();`时序是连接和stringbuilder几乎相互平等:`格式= 1520毫秒`,`连接= 167毫秒`,`字符串生成器= 173毫秒`我运行它们一个循环并平均每个以获得一个好的代表:( pre-jvm优化,当我有时间时会尝试10000+循环) (3认同)

Rei*_*der 35

一个问题.format是你失去了静态类型的安全性.您的格式参数可能太少,并且您可能为格式说明符设置了错误的类型 - 这两种类型都会导致IllegalFormatException 运行时,因此您最终可能会遇到破坏生产的日志记录代码.

相反,+可以由编译器测试参数.

  • 仅仅为了记录,现代IDE(例如IntelliJ)协助参数计数和类型匹配 (13认同)
  • 关于编译的好处,我建议你通过FindBugs进行这些检查(可以在IDE中运行或在构建期间通过Maven运行),请注意,这也将检查所有日志记录中的格式!无论用户IDE如何,这都有效 (2认同)

Thi*_*ilo 17

哪一个更具可读性取决于你的头部如何工作.

你在那里得到了答案.

这是个人品味的问题.

我想,字符串连接速度稍快,但这应该可以忽略不计.

  • 我不同意.无论项目有多大,你几乎都无法定位其中构建的每个字符串.换句话说,它取决于情况(用于的字符串是什么). (4认同)
  • 如果项目很小并且从未打算在任何有意义的意义上进行国际化,那么这只是个人品味的问题.否则,String.format会以各种方式胜过连接. (3认同)
  • 我同意.在这里考虑性能差异主要是过早优化 - 在不太可能的情况下,分析显示这里存在问题,然后担心它. (2认同)

Der*_*mba 14

这是一个测试,有多个样本大小,以毫秒为单位.

public class Time {

public static String sysFile = "/sys/class/camera/rear/rear_flash";
public static String cmdString = "echo %s > " + sysFile;

public static void main(String[] args) {

  int i = 1;
  for(int run=1; run <= 12; run++){
      for(int test =1; test <= 2 ; test++){
        System.out.println(
                String.format("\nTEST: %s, RUN: %s, Iterations: %s",run,test,i));
        test(run, i);
      }
      System.out.println("\n____________________________");
      i = i*3;
  }
}

public static void test(int run, int iterations){

      long start = System.nanoTime();
      for( int i=0;i<iterations; i++){
          String s = "echo " + i + " > "+ sysFile;
      }
      long t = System.nanoTime() - start;   
      String r = String.format("  %-13s =%10d %s", "Concatenation",t,"nanosecond");
      System.out.println(r) ;


     start = System.nanoTime();       
     for( int i=0;i<iterations; i++){
         String s =  String.format(cmdString, i);
     }
     t = System.nanoTime() - start; 
     r = String.format("  %-13s =%10d %s", "Format",t,"nanosecond");
     System.out.println(r);

      start = System.nanoTime();          
      for( int i=0;i<iterations; i++){
          StringBuilder b = new StringBuilder("echo ");
          b.append(i).append(" > ").append(sysFile);
          String s = b.toString();
      }
     t = System.nanoTime() - start; 
     r = String.format("  %-13s =%10d %s", "StringBuilder",t,"nanosecond");
     System.out.println(r);
}
Run Code Online (Sandbox Code Playgroud)

}

TEST: 1, RUN: 1, Iterations: 1
  Concatenation =     14911 nanosecond
  Format        =     45026 nanosecond
  StringBuilder =      3509 nanosecond

TEST: 1, RUN: 2, Iterations: 1
  Concatenation =      3509 nanosecond
  Format        =     38594 nanosecond
  StringBuilder =      3509 nanosecond

____________________________

TEST: 2, RUN: 1, Iterations: 3
  Concatenation =      8479 nanosecond
  Format        =     94438 nanosecond
  StringBuilder =      5263 nanosecond

TEST: 2, RUN: 2, Iterations: 3
  Concatenation =      4970 nanosecond
  Format        =     92976 nanosecond
  StringBuilder =      5848 nanosecond

____________________________

TEST: 3, RUN: 1, Iterations: 9
  Concatenation =     11403 nanosecond
  Format        =    287115 nanosecond
  StringBuilder =     14326 nanosecond

TEST: 3, RUN: 2, Iterations: 9
  Concatenation =     12280 nanosecond
  Format        =    209051 nanosecond
  StringBuilder =     11818 nanosecond

____________________________

TEST: 5, RUN: 1, Iterations: 81
  Concatenation =     54383 nanosecond
  Format        =   1503113 nanosecond
  StringBuilder =     40056 nanosecond

TEST: 5, RUN: 2, Iterations: 81
  Concatenation =     44149 nanosecond
  Format        =   1264241 nanosecond
  StringBuilder =     34208 nanosecond

____________________________

TEST: 6, RUN: 1, Iterations: 243
  Concatenation =     76018 nanosecond
  Format        =   3210891 nanosecond
  StringBuilder =     76603 nanosecond

TEST: 6, RUN: 2, Iterations: 243
  Concatenation =     91222 nanosecond
  Format        =   2716773 nanosecond
  StringBuilder =     73972 nanosecond

____________________________

TEST: 8, RUN: 1, Iterations: 2187
  Concatenation =    527450 nanosecond
  Format        =  10291108 nanosecond
  StringBuilder =    885027 nanosecond

TEST: 8, RUN: 2, Iterations: 2187
  Concatenation =    526865 nanosecond
  Format        =   6294307 nanosecond
  StringBuilder =    591773 nanosecond

____________________________

TEST: 10, RUN: 1, Iterations: 19683
  Concatenation =   4592961 nanosecond
  Format        =  60114307 nanosecond
  StringBuilder =   2129387 nanosecond

TEST: 10, RUN: 2, Iterations: 19683
  Concatenation =   1850166 nanosecond
  Format        =  35940524 nanosecond
  StringBuilder =   1885544 nanosecond

  ____________________________

TEST: 12, RUN: 1, Iterations: 177147
  Concatenation =  26847286 nanosecond
  Format        = 126332877 nanosecond
  StringBuilder =  17578914 nanosecond

TEST: 12, RUN: 2, Iterations: 177147
  Concatenation =  24405056 nanosecond
  Format        = 129707207 nanosecond
  StringBuilder =  12253840 nanosecond
Run Code Online (Sandbox Code Playgroud)

  • 当您在循环中追加字符时,例如,当您想要通过逐个添加来创建包含一千个 1 的字符串时,StringBuilder 绝对是最快的方法。以下是更多信息:http://www.pellegrino.link/2015/08/22/string-concatenation-with-java-8.html (2认同)

Ako*_* Cz 9

这是与上面相同的测试,修改了在StringBuilder上调用toString()方法.下面的结果显示StringBuilder方法比使用+运算符的字符串连接稍慢.

file:StringTest.java

class StringTest {

  public static void main(String[] args) {

    String formatString = "Hi %s; Hi to you %s";

    long start = System.currentTimeMillis();
    for (int i = 0; i < 1000000; i++) {
        String s = String.format(formatString, i, +i * 2);
    }

    long end = System.currentTimeMillis();
    System.out.println("Format = " + ((end - start)) + " millisecond");

    start = System.currentTimeMillis();

    for (int i = 0; i < 1000000; i++) {
        String s = "Hi " + i + "; Hi to you " + i * 2;
    }

    end = System.currentTimeMillis();

    System.out.println("Concatenation = " + ((end - start)) + " millisecond");

    start = System.currentTimeMillis();

    for (int i = 0; i < 1000000; i++) {
        StringBuilder bldString = new StringBuilder("Hi ");
        bldString.append(i).append("Hi to you ").append(i * 2).toString();
    }

    end = System.currentTimeMillis();

    System.out.println("String Builder = " + ((end - start)) + " millisecond");

  }
}
Run Code Online (Sandbox Code Playgroud)

Shell命令:(编译并运行StringTest 5次)

> javac StringTest.java
> sh -c "for i in \$(seq 1 5); do echo \"Run \${i}\"; java StringTest; done"
Run Code Online (Sandbox Code Playgroud)

结果:

Run 1
Format = 1290 millisecond
Concatenation = 115 millisecond
String Builder = 130 millisecond

Run 2
Format = 1265 millisecond
Concatenation = 114 millisecond
String Builder = 126 millisecond

Run 3
Format = 1303 millisecond
Concatenation = 114 millisecond
String Builder = 127 millisecond

Run 4
Format = 1297 millisecond
Concatenation = 114 millisecond
String Builder = 127 millisecond

Run 5
Format = 1270 millisecond
Concatenation = 114 millisecond
String Builder = 126 millisecond
Run Code Online (Sandbox Code Playgroud)


For*_*ega 6

String.format()不仅仅是连接字符串.例如,您可以使用显示特定区域设置中的数字String.format().

但是,如果您不关心本地化,则没有功能差异.也许一个比另一个快,但在大多数情况下它可以忽略不计......


Ste*_*ier 6

通常,字符串连接应该优先于String.format. 后者有两个主要缺点:

  1. 它不会对要以本地方式构建的字符串进行编码。
  2. 构建过程以字符串编码。

第 1 点,我的意思是不可能String.format()在单个顺序传递中理解调用正在做什么。一个人被迫在格式字符串和参数之间来回移动,同时计算参数的位置。对于短连接,这不是什么大问题。然而,在这些情况下,字符串连接不那么冗长。

第 2 点,我的意思是构建过程的重要部分是在格式字符串中编码的(使用 DSL)。使用字符串来表示代码有很多缺点。它本质上不是类型安全的,并且使语法突出显示、代码分析、优化等复杂化。

当然,在使用 Java 语言外部的工具或框架时,新的因素可能会发挥作用。