在此代码中,异常是如何产生的?

How do exceptions trickle up, in this code?

有一些第三方代码如下所示。假设有两个 类,classA 和 classB,它们的定义正确并且按预期工作。

// this function does not have a *throws Exception* in its definition
public Collection<classA> doSomething(String someStr) {

    List<ClassA> ClassAList = new ArrayList<ClassA>();
    int a = 0;

    while (a < 5) {
        classAList.add(
            new classA(
                someStr,
                new Callable<classB>() {
                    public classB call() throws Exception {
                        // do some work here
                        try {
                            // try something new
                        } catch (Exception e) { // <---- THIS EXCEPTION
                            // do something exceptional
                            throw e;
                        }
                        // do more work here, because why not?
                    }
                }
            )
        );
        a++;
    }
    return classAList;
}

这是一个人为的例子,所以它可能不完全合理。但是,它准确地反映了我的代码。

我想弄清楚的是,如果抛出异常会发生什么?是否异常突破,整个doSomething函数失效? (我怀疑是这种情况,但上层函数没有 "throws Exception",所以我可能错了吗?)

我对Java比较陌生,以前肯定没见过这种编程风格(另外,如果你知道它叫什么,我可以进一步研究它,请告诉我)-我有 C 和 Python 的背景,所以 -__(o.O)__/-

注意:这是对某物的扩展,因此不能运行直接调试。

注释 2:此问题被标记为可能与 this 重复。我不是在问如何在没有异常抛出子句的情况下进行编译。我正在尝试找出 where/when 抛出的异常。

这不可能发生,因为 Exception 是一个已检查的异常。您的方法签名中没有 throws 子句。我的猜测是编译器会抱怨您的示例代码。

您必须将其切换为未选中的 RuntimeException,或者将 throws 子句添加到您的方法签名中。

即使你这样做,我也会说这是一个糟糕的设计。

捕获异常表明您可以做一些明智的事情来从中恢复。它可能几乎没有记录事实,或者更重要的事情,比如清理资源和优雅地结束任务。

但是捕捉和 re-throwing 对我来说似乎是一种浪费。我宁愿添加 throws 子句而不是捕获异常,以便在线的人可以做一些明智的事情来从问题中恢复。

您提供的代码只是定义 Callable's。它不会在 doSomething 方法中执行,因此不会在那里抛出异常。在实际执行 Callable 的地方可能会抛出异常(通过 call() 或将其提交给 ExecutorService)。

看看这个例子https://www.journaldev.com/1090/java-callable-future-example

我假设这里的 Callable 类型是 java.util.concurrent.Callable.

异常实际上永远不会在doSomething的堆栈帧上抛出。这是因为它是在实现 Callable<classB> 的匿名内部 class 中定义的。它根本没有在 doSomething 中调用。然后将匿名 class 的实例传递给 classA 的构造函数,创建 classA 的新实例并将其放入列表中。这就解释了为什么 doSomething 不需要 throws

现在,如果您要访问列表,从 classA 的实例中获取 Callable<classB>,然后调用 Callable.call(),您 do 需要通过在周围方法中添加 ``try...catchor adding athrows` 子句来处理已检查的异常,如下所示:

public void doSomethingElse() throws Exception{
    ClassAList.get(0).getCallable().call(); // exception might be thrown here!
}