こんにちわ。しろです。
突然ですが、プログラムをかいていて、例外エラーが発生したときに、こんな感じの内容を見たことがあると思います。
Exception in thread "main" java.lang.NullPointerException
at exception/com.shirobetween.Main.method03(Main.java:26)
at exception/com.shirobetween.Main.method02(Main.java:21)
at exception/com.shirobetween.Main.method01(Main.java:16)
at exception/com.shirobetween.Main.main(Main.java:11)
これを見たときに、

うわぁ、意味分からないキライなやつきたな…。
見かたが分からないし、相談するのも恥ずかしい…。
どうしよう…。

はいはい。StackTraceね。
見かたが分からないけど、いつもどおり時間をかけて、一つ一つステップ実行して、どこで発生したか見つけるかー。
(2年目の頃の僕)
なんてことを考えてしまう方向けの記事となっています。
例外エラーが発生しても焦ることはないです。
重要なのは、Stackの仕組みと、StackTraceの読み方を理解することです。
そんなわけで今回は、StackTraceの内容から、例外エラー発生個所の特定と、原因箇所を特定する方法をご紹介します。
※本記事は、Javaを例にしていますが、どのプログラミング言語にも応用できる内容となっています。
また、例外エラーの基礎から学びたい方はこちらの記事が参考になるので、ぜひご覧くださいませ。
もくじ
はじめに
アプリケーションで障害が発生した際は、StackTraceの情報が原因究明・対策に大きな役割をはたします。
よって、StackTraceの見かたが分かるのと、分からないのとでは、対策までに要する時間に大きな差が生じます。
本記事を通して理解して頂ければ幸いです。
Stackとは
Stackとは、後入先出(LIFO)方式のデータ構造のことで、後に入れたものが先に取り出される仕組みのことです。
JVM上にも、Stackという領域があり、メソッドの呼び出しが格納されます。
解説
次のソースを例に解説します。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 |
package com.shirobetween; public class Main { /** * エントリポイント. * @param args 引数. */ public static void main(String[] args) { method01("あいうえお"); } private static void method01(String value) { method02(value); } private static void method02(String value) { method03(value); } private static void method03(String value) { System.out.println(value.trim()); } } |
このソースを実行すると、Stackには、メソッドの呼び出し順どおりにメソッドが格納されます。
- main
- method01
- method02
- method03
結果、Stackはこんな感じになります。
※先に呼び出されたものは、下に、そこから順に上に積み上げられてく感じです。

そして、メソッドの実行が完了する度に、次のように取り出されていきます。
冒頭でお話した、後入先出(LIFO)方式にもとづき、後に格納されたもの順に取り出されていく感じです。




Stackのまとめ
- JVMがもっている領域のこと。※他のプログラミング言語にもあります。
- 後に入れたものを先に取り出していく、後入先出(LIFO)方式のデータ構造。
- メソッドの呼び出し順で、データが格納されていく。
- 後から呼び出されたメソッドが完了する度に、取り出されていく。
StackTraceとは
Traceとは「追跡」を意味します。
つまり、StackTraceとはStackを追跡する情報のことを指します。
StackTraceの見かたと発生個所の特定
冒頭でかいたStackTraceをもう一度みてみましょう。
Exception in thread "main" java.lang.NullPointerException
at exception/com.shirobetween.Main.method03(Main.java:26)
at exception/com.shirobetween.Main.method02(Main.java:21)
at exception/com.shirobetween.Main.method01(Main.java:16)
at exception/com.shirobetween.Main.main(Main.java:11)
次のソースは、上記StackTraceを出力させたソースです。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 |
package com.shirobetween; public class Main { /** * エントリポイント. * @param args 引数. */ public static void main(String[] args) { method01(null); } private static void method01(String value) { method02(value); } private static void method02(String value) { method03(value); } private static void method03(String value) { System.out.println(value.trim()); } } |
繰り返しますが、Stackは後入先出(LIFO)方式のデータ構造です。
StackTraceの内容は、例外エラーがスローされた箇所を起点に、Stackからメソッドが取り出された順(追跡情報)を表したものです。
つまり、例外エラー発生個所は、StackTraceの最初に記されているように、ソースの26行目となります。
at exception/com.shirobetween.Main.method03(Main.java:26)
外部ライブラリ等を使用している場合は、一番上が外部ライブラリ内の情報だったりするので、基本的に一番上から順に見覚えのあるクラス名、メソッド名を探すと良いと思います。
原因の特定
例外エラー発生個所のmethod03では、NullPointerExceptionが発生しています。
引数のvalueがnullのため発生していると考えられるため、method03の呼び出しもとであるmethod02、さらにその呼び出しもとであるmethod01を見ると、それぞれ引数をそのまま渡しているだけなので原因とは考えられません。
最後にmainメソッドをみると、method01にnullを渡しているため、ここが原因箇所であることが分かります。
StackTraceを見ても以下のように原因箇所の行番号が載っていますね。
at exception/com.shirobetween.Main.main(Main.java:11)
対策
mainメソッドからmethod01を呼び出している箇所をnullから"あいうえお"のように、null以外の値を指定することで、対策完了です。
これでNullPointerExceptoinは回避できました。
1 2 3 4 |
public static void main(String[] args) { method01("あいうえお"); } |
StackTraceのまとめ
- Stackを追跡するための情報のこと。
- 例外エラーが発生した際に、発生個所と原因箇所を特定するために必要な情報。
- 一番上が発生個所で、そこから順番に見ていくと原因箇所が特定できる。
以上となります。
ここまで読んで頂き有難うございます。
次回は更なる応用をご紹介したいと思うので、気になる方は読んでいただけると幸いです。