14

次のテストを実行すると、失敗します。

public class CrazyExceptions {
    private Exception exception;

    @Before
    public void setUp(){
        exception = new Exception();
    }

    @Test
    public void stackTraceMentionsTheLocationWhereTheExceptionWasThrown(){
        String thisMethod = new Exception().getStackTrace()[0].getMethodName();
        try {
            throw exception;
        }
        catch(Exception e) {
            assertEquals(thisMethod, e.getStackTrace()[0].getMethodName());
        }
    }
}

次のエラーが発生します。

Expected :stackTraceMentionsTheLocationWhereTheExceptionWasThrown
Actual   :setUp

スタック トレースは完全に横たわっています。

例外がスローされたときにスタック トレースが書き換えられないのはなぜですか? 私は Java 開発者ではありません。ここで何かが足りないかもしれません。

4

6 に答える 6

21

スタック トレースは、例外がスローされたときではなく、例外がインスタンス化されたときに作成されます。これは、Java 言語仕様の指定された動作です。

20.22.1  public Throwable()

This constructor initializes a newly created Throwable object with null as
its error message string. Also, the method fillInStackTrace (§20.22.5) is
called for this object. 

....

20.22.5  public Throwable fillInStackTrace()

This method records within this Throwable object information about the
current state of the stack frames for the current thread. 

なぜそのようにしたのかはわかりませんが、仕様でそのように定義されている場合、少なくともさまざまな Java VM のすべてで一貫性があります。

exception.fillInStackTrace()ただし、手動で呼び出して更新できます。

また、 (bad style)を使用するThread.currentThread().getStackTrace()代わりに使用する必要があることに注意してください。new Exception().getStackTrace()

于 2009-11-08T14:59:41.420 に答える
10

例外のスタック トレースは、例外の作成時に書き込まれます。そうしないと、例外をキャッチして処理し、再スローすることができなくなります。元のスタック トレースは失われます。

これを強制したい場合は、exception.fillInStackTrace()明示的に呼び出す必要があります。

于 2009-11-08T15:03:04.800 に答える
1

そのスタック トレースの書き換えを要求しなかったからです。setUp メソッドで作成したときに設定され、何も変更していません。

Exception クラスでは、メソッド名を設定する機会はありません。それは不変です。したがって、リフレクションのような凶悪なことに頼りたくない限り、メソッド名をどこで再設定できるかを知る方法はありません。

@Test アノテーションでは、静的インポートが表示されないため、JUnit を使用しているか TestNG を使用しているかはわかりませんが、どちらの場合でも、"expected " @Test アノテーションのメンバー。

于 2009-11-08T14:58:44.393 に答える
1

スタック トラックを変更するために例外をスローしたくないか、安全に例外を再スローできませんでした。

public void throwsException() {
    throw new RuntimeException();
}

public void logsException() {
    try {
        throwsException();
    } catch (RuntimeException e) {
        e.printStrackTrace();
        throw e; // doesn't alter the exception.
    }
}

@Test
public void youCanSeeTheCauseOfAnException(){
    try {
        logsException();
    } catch(Exception e) {
        e.printStrackTrace(); // shows you the case of the exception, not where it was last re-thrown.
    }
}
于 2009-11-08T16:19:35.807 に答える
0

例外のスタック トレースは、「新しい」操作に対応しており、他には何もありません。

于 2009-11-08T20:18:27.487 に答える
0

例外をスローする過程にない限り、例外をインスタンス化しないという前提があると思います。スタック トレースを 2 回取得するために代償を払う必要はありません。

オブジェクトを送信するだけなので、スロー中にスタック トレースを再作成することは困難です。

例外はスローの前に完全にセットアップする必要があるため、インスタンス化の一部はスタック トレースを取得することです。

アップデート:

fillInStackTrace()これを解決するために電話することができます。

于 2009-11-08T14:59:29.377 に答える