将异常作为方法参数处理

时间:2014-10-23 11:28:55

标签: java design-patterns exception-handling

我正在寻找一种设计模式来处理作为方法参数接收的Exception个实例。

为了在问题中添加一些上下文,我使用GWT并拥有各种异步处理程序,通常采用类似于以下的形式:

public interface AsyncCallback<T> {

  void onFailure(Throwable caught);

  void onSuccess(T result);

}

因此,onFailure方法会收到我需要处理的Throwable实例。

现在,我在此方法中可以收到许多例外情况,例如

  • ConstraintViolationException
  • TimeoutException
  • NoSuchElementException

在我的处理代码中,我当然可以写下以下内容:

void handleException(final Exception e) {
    if(e instanceof TimeoutException) {
        handleTimeout();
    } else if (e instanceof NoSuchElementException) {
        handleInvalidElement();
    } else {
        stopAndCatchFire();
    }
}

但在我看来,这看起来非常难看。大if..else if链与instanceof的大量使用相结合似乎是应该避免的。

我想也许我可以使用try...catch构造来处理Exception,使用类似下面的内容:

void handleException(final Exception e) {
    try {
        throw e;
    } catch (TimeoutException te) {
        handleTimeout();
    } catch (NoSuchElementException nsee) {
        handleInvalidElement();
    } catch (Exception ex) {
        stopAndCatchFire();
    }
}

但这似乎是一种虐待。您是否认为第二种方法有任何缺点,或者我可以采用另一种方法来避免第一种情况?

4 个答案:

答案 0 :(得分:3)

你能否拥有一个由他们处理的异常类型键入的exceptionHandlers字典,然后当你得到一个异常时,你会在字典中查找异常类型的处理程序。如果有,则将异常传递给处理程序,如果没有则使用默认处理程序。

所以你的处理程序就像这样:

void handleException(final Exception e) {
    if (handlers.containsKey(e.getType())
    {
        handlers[e.getType()].handle(e);
    }
    else
    {
         defaultHandler.handle(e);
    }
}

我的Java有点生疏,所以这个例子很简单,但应该很容易翻译(虽然我记得没有把所有内容的第一个字母大写:))

这种方法的优点是可以简单地添加新的处理程序。

如果您对子类型具有相同的处理程序,则会受到影响,因为您必须明确注册每个子类型。

要解决此问题,只需让每个处理程序负责决定是否可以处理异常:

public interface ExceptionHandler
{
     bool canHandle(Exception e);
     void handle(Exception e)
}

然后只需将处理程序放在一个迭代列表中,询问每个处理程序是否可以处理当前异常,当你找到一个可以处理它时,让它处理它。

答案 1 :(得分:1)

  

但在我看来,这看起来非常难看。大量的if..else if链与大量使用instanceof相结合似乎是应该避免的。

我不同意。我认为这段代码正好使用了两种语言结构。如果代码变得难以管理(太多条款),那么您应该一般地质疑错误处理的方法,而不是这个方法的细节。在那个阶段你可能想要考虑AOP。

另一方面,第二种方法很可怕;)

答案 2 :(得分:1)

只需处理函数内异常中的if语句,就可以使它更优雅。

void handleException(Exception e){
    handleOne(e)
    handleTwo(e)
    ...
}

它看起来更漂亮。当然,每个函数总是被调用,但它的第一行只是一个if语句。有变化 - 例如使你的句柄函数guava函数对象,将它们放在一个列表中,并迭代它们,直到你得到第一个返回“true”。类似的东西:

public class handlerOne implements Function<Exception, Boolean> {

    Boolean apply(Exception input) {        
        return handlerOne();
    }
}

然后你的句柄功能可以是:

void handleException(Exception e){
    list<Function<Exception, Boolean> list = Object.getHandlers(); //store your handlers somewhere
    for(Function<Exception, Boolean> f : list){
        if(f.apply(e)){
            break
        }
    }
}

这样你就可以确保只调用一个有效的处理程序,你可以通过改变列表的顺序来控制顺序,因为列表迭代器会按顺序返回它们。

答案 3 :(得分:0)

应避免对异常进行控制流程,并且当然不应该在onFailure中。 onFailure方法应该尽可能简单。

修改异步运行的任何代码以处理那里的异常情况。可以通过在执行任何操作之前检查元素是否存在来处理ElementNotFound异常。超时异常可以通过try ... catch块包围可以超时(调用web服务或其他东西)的代码来处理。 然后扩展结果类型T以包含发生超时或找不到元素的额外信息 - 如果需要。