有一些第三方代码如下所示。假设有两个类,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,所以-__(oO)__ / -
注意:这是对某些内容的扩展,因此无法直接运行以进行调试。
注2 :此问题被标记为this的可能副本。我不是在没有异常抛出子句的情况下询问这是如何编译的。我试图找出抛出异常的位置/时间。
答案 0 :(得分:2)
我认为此处的Callable
类型为java.util.concurrent.Callable
。
实际上永远不会在doSomething
的堆栈帧上抛出异常。这是因为它是在一个实现Callable<classB>
的匿名内部类中定义的。它根本不在doSomething
中调用。然后将匿名类的实例传递到classA
的构造函数中,创建classA
的新实例并将其放入列表中。这解释了为什么doSomething
不需要throws
现在,如果您要访问该列表,请从Callable<classB>
的实例获取classA
,然后致电Callable.call()
,做需要处理通过在周围方法中添加``try ... catch or adding a
throws`子句来检查异常,如下所示:
public void doSomethingElse() throws Exception{
ClassAList.get(0).getCallable().call(); // exception might be thrown here!
}
答案 1 :(得分:1)
这不可能发生,因为Exception
是一个经过检查的例外。您的方法签名中没有throws子句。我的猜测是编译器会抱怨你的示例代码。
您必须将其切换为未选中的RuntimeException
,或将throws子句添加到方法签名中。
即使你这样做,我也会说这是一个糟糕的设计。
捕获异常表明您可以做一些明智的事情来从中恢复。它可能几乎没有任何东西可以记录这个事实,或者像清理资源和优雅地结束任务那样更重要的事情。
但抓住和重新投掷对我来说似乎是一种浪费。我宁愿添加throws子句而不是捕获异常,所以有人可以做一些明智的事情来从问题中恢复。
答案 2 :(得分:1)
您提供的代码只是定义Callable's
。它不会在doSomething
方法中执行,因此它不会在那里抛出异常。在实际执行Callable
(通过call()或将其提交给ExecutorService)的地方可以抛出异常。
查看此示例https://www.journaldev.com/1090/java-callable-future-example