【问题标题】:How do exceptions trickle up, in this code?在这段代码中,异常是如何产生的?
【发布时间】:2018-03-16 17:40:51
【问题描述】:

有一些第三方代码如下所示。假设有两个类,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函数失败了吗? (我怀疑是这种情况,但是上层函数没有“抛出异常”,所以可能是我错了吗?)

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

注意:这是对某些东西的扩展,因此不能直接运行以进行调试。

注意 2:此问题被标记为可能与 this 重复。我不是在问如果没有异常抛出子句,它是如何编译的。我正在尝试找出异常发生的位置/时间。

【问题讨论】:

标签: java exception exception-handling


【解决方案1】:

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

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

现在,如果您要访问列表,从 classA 的实例中获取 Callable&lt;classB&gt;,并调用 Callable.call(),您确实需要通过添加环绕方法中的 ``try...catchor adding athrows` 子句,如下所示:

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

【讨论】:

  • 是的,它是一个 java.util.concurrent.Callable。还有,我明白了。谢谢,有道理。所以,如果我理解正确的话,call 函数只是在那里定义,并没有实际执行。
  • 谢谢!这就是我想知道的。
【解决方案2】:

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

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

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

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

但对我来说,接住和重新投掷似乎是一种浪费。我宁愿添加 throws 子句而不是捕获异常,以便一线人员可以做一些明智的事情来从问题中恢复。

【讨论】:

  • 编译器(来自 Java 7)在这里不会抱怨,因为它足够聪明,不会从 try 块中发现异常
  • @duffymo - 此代码按原样编译,没有编译器错误。另外,它是第三方代码,所以我没有碰过它/可能不会改变它,除非我正在解决问题。
【解决方案3】:

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

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2017-10-22
    • 1970-01-01
    • 1970-01-01
    • 2019-04-10
    • 1970-01-01
    • 1970-01-01
    • 2016-07-23
    相关资源
    最近更新 更多