问题 链式异常中的循环


我将首先用我的用例快速激发问题。 我的库需要将Java异常分类器暴露给它插入的框架。例如:

enum Classification { FATAL, TRANSIENT, UNKNOWN }

Classification classify(Throwable t) {
    if (t instanceof MyTransientException)
        return Classification.TRANSIENT;
    else if (t instanceof MyFatalException)
        return Classification.FATAL;
    else
        return Classification.UNKNOWN;
}

有时,由于我无法控制的原因,传递的异常是我感兴趣的一个包装器所以我想搜索它的原因链。我最初的想法是:

Classification classify(Throwable t) {
    if (t == null)
        return Classification.UNKNOWN;

    if (t instanceof MyTransientException)
        return Classification.TRANSIENT;
    else if (t instanceof MyFatalException)
        return Classification.FATAL;
    else
        return classify(t.getCause());
}

不幸的是,如果传递的异常在其因果链中有一个循环,这可能导致无限递归。这样的异常很可能不会被传递,并且如果创建了这样的异常,可能会在系统的其他地方出现错误,但我对我的库负责生产的可能性感到非常不舒服。如果发生中断。 Throwable的API和javadoc没有明确禁止这种可能性,因为循环在因果链中本质上是无意义的。

我注意到Guava有一个@Beta方法来提取因果链, Throwables.getCausalChain,但它的实现很容易受到同样的问题 - 最终会抛出一个OOME。

我打算用一个 身份哈希集 检测周期并降低风险,但我想听听别人如何看待这个问题。你觉得我过度防守吗?你会怎么做?


12923
2017-09-28 15:07


起源



答案:


你是如此尽职尽责的很棒。但是你不想进入制造凯夫拉靴的生意。

如果用户做了一些可以做到均匀的事情 Throwable.printStackTrace 进入无限递归,用户无法帮助。甚至不用担心这个。


13
2017-09-28 15:56





我认为这是在防守端在自己的代码做的,但因为这几天我们使用许多图书馆,你永远不知道它会怎么做意料之外的东西作为创建causechain循环。

Apache Commons确实可以解决这个问题 ExceptionUtils。例如在 ExceptionUtils.getThrowableList。它以一种相当简单的方式实现:

public static List<Throwable> getThrowableList(Throwable throwable) {
    final List<Throwable> list = new ArrayList<>();
    while (throwable != null && !list.contains(throwable)) {
        list.add(throwable);
        throwable = throwable.getCause();
    }
    return list;
}

通过使用帮助程序库而不是构建自己的程序库,您可以防止在您从未想过的事情上出错。


0
2018-04-11 08:09