我创建了Exception xml并动态创建并抛出异常。
<exception-mappings>
<exception-mapping key="exceptionkey1">
<class-name>com.package.CheckedException</class-name>
<message>Checked Exception Message</message>
</exception-mapping>
<exception-mapping key="exceptionkey2">
<class-name>com.package.UnCheckedException</class-name>
<message>UnChecked Exception Message</message>
</exception-mapping>
我根据异常键使用反射动态创建异常对象。
public static void throwException(final String key) throws CheckedException, UncheckedException {
ExceptionMapping exceptionMapping = exceptionMappings.getExceptionMappings().get(key);
if (exceptionMapping != null) {
try {
Class exceptionClass = Class.forName(exceptionMapping.getClassName());
try {
throw ()exceptionClass.newInstance(); // line X
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
}
我想知道哪一个类在X行进行类型转换,这样我就不需要使用If / else了。背后的原因我不想使用if else,有可能在将来可能会添加新类,并且我不希望每次添加新异常时都更改此代码。
我的基本逻辑是我的服务层将抛出CheckedException或UncheckedException。如果抛出CheckedException,它将由我的Web层处理。此外,我不能抛出超级父类Exception或Throwable,因为我的web层只捕获CheckedException。如果抛出UncheckedException,它将显示异常页面。
请帮助我,因为我无法继续前进。
编辑:也接受任何其他解决方案。
答案 0 :(得分:10)
嗯,以科学的名义,你可以做到这一点。我会建议这样做吗?绝不是。我自己会做这样的远程事吗?可能不是。
public class ExceptionFactory {
public static void throwException(String className)
throws CheckedException, UncheckedException {
Class<?> exceptionClass;
try {
exceptionClass = Class.forName(className);
} catch (ClassNotFoundException e) {
throw new IllegalArgumentException(e);
}
try {
if (CheckedException.class.isAssignableFrom(exceptionClass)) {
throw exceptionClass.asSubclass(CheckedException.class)
.newInstance();
} else if (UncheckedException.class
.isAssignableFrom(exceptionClass)) {
throw exceptionClass.asSubclass(UncheckedException.class)
.newInstance();
} else {
throw new IllegalArgumentException(
"Not a valid exception type: "
+ exceptionClass.getName());
}
} catch (InstantiationException | IllegalAccessException e) {
throw new IllegalStateException(e);
}
}
public static void main(String... args) {
try {
throwException("CheckedException");
} catch (CheckedException e) {
System.out.println(e);
} catch (UncheckedException e) {
System.out.println(e);
}
}
}
class CheckedException extends Exception {
}
class UncheckedException extends Exception {
}
答案 1 :(得分:2)
我不明白这家工厂的意义。即使你让它工作(你可以通过将它抛出的所有异常作为单个祖先类的子类),它的用法将是这样的:
....
if (somethingInWrong) {
ExceptionFactory.throwException("SomeKey");
}
....
对于每个键,您仍然需要创建要映射到它的异常类。让我们说SomeKeyException
是映射到&#34; SomeKey&#34;。
在这种情况下,简单地写一下它的类型更安全:
....
if (somethingInWrong) {
throw new SomeKeyException();
}
....
这样编译器会检查您是否正在创建它实际知道的异常类。如果您使用Factory,则可能会使用一些非有效键的String,并且编译器无法对其执行任何操作。只有在运行时,Factory才能找到映射到无效密钥的异常。
答案 2 :(得分:2)
一些调整:
public static void throwException(final String key) throws Throwable {
ExceptionMapping exceptionMapping =
exceptionMappings.getExceptionMappings().get(key);
if (exceptionMapping != null) {
try {
Class<Throwable> exceptionClass =
(Class<Throwable>)Class.forName(exceptionMapping.getClassName());
try {
throw exceptionClass.cast( exceptionClass.newInstance() ); // line X
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
}
答案 3 :(得分:1)
没有必要使用反射(正如我上面评论you shouldn't use reflection unless you really have to...)。
您可以将例外类实现为:
class MyExceptions {
static void myExceptionsThrower(String key) throws Exception {
if("illegalstate".equals(key)) {
throw new IllegalStateException("that's my IllegalStateException bro!");
}
else if("illegalaccess".equals(key)) {
throw new IllegalAccessException("that's my IllegalAccessException bro!");
}
// etc...
}
}
并将其用于:
MyExceptions.myExceptionsThrower(key);
答案 4 :(得分:1)
这是我进入这场德比赛的进军。 : - )
其他答案评论这是否是一个合理的设计。为了这个答案的目的,我将这些问题放在一边。
我的几个小小的烦恼是不必要的警告(即使被压制),以及不报告实际出错的例外情况。特别是仅仅打印出堆栈迹线通常是不够的。是的,这只是测试代码,但在处理这样的代码时 - 即使是设计用于抛出异常的代码 - 实际上应该考虑如何处理错误。在这种情况下,我选择将这类错误表示为InternalError
的实例,因为配置或任何可能以各种方式出错的情况。具体来说:如果找不到类,如果找到它但不是CheckedException
或UncheckedException
(或者甚至是普通类)的子类型,或者如果没有 - arg构造函数或者它是否无法访问。
一些建议的解决方案的另一个问题是,如果异常类名称是"java.lang.InstantiationException"
(或其他内部捕获的异常之一),则可以构造,抛出此异常类型的实例,然后捕获在内部,导致堆栈跟踪但实际上没有抛出请求的异常。我通过线性化逻辑而不是嵌套try-catch块来避免这种情况。
最后,我将创建异常的代码解压缩到一个单独的方法中,以便它可以用于已检查和未检查的情况。如果重新排列异常层次结构以仅允许单个根异常(我建议取消选中)并且具有在Web层处理或被抛出给调用者的异常子类型,则可以大大简化这一过程。
static void throwException(final String exClassName) throws CheckedException, UncheckedException {
Class<?> clazz;
try {
clazz = Class.forName(exClassName);
} catch (ClassNotFoundException cnfe) {
throw new InternalError(exClassName, cnfe);
}
if (CheckedException.class.isAssignableFrom(clazz)) {
throw newException(clazz.asSubclass(CheckedException.class));
} else if (UncheckedException.class.isAssignableFrom(clazz)) {
throw newException(clazz.asSubclass(UncheckedException.class));
} else {
throw new InternalError(exClassName + " is not a valid exception");
}
}
static <X extends Throwable> X newException(Class<X> clazz) {
X x;
try {
x = clazz.newInstance();
} catch (InstantiationException|IllegalAccessException e) {
throw new InternalError("creating instance of " + clazz, e);
}
return x;
}
答案 5 :(得分:0)
这对于创建自定义前提条件例外以避免多个条件很有帮助。 在检查 null 指针时创建前提条件异常。
class Preconditions {
/**
* <p>
* Checks the value to be null and if null throws a new Exception with the message given.
* Used to reduce checking if conditions for complexity.
* </p>
* @param val - val to check null
* @param exceptionClass - exception class to be thrown
* @param args - message to be called for throwing exception
* @throws Throwable - Common Throwable Exception.
*/
public static void checkNotNull(final Object val, final Class<?> exceptionClass, final Object ...args) throws Throwable {
Class<?>[] argTypes = new Class<?>[args.length];
Arrays.stream(args).map(WithIndex.indexed()).forEach(arg ->argTypes[arg.index()] = arg.value().getClass());
if (null == val) throw (Throwable) exceptionClass.getConstructor(argTypes).newInstance(args);
}
}
然后,您可以在以下代码中使用它:
PreConditionUtil.checkNotNull(objectToCheck, CustomException.class, ErrorCode, "your error message", ...);