背景

最近在学习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)