我正在编写一个基本上做一件简单事情的方法,记录错误消息并使用相同的错误消息抛出运行时异常。我希望它能够抛出RuntimeException的任何子异常。我得到的方法是:
public static <T extends RuntimeException> void logErrorAndThrowException(Logger logger, String errorMessage, Class<T> exceptionClazz) throws T {
logger.error(errorMessage);
RuntimeException runtimeException = new RuntimeException(errorMessage);
throw exceptionClazz.cast(runtimeException); // Not work!!
}
我定义了这个例外:
public final class MyException extends RuntimeException {
public MyException() {
}
public MyException(String message) {
super(message);
}
public MyException(Throwable cause) {
super(cause);
}
public MyException(String message, Throwable cause) {
super(message, cause);
}
}
然后我使用以下方法调用该方法:
logErrorAndThrowException(logger, "This is an error message", MyException.class);
上面的注释行将因强制转换异常而失败。然后我尝试了另一种实现:
public static <T extends RuntimeException> void logWarningAndThrowException(Logger logger, String errorMessage, Class<T> exceptionClazz) throws T {
logger.error(errorMessage);
try {
throw exceptionClazz.newInstance();
} catch (InstantiationException e) {
// handle
} catch (IllegalAccessException e) {
// handle
}
}
通过这个实现,我只能调用异常的no-arg构造函数,因此无法设置错误消息。
任何人都可以帮忙吗?
答案 0 :(得分:5)
在实例化之前,首先需要为异常类获取适当的构造函数。当你这样做时:
throw exceptionClazz.cast(runtimeException); // Not work!!
这不起作用,因为您的类是RuntimeException
的子类。
你可以这样做:
final Constructor<T> c = exceptionClazz.getConstructor(String.class);
throw c.newInstance(theMessage);
但是,真的,不要:你必须处理这两种反射方法的所有可能的例外......
另一个不涉及反射的解决方案是拥有一个界面,例如:
public interface ExceptionCreator<T extends RuntimeException>
{
T doException(String whatsWrong);
}
然后你有IdentityHashMap
:
// IdentityHashMap because all Class objects are singletons
private static final Map<Class<? extends RuntimeException>, ExceptionCreator<?>> MAP
= new IdentityHashMap<>;
// fill the map in a static initialization block
您的方法将是:
public static <T extends RuntimeException> void logErrorAndThrowException(Logger logger,
String errorMessage, Class<T> exceptionClazz) throws T
{
logger.error(errorMessage);
// Note: no checks for null here. If null, just throw a "plain" RuntimeException
throw MAP.get(exceptionClazz).doException(errorMessage);
}
答案 1 :(得分:1)
您可以在不抛出异常的情况下创建异常。由于您无需为方法知道该类,因此请直接使用RuntimeException作为参数。试图在这里使用反射是没有意义的。
public static <T extends RuntimeException> void logErrorAndThrowException(Logger logger, T exception) throws T {
logger.error(exception.getMessage());
throw exception; // works !!! ;-)
}