Java - Stack trace出力する方法 (Throwable、Exception)

JavaでThrowableオブジェクトでコールスタックを出力することができます。 現在のコードの位置まで任意の関数を経てきたのかを示すことをStack traceと呼ばれます。

Throwableの次のメソッドを使用して、Traceを取得または出力することができます。

// Throwable.java
public void printStackTrace()
public void printStackTrace(PrintStream s)
public StackTraceElement[] getStackTrace()

Javaコードを見ると、ExceptionクラスはThrowableクラスを継承します。 そのため、ExceptionオブジェクトもThrowableのメソッドを利用することができます。

public class Exception extends Throwable {
  ...
}

Stack trace出力

通常try-catchパターンで例外処理をします。 ここで Exception.printStackTrace()を呼び出すと、ログにStack traceが出力されます。

try {
    Exception e = new Exception();
    e.initCause(new IOException("No space memory"));
    throw e;
} catch(Exception e) {
    e.printStackTrace();
}

結果

java.lang.Exception
	at example.StackTrace$AAA.ccc(StackTrace.java:21)
	at example.StackTrace$AAA.bbb(StackTrace.java:14)
	at example.StackTrace$AAA.aaa(StackTrace.java:10)
	at example.StackTrace.main(StackTrace.java:47)
Caused by: java.io.IOException: No space memory
	at example.StackTrace$AAA.ccc(StackTrace.java:22)
	... 3 more

Throwableは printStackTrace(PrintWriter s)メソッドもサポートします。

次のようにPrintWriterを引数として渡してTraceをPrintWriterに追加することができます。

try {
    Exception e = new Exception();
    e.initCause(new IOException("No space memory"));
    throw e;
} catch(Exception e) {
    StringWriter sw = new StringWriter();
    PrintWriter pw = new PrintWriter(sw);

    pw.append("+++Start printing trace:\n");
    e.printStackTrace(pw);
    pw.append("---Finish printing trace");
    System.out.println(sw.toString());
}

結果

+++Start printing trace:
java.lang.Exception
	at example.StackTrace$AAA.fff(StackTrace.java:50)
	at example.StackTrace$AAA.bbb(StackTrace.java:22)
	at example.StackTrace$AAA.aaa(StackTrace.java:12)
	at example.StackTrace.main(StackTrace.java:75)
Caused by: java.io.IOException: No space memory
	at example.StackTrace$AAA.fff(StackTrace.java:51)
	... 3 more
---Finish printing trace

ExceptionなくStack trace出力

上記のコードは、Exceptionが発生する場合にのみ使用することができます。

ただ、デバッグの目的でTraceを出力したい場合は以下のようにThrowableオブジェクトを作成し、 printStackTrace()を呼び出します。 throwするものではないため、ログのみが出力されて、オブジェクトが消滅します。

// print stack trace
(new Throwable()).printStackTrace();

結果

java.lang.Throwable
	at example.StackTrace$AAA.eee(StackTrace.java:39)
	at example.StackTrace$AAA.bbb(StackTrace.java:16)
	at example.StackTrace$AAA.aaa(StackTrace.java:10)
	at example.StackTrace.main(StackTrace.java:47)

Traceを出力せずにStringとしてインポート

Traceログに出力せずにStringオブジェクトとして取得することができます。

以下のように getStackTrace()を呼び出すと、 StackTraceElement配列を返します。 StackTraceElementオブジェクトは、Traceの情報を持っており、Stackが多く蓄積されるほど、配列の長さも長くなります。 このオブジェクトのアイテムをStringに出力することができます。

// get stack trace and print
StackTraceElement[] stacks = (new Throwable()).getStackTrace();
for (StackTraceElement element : stacks) {
    System.out.println(element);
}

結果

example.StackTrace$AAA.ddd(StackTrace.java:31)
example.StackTrace$AAA.bbb(StackTrace.java:15)
example.StackTrace$AAA.aaa(StackTrace.java:10)
example.StackTrace.main(StackTrace.java:47)

次のコードは、上記の例で使用したコードです。

package example;


import java.io.IOException;
import java.io.PrintWriter;
import java.io.StringWriter;

public class StackTrace {

    static class AAA {
        void aaa() {
            bbb();
        }

        void bbb() {
            ccc();
            sleep(1000);
            ddd();
            sleep(1000);
            eee();
            sleep(1000);
            fff();
        }

        void ccc() {
            try {
                Exception e = new Exception();
                e.initCause(new IOException("No space memory"));
                throw e;
            } catch(Exception e) {
                e.printStackTrace();
            }
        }

        void ddd() {
            // get stack trace and print
            StackTraceElement[] stacks = (new Throwable()).getStackTrace();
            for (StackTraceElement element : stacks) {
                System.out.println(element);
            }
        }

        void eee() {
            // print stack trace
            (new Throwable()).printStackTrace();
        }

        void fff() {
            try {
                Exception e = new Exception();
                e.initCause(new IOException("No space memory"));
                throw e;
            } catch(Exception e) {
                StringWriter sw = new StringWriter();
                PrintWriter pw = new PrintWriter(sw);

                pw.append("+++Start printing trace:\n");
                e.printStackTrace(pw);
                pw.append("---Finish printing trace");
                System.out.println(sw.toString());
            }
        }

        void sleep(long ms) {
            try {
                Thread.sleep(ms);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

    public static void main(String args[]) {
        AAA a = new AAA();
        a.aaa();
    }
}

参考

codechachaCopyright ©2019 codechacha