【发布时间】:2012-12-18 20:47:35
【问题描述】:
我一直在努力解决 SwingWorker 吃掉后台任务中抛出的任何异常的可用性问题,例如,描述 on this SO thread。该线程很好地描述了问题,但没有讨论恢复原始异常。
我收到的小程序需要向上传播异常。但我什至无法抓住它。我正在使用来自this blog entry 的 SimpleSwingWorker 包装类专门尝试解决这个问题。这是一个相当小的课程,但我会在最后转发它以供参考。
调用代码看起来很像
try {
// lots of code here to prepare data, finishing with
SpecialDataHelper helper = new SpecialDataHelper(...stuff...);
helper.execute(); // this will call get+done on the actual worker
} catch (Throwable e) {
// used "Throwable" here in desperation to try and get
// anything at all to match, including unchecked exceptions
//
// no luck, this code is never ever used :-(
}
包装器:
class SpecialDataHelper extends SimpleSwingWorker {
public SpecialDataHelper (SpecialData sd) {
this.stuff = etc etc etc;
}
public Void doInBackground() throws Exception {
OurCodeThatThrowsACheckedException(this.stuff);
return null;
}
protected void done() {
// called only when successful
// never reached if there's an error
}
}
SimpleSwingWorker 的特点是会自动调用真正的 SwingWorker 的done()/get() 方法。从理论上讲,这会重新引发后台发生的任何异常。在实践中,从来没有抓到任何东西,我什至不知道为什么。
SimpleSwingWorker 类,供参考,为简洁起见,没有省略:
import java.util.concurrent.ExecutionException;
import javax.swing.SwingWorker;
/**
* A drop-in replacement for SwingWorker<Void,Void> but will not silently
* swallow exceptions during background execution.
*
* Taken from http://jonathangiles.net/blog/?p=341 with thanks.
*/
public abstract class SimpleSwingWorker {
private final SwingWorker<Void,Void> worker =
new SwingWorker<Void,Void>() {
@Override
protected Void doInBackground() throws Exception {
SimpleSwingWorker.this.doInBackground();
return null;
}
@Override
protected void done() {
// Exceptions are lost unless get() is called on the
// originating thread. We do so here.
try {
get();
} catch (final InterruptedException ex) {
throw new RuntimeException(ex);
} catch (final ExecutionException ex) {
throw new RuntimeException(ex.getCause());
}
SimpleSwingWorker.this.done();
}
};
public SimpleSwingWorker() {}
protected abstract Void doInBackground() throws Exception;
protected abstract void done();
public void execute() {
worker.execute();
}
}
【问题讨论】:
-
所有这些都是基于错误的假设。阅读javadoc for the get() method:如果后台计算抛出异常,它会抛出 ExecutionException。
-
另见Q&A。
-
@JBNizet 是的,这就是 SimpleSwingWorker 的 done() 调用 get()、捕获 ExecutionException 并将其作为新的 RuntimeException 重新抛出的原因。这不是重点吗?如果不是,那么我们就是在谈论彼此,你必须更加明确。
-
@TiStrga:原来的 SwingWorker 通过在重写的
done()方法中调用get()来强制你处理异常,捕获ExecutionException,并处理这个异常。您的包装器没有提供任何处理异常的方法:要么存在异常,它被抛出但没有人可以捕获它并且包装器的done()方法永远不会被调用,或者没有异常并且包装器的done()方法叫做。 SwingWorker 不吃异常。你的包装器可以。 -
我说的是您在问题中提出的 SimpleSwingWorker 类。 SwingWorker 设计得很好。我建议按照 javadoc 中的说明使用它。
标签: java swing swingworker