多个 System.out.print() 和连接之间的区别



基本上,我想知道哪种方法是更好的做法,

for(int i = 0; i < 10000; i++){
System.out.print("blah");
}
System.out.println("");

String over_9000_blahs = "";
for(int i = 0; i < 10000; i++){
over_9000_blahs += "blah";
}
System.out.println(over_9000_blahs);

还是有我不知道的更好的方法?

由于您只写入System.out因此第一种方法更好,但是如果性能对您很重要,请使用以下方法(System.out.println同步并使用锁定 - 可以在此处和此处阅读更多相关信息)。

如果你想在以后使用"大字符串"或提高性能,使用StringBuilder会更干净。 (见下文),无论如何字符串+将由编译器转换为StringBuilder(更多详细信息在这里)

StringBuilder stringBuilder = new StringBuilder();
for(int i = 0; i < 10000; i++){
stringBuilder.append("bla");
}
System.out.println(stringBuilder.toString());

如果要在(更大的计数)循环中连接字符串,则需要使用StringBuilder

for(int i = 0; i < 10000; i++){
over_9000_blahs += "blah";
}

对于每次迭代,这都是这样做的:

  • 在内部创建一个新StringBuilder,其内部char数组足够大,以容纳中间结果 (over_9000_blahs)
  • 将字符从over_9000_blahs复制到内部数组中
  • 复制"blah"中的字符
  • 创建一个新String,再次从内部数组复制字符

所以每次迭代是越来越长的字符串的两个副本 - 这意味着二次时间复杂度。


由于System.out.println()可能是同步的,因此重复调用它可能会比使用StringBuilder慢(但我的猜测是它不会比使用+=在循环中连接字符串慢)。

因此,StringBuilder方法应该是三者中最好的。

按性能顺序:

  1. StringBuilder- 最快。基本上,它只是将单词添加到字符数组中。当容量不足时,它会成倍增加。发生次数不应超过 log(10000) 次。

  2. System.out.print- 与StringBuilder相比,它的性能很差,因为我们需要锁定out10000 次。此外,打印创建新char[writeBufferSize]10000 次,而在StringBuilder选项中,我们只执行 1 次!

  3. 连接字符串。创建许多(后来也很大)对象,启动一些"i"内存管理将严重影响性能。

编辑:

更准确地说,因为问题是关于选项2 和选项 3之间的区别,并且很清楚为什么Stringbuilder很快。

我们可以说第二种方法中的每次迭代都需要 K 时间,因为代码是相同的,并且每次迭代的字符串长度都相同。在执行结束时,第二个选项将花费 10000*K 时间进行 10000 次迭代。我们不能对第三种方法说同样的话,因为每次迭代时字符串的长度总是在增加。因此,分配对象和垃圾收集它们的时间会增加。我想说的是,在第三个选项中,执行时间不会线性增加。 因此,对于低NumberOfIterations,我们可能看不到最后两种方法之间的区别。但我们知道,开始一个特定的NumberOfIterations第二个选项总是比第三个选项更好。

在这种情况下,我会说第一个更好。 Java 使用 StringBuilders 进行字符串连接以提高性能,但由于 Java 不知道您像第二种情况那样反复使用循环进行连接,因此第一种情况会更好。

如果你只想系统化你的值 - 结果是一样的。

第二个选项将在内存中创建许多字符串,GC(垃圾收集器)将处理这些字符串。(但是在较新版本的 Java 中不会发生此问题,因为连接将在下面的 StringBuilder 解决方案中将场景转换为隐藏

)如果你想稍后使用你的字符串,在 sysout 之后,你应该检查StringBuilder类和append方法:

StringBuilder sb = new StringBuilder();
for(int i = 0; i < 10000; i++){
sb.append("blah");
}
System.out.println(sb);

最新更新