Java 动态创建异常的工厂模式

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>

我创建了异常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>
我想知道在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", ...);