Java 动态创建异常的工厂模式
我创建了异常xml,并动态创建和抛出异常Java 动态创建异常的工厂模式,java,exception-handling,factory-pattern,Java,Exception Handling,Factory Pattern,我创建了异常xml,并动态创建和抛出异常 <exception-mappings> <exception-mapping key="exceptionkey1"> <class-name>com.package.CheckedException</class-name> <message>Checked Exception Message</message> </exception-mapping>
<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>
我想知道在X行输入哪个类,这样我就不需要使用If/else。我不想使用if-else的原因是,将来可能会添加新类,我不想每次添加新异常时都更改此代码
我的基本逻辑是,我的服务层将抛出CheckedException或UncheckedException。如果抛出CheckedException,它将由我的web层处理。此外,我不能抛出超级父类异常或Throwable,因为我的web层只捕获CheckedException。若抛出UncheckedException,它将显示异常页面
请帮助我,因为我无法继续
编辑:也接受任何其他解决方案。我看不出这家工厂有什么意义。即使您让它工作(您可以通过将它引发的所有异常作为单个祖先类的子类来实现),它的用法也会是这样的:
....
if (somethingInWrong) {
ExceptionFactory.throwException("SomeKey");
}
....
对于每个键,您仍然必须创建一个要映射到它的异常类。假设SomeKeyException
是映射到“SomeKey”的异常
在这种情况下,只需编写以下代码,类型安全性就会大大提高:
....
if (somethingInWrong) {
throw new SomeKeyException();
}
....
这样,编译器会检查您是否正在创建一个它实际上知道的异常类。如果使用工厂,可能会使用一些无效键的字符串,编译器将无法对此执行任何操作。只有在运行时,您的工厂才能找到映射到无效密钥的异常。没有必要使用反射(正如我上面所评论的) 可以将exceptions类实现为如下所示:
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);
好吧,以科学的名义,你可以这样做。我会建议你这样做吗?绝对不是。我自己会做这样的事吗?可能不会
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 {
}
公共类例外工厂{
公共静态void throwException(字符串类名称)
抛出CheckedException,取消选中DexException{
类别例外类别;
试一试{
exceptionClass=Class.forName(className);
}catch(classnotfounde异常){
抛出新的IllegalArgumentException(e);
}
试一试{
if(CheckedException.class.isAssignableFrom(exceptionClass)){
抛出exceptionClass.asSubclass(CheckedException.class)
.newInstance();
}else if(取消选中dexception.class
.isAssignableFrom(例外类)){
抛出exceptionClass.asSubclass(取消选中DexException.class)
.newInstance();
}否则{
抛出新的IllegalArgumentException(
“不是有效的异常类型:”
+exceptionClass.getName());
}
}捕获(实例化异常|非法访问异常e){
抛出新的非法状态异常(e);
}
}
公共静态void main(字符串…参数){
试一试{
ThroweException(“CheckedException”);
}捕获(检查异常e){
系统输出打印ln(e);
}捕获(不勾选e){
系统输出打印ln(e);
}
}
}
类CheckedException扩展异常{
}
类UncheckedException扩展了异常{
}
一些调整:
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();
}
}
}
publicstaticvoidthrowException(最终字符串键)抛出Throwable{
例外映射例外映射=
getExceptionMappings.getExceptionMappings().get(键);
if(exceptionMapping!=null){
试一试{
类别例外类别=
(Class)Class.forName(例外的是mapping.getClassName());
试一试{
抛出exceptionClass.cast(exceptionClass.newInstance());//第X行
}捕获(实例化异常e){
e、 printStackTrace();
}捕获(非法访问例外e){
e、 printStackTrace();
}
}catch(classnotfounde异常){
e、 printStackTrace();
}
}
}
这是我参加这次德比的记录。:-)
其他答案都评论了这是否是一个合理的设计。为了回答这个问题,我将把这些问题放在一边
我的一些恼怒是不必要的警告(即使被抑制了),也是例外,它们不会报告实际出了什么问题。特别是,仅仅打印出堆栈跟踪通常是不够的。是的,这只是测试代码,但当处理这样的代码时——即使是设计用来抛出异常的代码——人们确实应该考虑如何处理错误。在本例中,我选择将这些类型的错误表示为InternalError
的实例,因为配置或任何东西可能以多种方式出错。特别是:如果找不到该类,如果该类已找到但不是CheckedException
或UncheckedException
(甚至是普通类)的子类型,或者如果该类没有无参数构造函数,或者如果该类不可访问
一些建议的解决方案的另一个问题是,如果异常类名为“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;
}
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;
}
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", ...);