如何实现多个异常的包装器?

时间:2017-04-05 15:37:42

标签: java exception error-handling

我有一些模块,每个模块都包含一些模型,我想从持久文件中解析它。

当我读取文件时,我不知道哪个模块能够解析它,这就是我尝试用我的第一个模块的解析器解析它的原因。如果失败,我尝试使用第二个模块的解析器并继续,直到我尝试了所有解析器。 解析器可以以多个异常(Exception类的不同子类型)或解析的模型对象(ModelBase类的不同子类型)的形式提供信息。

如果解析器都没有成功,我想将所有给定的异常包装成一个大的Exception,抛出它并在我的应用程序代码中以某种形式捕获它(以新的大异常形式),我可以在那里处理问题(例如向用户显示所有解析问题和堆栈跟踪,以某种方式处理它们等。)。

我的伪代码:

ModelBase getModelOrBigException(File file)
    throws MyBigException {

    List<Exception> exceptions = new ArrayList<>();
    for (Module module : myModules){
        try {
            ModelBase model = module.parse(file);
            return model;
        } 
        catch (ParsingException1 p1) { exceptions.add(p1); }
        catch (ParsingException2 p2) { exceptions.add(p2); }
    }
    throw new MyBigException(exceptions);
}

我想调用代码

void openFilesHandler(){

    //... selecting file 

    try {
        process(getModelOrBigException(file));
    } catch (MyBigException e) { 
        // process the sub-exceptions or show them to user or print stacktraces of all sub-exceptions or show sub-exceptions by type etc
    }
}

显然,如果我捕获MyBigException,我将无法在默认情况下调用getStackTrace(),getMessage(),getLocalizedMessage()等方法,只有在我实现类似于此的异常类时才会这样:

class MyBigException extends Exception {

    public MyBigException(Exception e1, Exception e2, ..., Exception eN){
        super(e1, e2, ..., eN); // This is not possible, only one argument is acceptable
    }
}

或者这个:

class MyBigException extends Exception {

    List<Exception> exceptions = new ArrayList<>();

    public MyBigException(List<Exception> exceptions){
        super(exceptions); // This is not possible, list or array of exceptions is not allowed here
    }
}

问题:

我应该如何创建一种新的Exception类型,它可以在支持原始Exception类的方法的情况下存储多个异常? 当我这样做时:

myBigException.printStackTrace();

或者这个:

myBigException.getMessage();

我想打印/获取所有存储异常的所有堆栈跟踪。 我应该将所有给定的例外传递给super()方法吗?

有没有比上述解决方案更好的方法来解析解决方案?

3 个答案:

答案 0 :(得分:3)

  

我想打印/获取所有存储异常的所有堆栈跟踪。我是不是该   将所有给定的异常传递给super()方法?

如果您想要打印所有堆栈跟踪或异常消息,那么您几乎就在那里,您需要添加更多位,如下所述:

(1)在MyBigException内,创建一个构造函数MyBigException(List<Exception> exceptions, String exeptionMessage)并调用super(exeptionMessage);

(2)覆盖printStackTrace()中的MyBigException并迭代List<Exception>并在每个异常对象上调用printStackTrace()

您可以参考以下代码:

MyBigException课程:

public class MyBigException extends Exception {

    private List<Exception> exceptions = new ArrayList<>();

    public MyBigException(List<Exception> exceptions, String exeptionMessages){
        //call super and pass message
        super(exeptionMessages);
        this.exceptions = exceptions;
    }

    public void printStackTrace() {
        for(Exception exception : exceptions) {
            exception.printStackTrace();
        }
    }   
}

getModelOrBigException()代码:

ModelBase getModelOrBigException(File file)
    throws MyBigException {

    List<Exception> exceptions = new ArrayList<>();

    //Capture exception messages as well using StringBuilder
    StringBuilder exceptioMessages = new StringBuilder();
    for (Module module : myModules){
        try {
            ModelBase model = module.parse(file);
            return model;
        } 
        catch (ParsingException1 p1) { 
            exceptions.add(p1); 
            exceptioMessages.append("YOUR MESSAGE FOR ParsingException1;");
        }
        catch (ParsingException2 p2) { 
            exceptions.add(p2); 
            exceptioMessages.append("YOUR MESSAGE FOR ParsingException2;");
        }
      }
      throw new MyBigException(exceptions, exceptioMessages.toString());
    }

答案 1 :(得分:1)

我想到了两个选择。

  1. 使用addSuppressed来抑制给定的异常。然后,您可以稍后使用getSuppressed()再次检索它。这也是用于try-with-resources-statements抛出异常的机制。这样,myBigException的堆栈跟踪也会自动显示被抑制的跟踪。

  2. 为您的异常类内部列表添加一个访问器方法,以便您可以从外部访问它,例如getExceptions()。但是,您需要自己处理每个异常的堆栈跟踪。您可以覆盖printStackTrace(*)方法,但这对我来说似乎是开销。

  3. 它主要取决于您想要实现的目标(或更合适的内容)以及您希望以后如何访问异常。

    您可能还希望在第二种情况下提供自己的printStackTraces()方法,或在两种情况下覆盖getMessage() - 方法,以提供更合适的消息。

答案 2 :(得分:1)

BigException的原因不能包含很多例外情况。抛出一个异常,它会一直向上移动,直到你处理它为止。您可以将其添加到因果关系链中,这就是Exception的构造函数接受另一个异常作为此异常的原因的原因。

但是在你的情况下,在抛出许多解析异常并且已经处理(通过将它们添加到列表中)后,你抛出BigException

因此,链中的第一个例外实际上是BigException。如果我是你,我只需要获取解析异常列表的getter并使用该列表,即通知用户,记录列表等。