背景
最近在学习Kotlin,在学习过程中发现了一个问题,发现了一个很神奇的问题,困扰了好久。特此记录。由于网上也没有找到答案,如果对结论有问题,欢迎私信讨论
问题描述
使用System.out.print(“test”); 在logcat中看不到日志,将print替换成println就可以看到。
代码
代码比较简单,只把部分测试关键代码附上,大家可以先别看答案,猜测一下是否会打印。
// 例子1,直接使用print输出。
System.out.print("111111111111111");
// 例子2, 连续使用print输出
System.out.print("111111111111111");
System.out.print("2222222222");
// 例子3, 先调用println,后调用print
System.out.println("111111111111111");
System.out.print("2222222222");
// 例子4, 先调用print,后调用println
System.out.print("111111111111111");
System.out.println("2222222222");
// 例子5, 字符串中添加换行符
System.out.print("111111111111111\n");
System.out.print("2222222222");
输出结果:
// 例子1: 无输出
// 例子2:无输出
// 例子3:System.out: 111111111111111
// 例子4:System.out: 1111111111111112222222222
// 例子5:System.out: 111111111111111
分析
怎么样?!神奇不,老子也是一头雾水啊 有木有,但是秉承着程序是不会骗我的思想,这里一定是我的只是盲区了,有盲区那就照亮他就完事儿了!
从System.out.print() 源码入手
// PrintStream.java
// out.print调用的就是PrintStream中的print方法。
public void print(String s) {
if (s == null) {
s = "null";
}
write(s);
}
// print() 调用的write()
private void write(String s) {
try {
synchronized (this) {
ensureOpen();
// Android-added: Lazy initialization of charOut and textOut.
BufferedWriter textOut = getTextOut();
textOut.write(s);
textOut.flushBuffer();
charOut.flushBuffer();
//重点1:应该是只使用print是无法调用flush导致的。
if (autoFlush && (s.indexOf('\n') >= 0))
out.flush();
}
}
catch (InterruptedIOException x) {
Thread.currentThread().interrupt();
}
catch (IOException x) {
trouble = true;
}
}
我们再来看一下System.out.println()的源码:
// PrintStream.java
// out.println调用的就是PrintStream中的println方法。
public void println(String x) {
synchronized (this) {
print(x);
// 重点2:println实际上是就是调用了print,然后newLine了一下。
newLine();
}
}
// print()过程上边已经分析过了,这里我们直接看newLine里面干了什么。
private void newLine() {
try {
synchronized (this) {
ensureOpen();
// Android-added: Lazy initialization of charOut and textOut.
BufferedWriter textOut = getTextOut();
textOut.newLine();
textOut.flushBuffer();
charOut.flushBuffer();
// 重点3: newLine的流程看着跟write很像,不过注意这里面的区别
if (autoFlush)
out.flush();
}
}
catch (InterruptedIOException x) {
Thread.currentThread().interrupt();
}
catch (IOException x) {
trouble = true;
}
}
相信看了源码之后大家应该都大概明白怎么回事儿了,autoFlush这个值的定义我就不附上了,很简单,大家自己看一下就行了。
我这里直接说结果,autoFlush是true,所以当我们使用println时,是一定会调用flush()的;当我们直接使用print打印的时候如果(s.indexOf(’\n’) >= 0)(即打印的信息中没有换行符)那么我们就不会触发字符流的缓冲区的刷新,即flush(), 导致没有打印日志,而我添加了一个换行符或者使用println都是可以调用flush(),这样我们就可以打印啦。
感觉java的io流真的是独立的一门学问呀。有机会还是需要好好学习一下。
我是张诺然,一个有点齁挺的咸鱼(不懂啥意思就问问旁边的东北人吧,hiahiahiahia)