使用String和使用String之间有明显的区别吗?格式和字符串连接在Java?

我倾向于使用String。格式,但偶尔会滑倒和使用连接。我想知道哪个比哪个好。

在我看来,String。Format让你在“格式化”字符串时更强大;连接意味着您不必担心不小心输入了额外的%s或遗漏了一个。

字符串。格式也更短。

哪一个更容易读,取决于你的大脑如何工作。


当前回答

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

如果你打算让你的应用程序本地化,你也应该养成为你的格式标记指定参数位置的习惯:

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

其他回答

我没有做任何具体的基准测试,但我认为连接可能更快。String.format()创建一个新的Formatter,该Formatter反过来创建一个新的StringBuilder(大小只有16个字符)。这是一个相当大的开销,特别是当您正在格式化一个较长的字符串并且StringBuilder必须不断调整大小时。

然而,串联不太有用,也更难阅读。一如既往,有必要对代码进行基准测试,看看哪个更好。在服务器应用程序中,当你的资源包、locale等加载到内存中,代码被jit后,这些差异可以忽略不计。

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

你不能比较字符串连接和字符串。格式由上面的程序。

你也可以尝试交换使用你的字符串的位置。格式和连接在你的代码块如下所示

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

您会惊讶地发现,Format在这里工作得更快。这是因为创建的初始对象可能不会被释放,内存分配可能会出现问题,从而影响性能。

下面是与上面相同的测试,只是修改了对StringBuilder调用toString()方法。下面的结果表明,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()调用在一次连续传递中所做的事情。人们被迫在格式字符串和参数之间来回切换,同时计算参数的位置。对于短连接,这不是什么大问题。但是,在这些情况下,字符串连接不那么详细。

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

当然,在使用Java语言之外的工具或框架时,可能会出现新的因素。

.format的一个问题是失去了静态类型安全性。格式的参数可能过少,格式说明符的类型也可能错误——这两种情况都会导致运行时出现IllegalFormatException异常,因此可能会生成破坏生产的日志代码。

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

printf的安全历史(格式化函数是在它的基础上建模的)是漫长而可怕的。