1. スタックトレースの取得

スタックトレースの取得

Java プログラミング言語は、プログラマがプログラム内で何が起こっているかに関する情報を取得するためのさまざまな方法を提供します。言葉だけではありません。

たとえば、C++ プログラムはコンパイルされると、マシン コードが詰まった 1 つの大きなファイルになります。実行時にプログラマが利用できるのは、現在実行中のマシン コードを含むメモリ ブロックのアドレスだけです。それほど多くはないと言えます。

しかし、Java の場合、プログラムがコンパイルされた後でも、クラスはクラスのままであり、メソッドと変数は消えず、プログラマはプログラム内で何が起こっているかに関する情報を取得する多くの方法を持っています。

スタックトレース

たとえば、プログラムの実行中の時点で、現在実行されているメソッドのクラスと名前を確認できます。1 つのメソッドだけではなく、現在のメソッドからそのメソッドに戻るメソッド呼び出しのチェーン全体に関する情報を取得できますmain()

現在のメソッド、そのメソッドを呼び出したメソッド、そのメソッドを呼び出したメソッドなどから構成されるリストを スタック トレース と呼びます。次のステートメントで取得できます。

StackTraceElement[] methods = Thread.currentThread().getStackTrace();

2 行で記述することもできます。

Thread current = Thread.currentThread();
StackTraceElement[] methods = current.getStackTrace();

currentThread()クラスの静的メソッドは、現在のスレッド、つまり現在の実行スレッドに関する情報を含むオブジェクトThreadへの参照を返しますThreadスレッドの詳細については、 Java Coreクエストのレベル 17 と 18 で学習します。

このThreadオブジェクトにはメソッドがありgetStackTrace()、オブジェクトの配列を返しますStackTraceElement。各オブジェクトにはメソッドに関する情報が含まれています。これらすべての要素をまとめると、スタック トレースが形成されます。

例:

コード
public class Main
{
   public static void main(String[] args)
   {
      test();
   }

   public static void test()
   {
      Thread current = Thread.currentThread();
      StackTraceElement[] methods = current.getStackTrace();

      for(var info: methods)
         System.out.println(info);
   }
}
コンソール出力
java.base/java.lang.Thread.getStackTrace(Thread.java:1606)
Main.test(Main.java:11)
Main.main(Main.java:5)

この例のコンソール出力からわかるように、getStackTrace()メソッドは 3 つの要素の配列を返しました。

  • getStackTrace()Threadクラスのメソッド
  • test()Mainクラスのメソッド
  • main()Mainクラスのメソッド

このスタック トレースから、次のことが結論付けられます。

  • このメソッドは、Main.java ファイルの 11 行目のメソッドThread.getStackTrace()によって呼び出されました。Main.test()
  • このメソッドは、Main.java ファイルの 5 行目のメソッドMain.test()によって呼び出されました。Main.main()
  • 誰もMain.main()メソッドを呼び出しませんでした。これは一連の呼び出しの最初のメソッドです。

ちなみに、画面に表示されたのは入手可能な情報の一部のみです。StackTraceElementそれ以外はすべてオブジェクトから直接取得できます



2.StackTraceElement

その名前が示すように、このクラスはスタック トレース要素、つまり .html 内の 1 つのメソッドStackTraceElementに関する情報を格納するために作成されました。stack trace

このクラスには次のインスタンス メソッドがあります。

方法 説明
String getClassName()
クラスの名前を返します
String getMethodName()
メソッドの名前を返します
String getFileName()
ファイルの名前を返します (1 つのファイルに複数のクラスを含めることができます)
int getLineNumber()
メソッドが呼び出されたファイル内の行番号を返します。
String getModuleName()
モジュールの名前を返します (これは の場合がありますnull)。
String getModuleVersion()
モジュールのバージョンを返します (これは の可能性がありますnull)。

これらは、現在の呼び出しスタックに関するより完全な情報を取得するのに役立ちます。

コード コンソール出力 ノート
public class Main
{
   public static void main(String[] args)
   {
      test();
   }

   public static void test()
   {
      Thread current = Thread.currentThread();
      StackTraceElement[] methods = current.getStackTrace();

      for(StackTraceElement info: methods)
      {
         System.out.println(info.getClassName());
         System.out.println(info.getMethodName());

         System.out.println(info.getFileName());
         System.out.println(info.getLineNumber());

         System.out.println(info.getModuleName());
         System.out.println(info.getModuleVersion());
         System.out.println();
      }
   }
}
java.lang.Thread
getStackTrace
Thread.java
1606
java.base
11.0.2

