我想创建一个例程来执行一些日志记录,执行其他操作,然后抛出异常。我希望从许多不同的地方调用这个例程。但是,在此例程中创建异常意味着它们将在其堆栈跟踪中具有此例程。我宁愿堆栈跟踪不报告此实用程序例程。有没有办法在调用者中创建Exception并将其传递给实用程序例程?
public static void die(String message) throws MyException {
log(message);
...
throw new MyException();
}
对于Perl / Java双语的程序员:我如何在Java中 carp ?
答案 0 :(得分:11)
您可以设置要抛出的任何异常的堆栈跟踪:
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
public class CarpTest {
public static void main(String[] args) {
new CarpTest().run();
}
public void run() {
methodThatCarps();
}
private void methodThatCarps() {
carp("Message");
}
private void carp(String message) {
RuntimeException e = new RuntimeException(message);
e.fillInStackTrace();
List<StackTraceElement> stack = new ArrayList<StackTraceElement>(Arrays.asList(e.getStackTrace()));
stack.remove(0);
e.setStackTrace(stack.toArray(new StackTraceElement[stack.size()]));
throw e;
}
}
这将在运行时打印以下堆栈跟踪:
Exception in thread "main" java.lang.RuntimeException: Message
at CarpTest.methodThatCarps(CarpTest.java:18)
at CarpTest.run(CarpTest.java:14)
at CarpTest.main(CarpTest.java:10)
请注意,如您所愿,“carp”方法不会出现在堆栈跟踪中。然而,堆栈跟踪的操作只能通过greates care来完成。
答案 1 :(得分:4)
如果你想使用Exception控制流程以及之后发生的事情,建议它覆盖fillInStackTrace()方法:
public Throwable fillInStackTrace() {
return this;
}
因此,您将拥有一个没有堆栈跟踪的Exception并且开销减少(填充堆栈跟踪需要时间)。
答案 2 :(得分:2)
无法从堆栈跟踪中删除throw函数。堆栈跟踪的整个目的是记录异常路径,因此允许函数退出将失败目的。
您可以更改此选项的唯一方法是返回异常而不是抛出异常。但这迫使你依赖于调用者知道抛出异常。
throw die("someReason).fillInStackTrace();
修改功能
public static Exception die(String message) {
log(message);
...
return new MyException();
}
编辑
添加了fillInStackTrace()调用以确保将堆栈重置为throw的点。
http://java.sun.com/j2se/1.3/docs/api/java/lang/Throwable.html#Throwable()
答案 3 :(得分:1)
嗯..你可以继承异常并覆盖其中的所有方法,并包装原始异常。在内部,使用包装异常中的getStackTrace()方法生成新的堆栈跟踪。我没有看过Exception的来源,但你可能甚至不必覆盖那么多方法。
答案 4 :(得分:1)
也许您应该考虑从不同的方向解决问题。而不是修改堆栈跟踪,为什么不只是让您的异常生成器方法(在您的示例中为die
)返回异常而不是抛出它?然后你的电话是throw die();
。
例如:
// revised die() method:
public static MyException die(String message){
log(message);
//...
return new MyException();
}
// calling code:
throw die("a-whoopsie daisy!");
现在,被授予,throw die()
可能看起来有点不美观,因此您可以将die()
重命名为newException()
或其他内容。但是满足了异常处理方法未在堆栈跟踪中显示的要求 - die()
(或newException()
)在抛出异常之前返回,因此不是要跟踪的堆栈的一部分。
编辑:我的不好。我花了很多时间使用C#,我忘了在Java中异常堆栈跟踪是在实例化时生成的,其中C#/ .NET异常堆栈跟踪是在抛出时生成的。
所以这个技巧将在C#中工作,但在Java中则不行。
答案 5 :(得分:1)
根据ordnungswidrig关于设置堆栈跟踪的说法,以及未知(谷歌)所说的覆盖fillInStackTrace()的内容,我创建了一个CarpException,它完全符合我的要求。请注意,我发现我必须删除四个堆栈跟踪帧而不是一个,因为我从Throwable和Exception中拾取帧。
public class CarpException extends Exception {
@Override
public Throwable fillInStackTrace() {
super.fillInStackTrace();
StackTraceElement[] origStackTrace = getStackTrace();
StackTraceElement[] newStackTrace = new StackTraceElement[origStackTrace.length - 4];
System.arraycopy(origStackTrace, 4, newStackTrace, 0, origStackTrace.length - 4);
setStackTrace(newStackTrace);
return this;
}
}
答案 6 :(得分:0)
没有办法......我曾经尝试做过这样的事情(我试图在AOP存在之前捕获堆栈跟踪来记录方法调用)。
创建异常时填充堆栈跟踪,并且本机完成。对于我正在处理的事情,我最终阅读了堆栈跟踪并查看了第二个元素,但这对你没有帮助......
答案 7 :(得分:0)
您可能会考虑让您的方法接收Logger作为方法的参数。这将允许您根据调用类控制日志记录输出。
我建议不要让你的异常排除这部分堆栈跟踪。当你离开并且一些新人来维护你的代码时,他们不会理解这种非标准的错误处理。
答案 8 :(得分:0)
为了能够分析它,你是否抛出堆栈跟踪?在这种情况下,您可以在Exception上调用getStackTrace()方法,该方法返回StackTraceElement []。在那里你可以过滤你不想要的元素(例如“die”方法)。