如果我运行以下测试,则会失败:
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开发人员,也许我在这里错过了一些东西。
答案 0 :(得分:20)
实例化异常时创建堆栈跟踪,而不是在抛出异常时创建。这是Java Language Specification
的指定行为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()
来刷新它。
另请注意,您应该使用Thread.currentThread().getStackTrace()
而不是new Exception().getStackTrace()
(不良风格)。
答案 1 :(得分:10)
异常的堆栈跟踪在异常创建时填充。否则就不可能捕获异常,处理它并重新抛出它。原始的堆栈跟踪会丢失。
如果您想强行执行此操作,则必须明确调用exception.fillInStackTrace()
。
答案 2 :(得分:1)
因为您没有要求重写该堆栈跟踪。它是在setUp方法中创建时设置的,您从未做过任何改变它的操作。
Exception类没有给你任何设置方法名称的机会;它是不可改变的。所以我不知道你可以在哪里重新设置方法名称,除非你想采取像反射一样令人发指的事情。
你的@Test注释没有告诉我你是使用JUnit还是TestNG,因为我看不到静态导入,但在任何一种情况下你都可以运行测试来查看是否通过使用抛出特定异常@Test注释中的“预期”成员。
答案 3 :(得分: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.
}
}
答案 4 :(得分:0)
我认为假设您不会实例化异常,除非您正在抛出异常,那么为什么要付出代价才能获得两次堆栈跟踪?
在抛出堆栈跟踪时很难重新创建堆栈跟踪,因为这只是将对象发送出去。
异常应该在throw之前完全设置,因此实例化的一部分是获取堆栈跟踪。
<强>更新强>
您可以致电fillInStackTrace()
来解决此问题。
答案 5 :(得分:0)
异常中的堆栈跟踪对应于“新”操作,没有别的。