Main
test
Main.java
11
null
null

Main
main
Main.java
5
null
null
クラス名
メソッド名
ファイル名 行
番号 モジュール名 モジュールバージョン クラス名 メソッド名 ファイル名 行番号 モジュール名 モジュールバージョン クラス名 メソッド名 ファイル名 行 番号 モジュール名 モジュールバージョン

















3. 積み重ねる

スタック トレースが何であるかはすでにわかりましたが、スタック(スタック クラス) とは何でしょうか?

スタックは、要素を追加したりそこから要素を取得したりできるデータ構造です。その際、要素は末尾からのみ取得できます。まず最後に追加された要素を取得し、次に最後から 2 番目に追加された要素を取得します。

名前スタック自体は、紙の束をどのように操作するかのように、この動作を示唆しています。シート 1、2、および 3 をスタックに置いた場合は、逆の順序で取り出す必要があります。最初に 3 番目のシート、次に 2 番目のシート、そして最初のシートだけを取り出す必要があります。

Java には、同じ名前と動作を持つ特別な Stack コレクション クラスもあります。このクラスは多くの動作を およびArrayListと共有しますLinkedList。ただし、スタック動作を実装するメソッドもあります。

メソッド 説明
T push(T obj)
obj要素をスタックの先頭に追加します
T pop()
スタックの最上位から要素を取得します (スタックの深さが減少します)。
T peek()
スタックの先頭にある項目を返します (スタックは変更されません)。
boolean empty()
コレクションが空かどうかを確認します
int search(Object obj)
コレクション内のオブジェクトを検索し、そのオブジェクトを返します。index

例:

コード スタックの内容 (スタックの一番上が右側)
Stack<Integer> stack = new Stack<Integer>();
stack.push(1);
stack.push(2);
stack.push(3);
int x = stack.pop();
stack.push(4);
int y = stack.peek();
stack.pop();
stack.pop();

[1]
[1, 2]
[1, 2, 3]
[1, 2]
[1, 2, 4]
[1, 2, 4]
[1, 2]
[1]

スタックはプログラミングでよく使用されます。ということで、これは便利なコレクションです。



4. 例外処理時のスタックトレースの表示

メソッド呼び出しのリストがスタック トレースと呼ばれるのはなぜですか? なぜなら、メソッドのリストをメソッド名が記載された紙の束と考えると、次のメソッドを呼び出すときに、そのメソッドの名前が記載されたシートがスタックに追加されるからです。そして次の紙がその上に置かれ、というように続きます。

メソッドが終了すると、スタックの一番上のシートが削除されます。スタックの中央からシートを削除するには、その上にあるシートをすべて削除する必要があります。同様に、呼び出したすべてのメソッドを終了することなく、一連の呼び出しの途中でメソッドを終了することはできません。

例外

スタックのもう 1 つの興味深い用途は、例外処理時です。

プログラムでエラーが発生し、例外がスローされると例外には現在のスタック トレースが含まれます。このスタック トレースは、メイン メソッドから始まり、エラーが発生したメソッドで終わるメソッドのリストで構成されます。例外がスローされた行もあります。

このスタック トレースは例外内に保存され、次のメソッドを使用して例外から簡単に取得できます。StackTraceElement[] getStackTrace()

例:

コード ノート
try
{
   // An exception may occur here
}
catch(Exception e)
{
   StackTraceElement[] methods = e.getStackTrace()
}




例外をキャッチする

エラーが発生したときに存在していたスタック トレースを取得します。

これはクラスのメソッドであるThrowableため、そのすべての子孫 (つまり、すべての例外) がこのgetStackTrace()メソッドを持ちます。すごく便利ですね。

例外のスタック トレースを表示する

ちなみに、このThrowableクラスにはスタック トレースを操作するための別のメソッドがあります。これは、例外内に格納されているすべてのスタック トレース情報を表示するメソッドです。と呼ばれますprintStackTrace()

非常に便利なことに、どの例外でも呼び出すことができます。

例:

コード
try
{
   // An exception may occur here
}
catch(Exception e)
{
   e.printStackTrace();
}
コンソール出力
java.base/java.lang.Thread.getStackTrace(Thread.java:1606)
Main.test(Main.java:11)
Main.main(Main.java:5)