有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

java是一个异步的Throwable类的printStackTrace()

我测试了一些代码来读取类路径中可用的文件,但最终得到了一些关于Throwable类的printStackTrace()方法的有趣的东西

代码如下:

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.net.URISyntaxException;
import java.net.URL;

import org.apache.commons.io.FileUtils;
import org.apache.commons.io.IOUtils;

public class Main {

    public static void main(String[] args) throws IOException, URISyntaxException {
        try {
            System.out.println("before-test1");
            test1(); // will throw exception
            System.out.println("after-test1");
        } catch (Exception e) {
            System.out.println("entering catch-1");
            e.printStackTrace();
            System.out.println("exiting catch-1");
        }

        try {
            System.out.println("before-test2");
            test2();
            System.out.println("after-test2");
        } catch (Exception e) {
            e.printStackTrace();
        }

        try {
            System.out.println("before-test3");
            test3();
            System.out.println("after-test3");
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    private static void test1() throws IOException {
        String path = "classpath:/test.txt";

        File file = new File(path);

        String content = FileUtils.readFileToString(file, "UTF-8");

        System.out.println("content = " + content);
    }

    private static void test2() throws IOException {
        String path = "/test.txt";
        InputStream in = Main.class.getResourceAsStream(path);

        String content = IOUtils.toString(in);
        System.out.println("content = " + content);
    }

    private static void test3() throws IOException, URISyntaxException {
        String path = "/test.txt";

        URL url = Main.class.getResource(path);

        File file = new File(url.toURI());

        String content = FileUtils.readFileToString(file, "UTF-8");

        System.out.println("content = " + content);
    }

}

测试的内容。txt仅为一行,如下所示:

anil bharadia

现在,该程序的预期输出如下所示:

before-test1
entering catch-1
java.io.FileNotFoundException: classpath:\test.txt (The filename, directory name, or volume label syntax is incorrect)
    at java.io.FileInputStream.open(Native Method)
    at java.io.FileInputStream.<init>(Unknown Source)
    at org.apache.commons.io.FileUtils.readFileToString(FileUtils.java:874)
    at Main.test1(Main.java:50)
    at Main.main(Main.java:16)
exiting catch-1
before-test2
content = anil bharadia
after-test2
before-test3
content = anil bharadia
after-test3

当我第一次运行这个类时,我得到了与上面相同的输出

然后在我再次运行同一个类之后,我得到了以下输出:

before-test1
entering catch-1
exiting catch-1
before-test2
content = anil bharadia
after-test2
before-test3
java.io.FileNotFoundException: classpath:\test.txt (The filename, directory name, or volume label syntax is incorrect)
    at java.io.FileInputStream.open(Native Method)
    at java.io.FileInputStream.<init>(Unknown Source)
    at org.apache.commons.io.FileUtils.readFileToString(FileUtils.java:874)
    at Main.test1(Main.java:50)
    at Main.main(Main.java:16)
content = anil bharadia
after-test3

在上面的输出中,堆栈跟踪是在调用它的catch块执行之后以及test2()的执行结束之后打印的

所以我认为printStackTrace()方法在某种程度上是异步的

我试图查找printStackTrace()的源代码,但发现以下代码对我没有帮助:

public void printStackTrace(PrintStream s) {
        synchronized (s) {
            s.println(this);
            StackTraceElement[] trace = getOurStackTrace();
            for (int i=0; i < trace.length; i++)
                s.println("\tat " + trace[i]);

            Throwable ourCause = getCause();
            if (ourCause != null)
                ourCause.printStackTraceAsCause(s, trace);
        }
    }

我试着用谷歌搜索,但没有找到任何解释

当我一次又一次尝试运行同一个类时,在许多情况下,我还发现了以下输出:

java.io.FileNotFoundException: classpath:\test.txt (The filename, directory name, or volume label syntax is incorrect)
    at java.io.FileInputStream.open(Native Method)
    at java.io.FileInputStream.<init>(Unknown Source)
    at org.apache.commons.io.FileUtils.readFileToString(FileUtils.java:874)
    at Main.test1(Main.java:50)
    at Main.main(Main.java:16)
before-test1
entering catch-1
exiting catch-1
before-test2
content = anil bharadia
after-test2
before-test3
content = anil bharadia
after-test3

这让我思考得更多,比如调用test1()方法之前堆栈跟踪是如何打印的。这是不可能的


共 (3) 个答案

  1. # 1 楼答案

    System.out.println("after-test3");将输入写入out流,并且printStackTrace()方法将输入写入System.err

    public void printStackTrace() {
        printStackTrace(System.err);
    }
    
  2. # 2 楼答案

    stacktrace打印到另一个流——它们被打印到错误流,而不是标准输出流。这就是为什么有时它们会以不同的顺序显示

  3. # 3 楼答案

    错误转到System.err流。 正常输出进入System.out

    这些流是由不同的线程编写的,所以如果再次运行,也可以预期输出中的序列不同

    要获得所需的输出,您需要更改为:

    e.printStacktrace(System.out);
    

    这将把输出重定向到系统。外流