Java
 Computer >> コンピューター >  >> プログラミング >> Java

Java 9のStackWalker APIでスタックフレームをクラス単位にフィルタリングする方法

StackWalker APIは、プログラムの実行中にスタックトレースの情報をストリームとして提供するAPIです。このAPIでは、仮想マシン(JVM)がスタック全体のスナップショットをキャプチャし、フィルタリング対象となる要素の配列を返します。walk()メソッドを使用することで、スタックフレームのスキップ・ドロップ・件数制限などの操作が可能です。

さらに、filter()メソッドを組み合わせれば、特定のクラスを基準にスタックフレームを絞り込むこともできます。「最初に一致したフレームだけを取得したい」場合はfindFirst()を、「一致するすべてのフレームを取得したい」場合はcollect(Collectors.toList())を使用します。

なお、getDeclaringClass()でフレームの宣言クラスを参照するには、StackWalker.getInstance()の引数にStackWalker.Option.RETAIN_CLASS_REFERENCEを指定する必要があります。

以下の例では、StackWalker APIを使ってスタックフレームをクラス単位でフィルタリングする方法を示します。

コード例

import java.lang.StackWalker.StackFrame;
import java.util.*;
import java.util.stream.*;

public class StackWalkerFilterTest {
    public static void main(String args[]) {
        final List<Class> filterClasses = new ArrayList<>();
        filterClasses.add(StackWalkerFilterTest.class);

        System.out.println("--- filter Frame by Class >> get first matching frame ---");
        Optional<StackFrame> frameByClass = findFrameByClass(filterClasses);
        System.out.println(frameByClass.toString());

        System.out.println("--- filter Frame by Class >> get all matching frames ---");
        List<StackFrame> framesByClass = findAllFramesByClass(filterClasses);
        System.out.println(framesByClass);
    }

    // 最初に一致したフレームを1件だけ取得する
    private static Optional<StackFrame> findFrameByClass(List<Class> filterClasses) {
        return StackWalker.getInstance(StackWalker.Option.RETAIN_CLASS_REFERENCE)
            .walk(s -> s.filter(f -> filterClasses.contains(f.getDeclaringClass()))
                        .findFirst());
    }

    // 一致するすべてのフレームをリストとして取得する
    private static List<StackFrame> findAllFramesByClass(List<Class> filterClasses) {
        return StackWalker.getInstance(StackWalker.Option.RETAIN_CLASS_REFERENCE)
            .walk(s -> s.filter(f -> filterClasses.contains(f.getDeclaringClass()))
                        .collect(Collectors.toList()));
    }
}

実行結果

--- filter Frame by Class >> get first matching frame ---
Optional[StackWalkerTest.findFrameByClass(StackWalkerTest.java:20)]
--- filter Frame by Class >> get all matching frames ---
[StackWalkerTest.findAllFramesByClass(StackWalkerTest.java:23), StackWalkerTest2.main(StackWalkerTest.java:15)]

ポイント解説

  • RETAIN_CLASS_REFERENCE: StackFrame#getDeclaringClass()で宣言クラスを取得できるようにするオプションです。指定しない場合、クラスオブジェクトへのアクセス時に例外が発生します。
  • walk(): スタックフレームのStreamを受け取り、遅延評価で処理を行うメソッドです。全スタックを一括でスナップショット化するため、従来のThread.getStackTrace()よりも効率的にフィルタリングできます。
  • filter() + findFirst(): 条件に合う最初のフレームのみをOptionalとして返すため、呼び出し元の特定などに便利です。
  • filter() + collect(): 条件に合うすべてのフレームをListとして収集できます。ログ出力やデバッグ用途に活用できます。
  1. JavaのStackクラス徹底解説!LIFO構造の基本と主要メソッドの使い方

    Javaにおけるスタック(Stack)は、「後入れ先出し(LIFO: Last-In, First-Out)」と呼ばれるデータ構造です。スタックから最初に取り出されるのは、最後に追加された要素です。新しい要素は常にスタックの末尾に追加され、JavaのStackクラスはVectorクラスを継承しています。 Javaのスタックとは プログラミングにおいて、スタックはデータを格納するための後入れ先出し(LIFO)のデータ構造です。リスト内の対称性を検証したり、リストの順序を逆転させたりするなど、さまざまな場面で活躍します。 Javaのコレクションフレームワークには、スタックを構築するためのSt

  2. 【Android開発】Year APIクラスを使って現在の年を取得・表示する方法

    はじめにこのチュートリアルでは、java.timeパッケージに含まれるYear APIクラスを使って、Androidアプリで現在の年を取得し画面に表示する方法を解説します。Calendarクラスなどを直接操作するよりも直感的に年情報を扱えるため、日付処理を行うアプリの開発に役立ちます。ステップ1:新規プロジェクトを作成するAndroid Studioを開き、File ⇒ New Project を選択します。必要な項目をすべて入力して、新しいプロジェクトを作成しましょう。ステップ2:レイアウトファイル(activity_main.xml)を編集するres/layout/activit