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

我倾向于使用 String.format 但偶尔会滑倒并使用串联。我想知道其中一个是否比另一个更好。

在我看来, String.format 为您提供更多“格式化”字符串的能力;连接意味着您不必担心意外添加额外的 %s 或漏掉一个。

String.format 也更短。

哪一种更具可读性取决于您的大脑如何工作。

有帮助吗?

解决方案

我建议,这是更好的做法是使用String.format()。其主要原因是,String.format()可以与来自资源文件加载的文本被更容易地定位,而级联不能而不产生新的可执行不同的代码对每个语言本地化。

如果您计划在您的应用程序是localisable你也应该进入指定为您的格式参数位置的习惯令牌以及

"Hello %1$s the time is %2$t"

这然后可局部化,并且具有名称和时间的令牌,而不需要可执行重新编译以考虑不同的排序交换。与参数位置还可以重复使用相同的参数,而不传递到函数两次:

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

其他提示

关于性能:

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");
}

时序结果如下:

  • 串联 = 265 毫秒
  • 格式 = 4141 毫秒

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

由于有关于性能的讨论,我想我应该添加一个包括 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");
  • 2012-01-11 16:30:46,058 信息 [TestMain] - 格式 = 1416 毫秒
  • 2012-01-11 16:30:46,190 INFO [TestMain] - 连接 = 134 毫秒
  • 2012-01-11 16:30:46,313 信息 [TestMain] - 字符串生成器 = 117 毫秒

.format一个问题是,你失去了静态类型安全。你可以有参数太少了您的格式,你可以有错误类型的格式说明 - 在运行时都导致一个IllegalFormatException 的,所以你可能最终打破生产测井代码

在相反,参数+可以由编译器进行测试。

  

哪一个是更具可读性取决于你的脑袋是如何工作的。

你有你的答案就在这里。

这是个人喜好的问题。

字符串连接是稍快,我想,但应该是可忽略的。

下面是与以毫秒为单位的多个样本大小的测试。

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);
}

}

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

下面是相同的测试如以上调用的 的toString() 上的的StringBuilder 方法的变形例。下面的结果表明StringBuilder的方法使用比字符串连接慢只是有点的 + 运算符。

文件: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");

  }
}

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

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

结果:

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

String.format()不仅仅是连接字符串更多。例如,可以在一个特定的语言环境中使用String.format()显示数字。

不过,如果你不关心的定位,没有功能上的差异。 也许一个比其它快,但在大多数情况下这将是可忽略不计..

一般来说,字符串连接应该优先于 String.format. 。后者有两个主要缺点:

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

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

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

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

我没有做任何具体的基准,但我认为级联可能会更快。的String.format()创建一个新的格式化,这反过来,创建一个新的StringBuilder(大小只有16个字符的)。这是开销,特别是如果你正在格式化更长的字符串和StringBuilder的不断不得不调整了相当多的。

然而,级联是不太有用,更难阅读。一如往常,这是值得做的事情在你的代码,看看哪个更好的基准。后的差别可能是在服务器应用程序可忽略不计的资源束,语言环境等被加载在存储器中,该代码是即时编译。

也许作为最佳实践,这将是一个好主意,创建自己的格式化程序与适当大小的StringBuilder(可追加)和区域设置和使用,如果你有很多的格式做。

有可能是一个可察觉的差异。

String.format是相当复杂的,并使用正则表达式的下面,所以不要使之成为习惯,在任何地方使用它,但只有在你需要它。

StringBuilder会更快一个数量级(如这里有人已经指出的那样)。

可以不是由上述的程序比较字符串连接和的String.Format。

您可以尝试这也可以互换使用的String.Format和串联在代码块像下面的

的位置
public static void main(String[] args) throws Exception {      
  long start = System.currentTimeMillis();

  for( int i=0;i<1000000; i++){
    String s = String.format( "Hi %s; Hi to you %s",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") ;
}

您会惊奇地看到,格式更快的工作在这里。这是自创建INTIAL对象可能不会被释放,并有可能与内存分配的问题,从而性能。

这需要习惯的String.Format一点时间,但它是值得的,在大多数情况下。在NRA(永不重复的任何东西)这是保持你的切分消息(记录或用户)的一个常数库是非常有用的世界(我喜欢什么相当于一个静态类),并在必要时使用的String.Format给他们打电话,无论您在本地化或没有。尝试使用这样的库用串联方法是难以阅读,排查,校对,并与任何需要级联任何办法管理。更换是一种选择,但我怀疑它的高性能。经过多年的使用,我用的String.Format最大的问题是通话时长是不方便的长,当我向它传递到另一个函数(如MSG),但是这很容易用一个自定义函数作为一个别名来解决

我想我们可以去MessageFormat.format因为它应该是既善于的可读性,同时性能方面。

我使用哪个使用一个相同的程序的 Icaro酒店在他的上面的回答和我与附加代码用于使用MessageFormat解释性能数字增强它。

  public static void main(String[] args) {
    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");

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

级联= 69毫秒

     

格式= 1435毫秒

     

的MessageFormat = 200毫秒

<强>更新

作为每SonarLint报告printf风格格式字符串应该正确使用(鱿鱼:S3457)

由于printf风格格式字符串是在运行时解释的,而不是由编译器验证,它们可含有导致正在创建的错误串错误。这条规则静态验证printf风格的格式字符串,以他们的论据调用格式(......)时的java.util.Formatter,java.lang.String中,java.io.PrintStream中,MessageFormat中,java.io和方法的相关性.PrintWriter类和的printf(...)java.io.PrintStream中或java.io.PrintWriter中的类的方法。

我用大括号替代printf风格,我得到了一些有趣的结果如下。

  

级联= 69毫秒,点击格式= 1107毫秒,点击   的格式:大括号= 416毫秒结果的MessageFormat = 215   毫秒结果的MessageFormat:大括号= 2517毫秒,点击

我结论:结果 正如我上面所强调的,使用的String.format用大括号应该是一个不错的选择,以获得良好的可读性,同时性能的好处。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top