35

リフレクションまたはいくつかの素晴らしい API を介して現在の行番号を動的に取得する Java の方法はありますか? 例外が発生した場合と同様に、次のように行番号がスタック トレースに出力されます。

at weblogic.rmi.cluster.ClusterableRemoteRef.invoke(ClusterableRemoteRef.java:348)

以下のコードのように印刷またはログ記録する方法はありますか?

log.error("Error in: " + this.getClass.getName() + "at line #"+ this.getClass.getActualLine());

なぜ単純に行番号を出力しないのですか? 特定の log.error() メソッド呼び出しの前にコードが削除または追加される可能性があるためです。

4

5 に答える 5

52

を作成しThrowableて使用できStackTraceElementsます。

  System.err.println(new Throwable().getStackTrace()[0].getLineNumber());

@Joachimが言ったように、次Thread.getStackTrace()のように使用することもできます

  System.err.println(Thread.currentThread().getStackTrace()[1].getLineNumber());

2 番目の方法では多少異なる配列が返されることに注意してください。最初の要素としてそれ自体への呼び出しが含まれているため、インデックス 1 の配列要素を使用して現在の行番号を取得する必要があります。getStackTrace()

@Joachimの回答からのロギングとパフォーマンスに関するコメントにも注意してください。

于 2013-07-04T14:57:24.450 に答える
16

まず第一に、もしあればロギングパターン(またはレイアウト、またはロギングフレームワークがその部分を呼び出すもの)がこれを行う必要があります。コード内のロガー呼び出しは、実際のビジネス情報のみを書き込む必要があります。ロガーによって追加される場所に関する情報。

次に: そのような操作を行うには (時間の点で) コストがかかります。これは、Java が最適化されていないためです。実行時に、JVM はその状態を検査し、デバッグ情報をロード/解析し、特定の命令に対応する行番号を見つける必要があります。そのため、通常、この種の情報は、例外が発生したときにのみ提供されます (この場合、既に問題が発生しており、通常は費やす時間に見合うだけの価値があることがわかっています)。

最後になりましたが、何らかの理由でその情報が自分で必要な場合は、その情報を使用Thread.getStackTrace()して調べることができますStackTraceElement

于 2013-07-04T14:57:36.423 に答える
14

Thread.currentThread().getStackTrace() メソッドを使用して、次のように連携して最初のメソッドを呼び出したコードの行番号を生成する一連の関数を作成できました。

/** @return The line number of the code that ran this method
 * @author Brian_Entei */
public static int getLineNumber() {
    return ___8drrd3148796d_Xaf();
}

/** This methods name is ridiculous on purpose to prevent any other method
 * names in the stack trace from potentially matching this one.
 * 
 * @return The line number of the code that called the method that called
 *         this method(Should only be called by getLineNumber()).
 * @author Brian_Entei */
private static int ___8drrd3148796d_Xaf() {
    boolean thisOne = false;
    int thisOneCountDown = 1;
    StackTraceElement[] elements = Thread.currentThread().getStackTrace();
    for(StackTraceElement element : elements) {
        String methodName = element.getMethodName();
        int lineNum = element.getLineNumber();
        if(thisOne && (thisOneCountDown == 0)) {
            return lineNum;
        } else if(thisOne) {
            thisOneCountDown--;
        }
        if(methodName.equals("___8drrd3148796d_Xaf")) {
            thisOne = true;
        }
    }
    return -1;
}

お役に立てれば!これらをユーティリティ クラスに配置して、邪魔にならないようにしますが、簡単にアクセスできるようにします。2 番目のメソッドは、常に正しく動作するように、最初のメソッド以外のメソッドが呼び出されないようにするためにプライベートです。

于 2014-10-16T17:29:40.637 に答える
3

次のスニペットを使用して例外行番号を取得することもできます。util クラスで次の util メソッドを使用します。

 public static int getExceptionLineNumber(Exception e, String methodNameExp) 
 {
    StackTraceElement ele = Arrays.stream(e.getStackTrace()).filter(o -> o.getMethodName().equals(methodNameExp)).findAny().orElse(null);
    if(ele != null){
        return ele.getLineNumber();
    }
    return -1;
 }

catch ブロックから、以下のように呼び出すことができます:

catch (Exception e){
        logger.info("Exception line number "+ Util.getExceptionLineNumber(e, new Object(){}.getClass().getEnclosingMethod().getName()));
    }

これがうまくいくことを願っています!:)

于 2018-01-19T11:45:22.660 に答える