【发布时间】:2014-07-10 23:38:01
【问题描述】:
我正在尝试创建一个帮助方法来消除对这样的代码的需要:
void foo() throws ExceptionA, ExceptionB, DefaultException {
try {
doSomething(); // that throws ExceptionA, ExceptionB or others
} catch (Exception e) {
if (e instanceof ExceptionA)
throw new ExceptionA("extra message", e);
if (e instanceof ExceptionB)
throw new ExceptionB("extra message", e);
throw new DefaultException("extra message", e);
}
}
问题是我需要同时在函数声明和函数体中维护 throws 列表。我正在寻找如何避免这种情况并使更改抛出列表足够,并且我的代码看起来像:
void foo() throws ExceptionA, ExceptionB, DefaultException {
try {
doSomething(); // that throws ExceptionA, ExceptionB or others
} catch (Exception e) {
rethrow(DefaultException.class, "extra message", e);
}
}
哪里 rethrow 方法足够聪明,可以从方法声明中识别 throws 列表。
这样,当我更改我的方法在 throws 列表中传播的类型列表时,我不需要更改正文。
以下是可以解决问题的函数。问题是因为它不知道它会抛出什么类型的异常,它的 throws 声明必须说 Exception,但如果它这样做了,那么将要使用它的方法也需要指定它,以及整个想法使用 throws 列表会下地狱。
有什么建议可以解决这个问题吗?
@SuppressWarnings("unchecked")
public static void rethrow(Class<?> defaultException, String message, Exception e) throws Exception
{
final StackTraceElement[] ste = Thread.currentThread().getStackTrace();
final StackTraceElement element = ste[ste.length - 1 - 1];
Method method = null;
try {
method = getMethod(element);
} catch (ClassNotFoundException ignore) {
// ignore the Class not found exception - just make sure the method is null
method = null;
}
boolean preserveType = true;
if (method != null) {
// if we obtained the method successfully - preserve the type
// only if it is in the list of the thrown exceptions
preserveType = false;
final Class<?> exceptions[] = method.getExceptionTypes();
for (Class<?> cls : exceptions) {
if (cls.isInstance(e)) {
preserveType = true;
break;
}
}
}
if (preserveType)
{
// it is throws exception - preserve the type
Constructor<Exception> constructor;
Exception newEx = null;
try {
constructor = ((Constructor<Exception>) e.getClass().getConstructor());
newEx = constructor.newInstance(message, e);
} catch (Exception ignore) {
// ignore this exception we prefer to throw the original
newEx = null;
}
if (newEx != null)
throw newEx;
}
// if we get here this means we do not want, or we cannot preserve the type
// just rethrow it with the default type
Constructor<Exception> constructor;
Exception newEx = null;
if (defaultException != null) {
try {
constructor = (Constructor<Exception>) defaultException.getConstructor();
newEx = constructor.newInstance(message, e);
} catch (Exception ignore) {
// ignore this exception we prefer to throw the original
newEx = null;
}
if (newEx != null)
throw newEx;
}
// if we get here we were unable to construct the default exception
// there lets log the message that we are going to lose and rethrow
// the original exception
log.warn("this message was not propagated as part of the exception: \"" + message + "\"");
throw e;
}
更新 1:
我可以使用RuntimeException 来避免需要抛出声明,但在这种情况下,我会丢失异常的类型,这是最重要的一点。
有什么办法可以解决这个问题?
【问题讨论】:
-
不要这样做!!!您将丢失异常堆栈跟踪信息,这是异常中一些最重要的信息。相反,抛出一个新异常(所有情况下的单个“MyFunctionFailedException”类),其中旧异常是“原因”。
-
如果我将前一个异常作为参数传递给新异常,我认为我不会这样做。
-
只需抛出“MyFunctionFailedException”。
-
这完全没有必要。如果你不能处理你所在的异常,就让它冒泡,直到你可以处理它。如果您可以通过抛出完全不同类型的异常来处理它,则抛出其他类型的异常。
-
重点是保留类型,但要使用更多细节扩展消息。我认为这很有意义。这个网站上有几个问题怎么做。