简体   繁体   English

将异常作为方法参数处理

[英]Handling an exception as a method argument

I am looking for a design pattern to handle Exception instances received as method arguments. 我正在寻找一种设计模式来处理作为方法参数接收的Exception实例。

To put some context into the question, I am using GWT and have various asynchronous handlers that usually come in a form similar to: 为了解决这个问题,我正在使用GWT并具有各种异步处理程序,这些处理程序通常以类似于以下形式的形式出现:

public interface AsyncCallback<T> {

  void onFailure(Throwable caught);

  void onSuccess(T result);

}

So, the onFailure method receives a Throwable instance that I need to handle. 因此, onFailure方法接收我需要处理的Throwable实例。

Now, I have a number of exceptions I can receive in this method, for example 现在,例如,在此方法中我可以收到许多例外

  • ConstraintViolationException
  • TimeoutException
  • NoSuchElementException

In my handling code I could of course write the following: 在我的处理代码中,我当然可以编写以下内容:

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

But to my eye, that looks very ugly. 但是在我看来,这看起来非常丑陋。 The large if..else if chain combined with heavy usage of instanceof seems like something that should be avoided. 大型if..else if链与大量使用instanceof相结合似乎是应该避免的事情。

I thought that maybe I could use the try...catch construct to handle the Exception using something like the following: 我认为也许我可以使用try...catch构造来处理类似于以下内容的Exception

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

But this seems like an abuse somehow. 但这似乎是一种滥用。 Do you see any downsides to the second approach or another approach I could go with to avoid the first case? 您是否看到第二种方法或我可以避免第一种情况的另一种方法的不利之处?

Could you not have a dictionary of exceptionHandlers keyed by the type of exception they handle, then when you get a exception you look in the dictionary for the handler for the exception type. 您是否不能拥有一个由它们处理的异常类型作为关键字的exceptionHandlers字典,那么当您获得异常时,您会在字典中查找该异常类型的处理程序。 If there is one, then pass the exception to the handler, if there isn't then use the default handler. 如果存在,则将异常传递给处理程序,如果不存在,则使用默认处理程序。

So your handler becomes something like this: 因此,您的处理程序将变成这样:

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

My Java is a bit rusty, so the example is c-sharpy but should be simple enough to translate (though I remembered not to capitalise the first letter of everything :)) 我的Java有点生锈,因此该示例是c-sharpy,但应该足够简单以进行翻译(尽管我记得不要大写所有内容的首字母:))

This approach should have the advantage that you can add new handlers simply. 这种方法应具有的优点是您可以简单地添加新的处理程序。

It will however suffer if you have the same handler for sub types, as you will have to register each subtype explicitly. 但是,如果您具有相同的子类型处理程序,则将受到影响,因为您将必须显式注册每个子类型。

To get around this issue simply make each handler responsible for making the decision about whether it can handle an exception: 要解决此问题,只需让每个处理程序负责决定是否可以处理异常:

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

then just put the handlers in a list an iterate asking each one if it can handle the current exception and when you find one that can, get it to handle it. 然后只需将处理程序放在一个列表中,就可以迭代地询问每个处理程序是否可以处理当前异常,当找到一个可以处理的异常时,请使其进行处理。

But to my eye, that looks very ugly. 但是在我看来,这看起来非常丑陋。 The large if..else if chain combined with heavy usage of instanceof seems like something that should be avoided. 大型if..else if链与大量使用instanceof相结合似乎是应该避免的事情。

I don't agree. 我不同意 I think this snippet of code is using both language constructs exactly how they were intended. 我认为这段代码正好使用两种语言的构造。 If the code becomes unmanageable (too many clauses) then you should question the approach to error handling generally, rather than the specifics of this method. 如果代码变得难以管理(子句过多),则应该质疑一般的错误处理方法,而不是此方法的细节。 At that stage you might want to consider AOP. 在那个阶段,您可能要考虑AOP。

The second approach on the other hand is horrible ;) 另一方面,第二种方法太可怕了;)

You can make it more elegant just by handling the if statements inside the exceptions inside the function. 您可以通过处理函数内部异常中的if语句来使其更加优雅。

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

It looks prettier. 看起来更漂亮。 Of course, every function is always called, but its first line is just an if statement. 当然,每个函数总是被调用,但是它的第一行只是一个if语句。 There are variations - eg make your handle functions guava function objects, put them in a list, and iterate through them until you get the first one that returns "true". 有一些变化-例如,使您的句柄函数番石榴函数对象,将它们放入列表中,并对其进行迭代,直到获得第一个返回“ true”的对象。 Something like: 就像是:

public class handlerOne implements Function<Exception, Boolean> {

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

Then your handle function can be something like: 然后,您的handle函数可能类似于:

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
        }
    }
}

That way you insure only one handler which works is called, and you can control the order by changing the order of the list, since the list iterator will return them in order. 这样,您可以确保仅调用一个有效的处理程序,并且可以通过更改列表的顺序来控制顺序,因为列表迭代器将按顺序返回它们。

Control flow on exceptions should be avoided, and should certainly not be in the onFailure. 应该避免针对异常的控制流,并且绝对不应将其置于onFailure中。 the onFailure method should be as simple as possible. onFailure方法应尽可能简单。

Modify whatever code is run asynchronously to handle the exception cases there. 修改异步运行的任何代码以处理那里的异常情况。 The ElementNotFound-exception could be handled by just checking if an element exists prior to doing anything. 可以通过在执行任何操作之前检查元素是否存在来处理ElementNotFound-exception。 Timeout-exception could be handled by surrounding the code that can timeout (calling a webservice or something)?) by a try .. catch block. 可以通过try .. catch块将可以超时的代码(调用Web服务或其他东西)包围起来来处理超时异常。 Then extend the result-type T to contain extra information that a timeout occurred or an element is not found - if needed. 然后扩展结果类型T,以包含发生超时或找不到元素的额外信息(如果需要)。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM