在Java中,使用String.format比字符串拼接更好的实践吗?

345

在Java中使用String.format和字符串拼接之间有明显的区别吗?

我倾向于使用String.format,但偶尔会用拼接。我想知道哪一个更好。

我认为,String.format在“格式化”字符串方面给您更多的控制权;而拼接意味着您不必担心意外地输入额外的%s或漏掉一个。

String.format也更短。

哪个更易读取取决于您的思维方式。


我认为我们可以使用MessageFormat.format。更多信息请参见答案https://dev59.com/CnNA5IYBdhLWcg3whuZ_#56377112。 - Ganesa Vijayakumar
16个回答

2
我没有进行过具体的基准测试,但我认为连接可能更快。String.format()会创建一个新的Formatter,进而创建一个新的StringBuilder(大小仅为16个字符)。这是相当大的开销,特别是如果您正在格式化较长的字符串,并且StringBuilder不断调整大小。

然而,连接功能不太实用且难以阅读。与往常一样,值得在代码上进行基准测试以查看哪种方法更好。在资源包、语言环境等加载到内存中并且代码被JIT编译后,服务器应用程序中的差异可能微不足道。

也许作为最佳实践,如果您需要进行大量格式化,则最好使用自己的Formatter,其中包含正确大小的StringBuilder(Appendable)和Locale。


2

可能会有明显的差异。

String.format非常复杂,并在底层使用正则表达式,因此不要习惯性地到处使用它,而是只在需要时使用。

StringBuilder将快上一个数量级(如这里已经指出的)。


1
我认为我们可以采用MessageFormat.format,因为它在可读性和性能方面都很好。我使用了与在他上面的答案中使用的相同程序,并附加了使用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样式格式字符串(squid:S3457)。

由于printf-style格式字符串是在运行时解释的,而不是由编译器验证的,它们可能包含错误,导致创建错误的字符串。当调用java.util.Formatterjava.lang.Stringjava.io.PrintStreamMessageFormatjava.io.PrintWriter类的format(...)方法以及java.io.PrintStreamjava.io.PrintWriter类的printf(...)方法时,此规则静态验证printf-style格式字符串与其参数之间的相关性。

我将printf-style替换为花括号,并得到以下有趣的结果。

连接时间 = 69 毫秒
格式化时间 = 1107 毫秒
使用大括号的格式化时间 = 416 毫秒
MessageFormat = 215 毫秒
使用大括号的MessageFormat时间 = 2517 毫秒

我的结论:
如上所述,使用带有大括号的String.format应该是一个不错的选择,既能获得良好的可读性,又能获得良好的性能。


2
这不是你应该编写任何测试的方式,因为结果是不可预测的。你违反了许多规则,比如你没有热身它,忽略了Java优化器等等。 - horvoje

0

要熟悉String.Format需要一些时间,但在大多数情况下它是值得的。在“永不重复任何东西”的世界中,使用常量库(我更喜欢静态类)保持令牌化的消息(日志或用户)非常有用,并在必要时调用它们,无论您是否进行本地化。尝试使用连接方法的库更难阅读、调试、校对和管理,而使用任何需要连接的方法都是如此。替换是一个选择,但我怀疑它的性能。经过多年的使用,我对String.Format最大的问题是当我将其传递到另一个函数(例如Msg)中时,其长度很不方便,但这很容易通过自定义函数作为别名来解决。


0
格式化 = 1508 毫秒 连接 = 31 毫秒
进程以退出代码 0 结束
连接比格式化好多了。

1
根据目前的写法,你的回答不够清晰。请编辑以添加更多细节,帮助其他人理解这如何回答所提出的问题。你可以在帮助中心找到关于如何撰写好回答的更多信息。 - Community

-1

你不能通过上面的程序比较字符串拼接和字符串格式化。

你可以尝试在代码块中交换使用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") ;
}

你会惊讶地发现,在这里使用 Format 的速度更快。这是因为初始创建的对象可能没有被释放,可能存在内存分配问题,从而影响性能。

3
你有尝试过你的代码吗?连接操作总是比其他操作快10倍。 - Icaro
这个“System.currentTimeMillis()”执行所需的毫秒数怎么样? :P - Rohit Rehan

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接