处理异常时,操纵列表中的所有 *项目的通用方法



我尝试在列表的所有项目上执行一种方法,同时忽略导致异常的条目。如果抛出异常,则忽略该项目,并且处理以下项目。最后,遇到的第一个例外是要警告出现问题。

基本上,这应该导致相同的输出,而与输入的顺序无关(如果例外是第一个或最后一个元素抛出的,则所有其他元素仍被处理(。

具体情况是:

List<Input> inputs = getInputs();
List<Output> outputs = new ArrayList<>();
MyException exc = null;
for(Input input: inputs){
    try{
        outputs.add(handleInput(input));
    } catch(MyException e) {
        if(exc != null){
            exc = e;
        }
    }
}
if(exc != null){
    throw exc;
}

可能的通用情况不会编译:

public <I, O, E extends Exception> List<O> tryAll(List<I> inputs, ExceptionFunction<I, O, E> f) throws E {
    E exc = null;
    List<O> outputs = new ArrayList<>();
    for(I input: inputs){
        try{
            outputs.add(f.apply(input));
        } catch(E e){ //compile error
            if(exc != null){
                exc = e;
            }
        }
    }
    if(exc != null){
        throw exc;
    }
    return result;
}

其中 ExceptionFunction是:

@FunctionalInterface
public interface ExceptionFunction<T, R, E extends Throwable> {
    public R apply(T t) throws E;
}

上面的代码不起作用,因为您无法在Java中捕获通用异常。有其他方法可以实现这一目标吗?

我意识到,投掷例外可以停止对输出列表的任何访问,但是handleInput可以突变其他标志,对此检查所有元素很重要。

处理它的一种方法是更改设计并不使用通用异常,而是使用您自己的异常(例如IgnorableException代替E extends Throwable(。

在您描述的情况下,您将有可能实现,您将被迫使用handleInput方法中的IgnorableException和捕获子句中的异常。

解决此问题的常见方法是使 tryAll采用指示异常类型的类型令牌:

public <I, O, E extends Exception> tryAll(
    List<I> inputs,
    ExceptionFunction<I, O, E> function,
    Class<E> exceptionType)
        throws E;

然后在实现中,只需捕获更广泛的类型(例如Exception(,然后使用throw exceptionType.cast(ex)来确保仅重新插入给定类型的例外。像Guava的Throwables.propagateIfInstanceOf()这样的实用程序在这里很有用。

(请注意,这是安全的,因为从Throwable延伸的类型不能是通用的,因此异常类型将始终可以进行修复。(

如果您可以将所有异常都插入一个通用层次结构(或接受像Exception这样的基本类型(,则可以消除E类型参数和相应的类型标记参数。

最新更新