java中println和print的效率问题

旅行者

一般使用应该区别不大,时间应该都是微秒级别,不过较真起来,还是有区别的。

测试println:


public static void main(String[] args) {

ArrayList<Long> timeList = new ArrayList<>();

for (int j = 0; j < 20; j++) {

long start = System.currentTimeMillis();

for (int i = 0; i < 1000000; i++) {

System.out.println(i % 2 + "");

}

timeList.add(System.currentTimeMillis() - start);

}

System.out.println(timeList.toString());

}

System.out.println(i % 2 + "")

这个语句使用 i % 2 可以保证每次输出的长度都是固定为1字节,并且与上次不同。

最后输出:


[3435, 3120, 3166, 3195, 3079, 3099, 2982, 3178, 3100, 2866, 3291, 3148, 2811, 3097, 3109, 2984, 3129, 2987, 3182, 2894]

总时间:61852 ms,平均耗时:3092.6 ms


测试print:


public static void main(String[] args) {

ArrayList<Long> timeList = new ArrayList<>();

for (int j = 0; j < 20; j++) {

long start = System.currentTimeMillis();

for (int i = 0; i < 1000000; i++) {

System.out.print(i % 2 + "\n");

}

timeList.add(System.currentTimeMillis() - start);

}

System.out.println(timeList.toString());

}

换行使用+"\n"代替。

输出:


[1904, 1834, 1642, 1549, 1603, 1735, 1548, 1493, 1771, 1658, 1697, 1550, 1517, 1510, 1834, 1798, 1867, 1566, 1550, 1545]

总耗时:33171 ms,平均耗时:1658.55 ms。

结论:print函数+"\n"花费时间仅为println函数的53.63%。

但通常情况下不需要区分他们的区别,因为从上面print函数的情况来看,执行一个循环所需的时间仅为1.66 us(微秒),包括判断条件、计算余数、打印输出、自增,这一点点时间区别榨不出一点油水。只有在超大循环里面来能比较明显地看出他们的区别。但是有几个人会用超大循环在控制台print输出呢?

另外还有一点,上面测试时使用的很短的字符串进行连接,假如用的是很长的字符串呢?会不会连接字符串的时间就赶上来了呢?

主 楼 发布于:2018-11-18 00:07:27 编辑于:2018-11-18 00:25:42回复
旅行者

改用长字符串测试


public static void main(String[] args) {

ArrayList<Long> timeList = new ArrayList<>();

for (int j = 0; j < 10; j++) {

long start = System.currentTimeMillis();

for (int i = 0; i < 500000; i++) {

System.out.println(i % 2 + "oiwjejasfjlaskjgaijalisjvglzkjhkljhdfrtdthfghghghfhgfknxviahjgjadslfjalsd;fjask" + (i % 2 + 1) + "");

}

timeList.add(System.currentTimeMillis() - start);

}

System.out.println(timeList.toString());

}

总耗时:20339 ms,平均耗时 2033.9 ms

2 楼 发布于:2018-11-18 00:55:56
回复
旅行者

忘了贴时间了:

[3437, 1648, 2227, 1572, 1490, 3742, 1792, 1628, 1435, 1368]

3 楼 发布于:2018-11-18 00:59:07
回复
旅行者

print:

[2443, 1734, 974, 1153, 1005, 1061, 3360, 1140, 967, 961]

总时间:14798 ms,平均:1.4798 ms,是println的72%。

可见,字符串的操作时间所占的比例在提高,导致两个print语句的区别被冲淡。

结论就是,一般使用不需要考虑2者区别。如果真是需要大规模输出,推荐print。其实看看源码应该更清楚:


public void println(String x) {

synchronized (this) {

print(x);

newLine();

}

}

println每次都会多出一个newLine方法,而该方法源码:


private void newLine() {

try {

synchronized (this) {

ensureOpen();

textOut.newLine();

textOut.flushBuffer();

charOut.flushBuffer();

if (autoFlush)

out.flush();

}

}

catch (InterruptedIOException x) {

Thread.currentThread().interrupt();

}

catch (IOException x) {

trouble = true;

}

}

多了好多乱七八糟的调用!

4 楼 发布于:2018-11-18 01:10:26
回复
旅行者

printf就更别想了,那就不是正经的print!

5 楼 发布于:2018-11-18 01:15:35
回复
旅行者

然而频繁地调用print方法还是不大合理,使用StringBuider暂存如何?


public static void main(String[] args) {

ArrayList<Long> timeList = new ArrayList<>();

for (int j = 0; j < 20; j++) {

long start = System.currentTimeMillis();

StringBuilder builder = new StringBuilder(1000000);

for (int i = 0; i < 1000000; i++) {

builder.append(i % 2).append("\n");

}

System.out.print(builder.toString());

timeList.add(System.currentTimeMillis() - start);

}

System.out.println(timeList.toString());

}

结果:


[1709, 724, 442, 478, 565, 459, 494, 431, 514, 518, 413, 527, 591, 620, 524, 430, 640, 368, 467, 401]

总耗时:11315 ms,平均耗时:565.75 ms

平均时间只有print的34%!更是只有println的九分之一!

6 楼 发布于:2018-11-18 03:31:19
回复
旅行者

既然StringBuilder 内部是靠数组,那么直接使用数组如何?


public static void main(String[] args) {

ArrayList<Long> timeList = new ArrayList<>();

int index;

for (int j = 0; j < 20; j++) {

long start = System.currentTimeMillis();

char[] chars = new char[2000000];

for (int i = 0; i < 1000000; i++) {

index = i * 2;

chars[index] = (char) (i % 2 + 48);

chars[index + 1] = '\n';

}

System.out.print(new String(chars));

timeList.add(System.currentTimeMillis() - start);

}

System.out.println(timeList.toString());

}

输出:


[446, 601, 1196, 414, 424, 442, 456, 429, 466, 428, 407, 549, 550, 534, 537, 456, 445, 578, 354, 445]

总耗时:10157 ms,平均耗时:507.85 ms,提高了一点点

7 楼 发布于:2018-11-18 03:45:08
回复
旅行者

7楼的程序中有个加法和类型强制转换,可能会影响效率,换成三元运算符如何?


public static void main(String[] args) {

ArrayList<Long> timeList = new ArrayList<>();

int index;

for (int j = 0; j < 20; j++) {

long start = System.currentTimeMillis();

char[] chars = new char[2000000];

for (int i = 0; i < 1000000; i++) {

index = i * 2;

chars[index] = (i % 2 == 0) ? '0' : '1';

chars[index + 1] = '\n';

}

System.out.print(new String(chars));

timeList.add(System.currentTimeMillis() - start);

}

System.out.println(timeList.toString());

}

输出:


[308, 533, 1050, 326, 350, 432, 438, 328, 448, 328, 429, 346, 464, 458, 457, 756, 712, 419, 342, 368]

总耗时:9292 ms,平均耗时:464.6 ms!

当然,使用数组,就是这个问题的特解,已经没有现实意义了,只有探索意义,但仍有参考价值!

8 楼 发布于:2018-11-18 03:51:58
回复
旅行者

运行环境:

CPU:i5 4590 @3.3GHz

内存:ddr3 1600mHz 32GB

操作系统:windows 7 旗舰版

JDK版本:jdk1.8.0_191 64位

jvm内存设置:-Xmx20480m

9 楼 发布于:2018-11-18 03:57:13
回复
旅行者

上面告诉我们一个道理:在性能悠关的关键场合,任何一个语句都有优化的可能。

10 楼 发布于:2018-11-18 04:13:53
回复
世上没有真情

时间就像乳沟,只要挤一挤总还是有的!

11 楼 发布于:2018-12-03 15:42:52
回复
我德新世界1994

当你读到这封短信时,我正在世界上的某一个角落静静地想你,想知道你在做什么,想知道你有没有在想我?

12 楼 发布于:2019-01-19 01:04:10
回复
消失寒暄

亲爱的,我不会爱你太久,只是比“永远”多一天!

13 楼 发布于:2019-03-03 17:58:13
回复
抗忙北鼻来亲亲

楼主继续加油啊

14 楼 发布于:2019-03-11 14:21:13
回复
坏脾气的怪咔

也许,别人能给你的,我不一定能给你。但我能保证:我能给你的,别人永远给不了!

15 楼 发布于:2019-10-19 18:45:06
回复
细细长长在70

一句寒暖,一线相喧;一句叮咛,一笺相传;一份相思,一心相盼;一份友情,一生挂念。

16 楼 发布于:2025-06-26 16:13:07
回复

发表回复: