英文:
Java OutputStream printing speed
问题
假设我需要打印一个带有逗号分隔值的数组 arr。目前,我正在执行以下操作:
for (int i = 0; i < arr.length; i++) {
System.out.print(arr[i] + ",");
}
然而,对于很大的 arr 长度,我在想这样做可能会非常慢。我心里考虑的第二种方法是使用 StringBuilder,构建最终的输出字符串,并且只使用一个打印语句。这样做是否值得一试?权衡之处在于代码会变得更加复杂。
如果有影响的话,我希望得到关于在控制台打印和打印到文件的答案。
英文:
Suppose I had to print an array arr with comma-separated values. Right now, I am doing the following:
for(int i = 0;i<arr.length;i++) {
System.out.print(arr[i] + ",");
}
However, for large arr lengths, I was wondering if this might be really slow. A second approach I had in mind was using StringBuilder, and constructing the final output string and only using 1 print statement. Would that be worth going for? The tradeoff would be more complicated code.
If it matters, I would like an answer for printing to console and printing to a file.
答案1
得分: 1
这段代码效率不高,因为每次计算 arr[i] + ","
都需要实例化一个新的字符串,这会导致分配一个新的内存槽,并在完成后通过垃圾回收器丢弃旧的字符串。
Dave Newton 提供的解决方案是打印数组的最有效方法。我使用一个包含 20,000 个元素的数组进行了小型基准测试(这是我在小型PC上选择的最大数字,因为在数组太大时显示数组会扭曲计算时间):
import java.util.Arrays;
public class Main {
public static void main(String[] args) {
String[] array = new String[20000];
Arrays.fill(array, "A");
long t0 = System.currentTimeMillis();
/* 测试 1:使用 for 循环 */
for (int i = 0; i < array.length; i++)
System.out.print(array[i] + ",");
System.out.println();
long t1 = System.currentTimeMillis();
/* 测试 2:使用 for-each 循环 */
for (String a : array)
System.out.print(a + ",");
System.out.println();
long t2 = System.currentTimeMillis();
/* 测试 3:使用 String.join */
System.out.println(String.join(",", array));
long t3 = System.currentTimeMillis();
System.out.println("测试 1:" + (t1 - t0) + "ms");
System.out.println("测试 2:" + (t2 - t1) + "ms");
System.out.println("测试 3:" + (t3 - t2) + "ms");
}
}
我得到了以下结果:
测试 1:110ms
测试 2:93ms
测试 3:0ms
这个网站 解释了原因。String.join
生成一个 StringJoiner
实例,该实例在 StringBuilder
中存储字符。
StringBuilder
充当缓冲区;将 String
附加到缓冲区中,然后显示结果要比多次实例化两个 String
的和要高效得多。
英文:
This code isn't efficient because you have to instantiate a new String each time you calculate arr[i] + ","
, which requires to allocate a new memory slot and discard the old string with the garbage collector when it's done.
The solution given by Dave Newton is the most efficient way to print your array. I've made a little benchmark with an array containing 20 000 elements (the biggest number I can choose in my small PC because displaying the array tends to distort the computing time when the array is too big):
import java.util.Arrays;
public class Main {
public static void main(String[] args) {
String[] array = new String[20000];
Arrays.fill(array, "A");
long t0 = System.currentTimeMillis();
/* Test 1 : using a for loop */
for (int i = 0; i < array.length; i++)
System.out.print(array[i] + ",");
System.out.println();
long t1 = System.currentTimeMillis();
/* Test 2 : using a for-each loop */
for (String a : array)
System.out.print(a + ",");
System.out.println();
long t2 = System.currentTimeMillis();
/* Test 3 : using String.join */
System.out.println(String.join(",", array));
long t3 = System.currentTimeMillis();
System.out.println("Test 1 : " + (t1 - t0) + "ms");
System.out.println("Test 2 : " + (t2 - t1) + "ms");
System.out.println("Test 3 : " + (t3 - t2) + "ms");
}
}
I have the following results:
Test 1 : 110ms
Test 2 : 93ms
Test 3 : 0ms
This website explains the reason. String.join
generates a StringJoiner
instance which stores characters in a StringBuilder
.
StringBuilder
works as a buffer; appending String
s in a buffer then display the result is way more efficient than instantiating the sum of 2 String
s multiple times.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论