我一直在努力解决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(); } }
解决方法
忘记你的包装,这是吃异常,而SwingWorker没有.以下是应该如何使用SwingWorker,以及如何处理从后台任务抛出的特定异常:
class MeaningOfLifeFinder extends SwingWorker<String,Object> { @Override public String doInBackground() throws SomeException { return findTheMeaningOfLife(); } @Override protected void done() { // called in the EDT. You can update the GUI here,show error dialogs,etc. try { String meaningOfLife = get(); // this line can throw InterruptedException or ExecutionException label.setText(meaningOfLife); } catch (ExecutionException e) { Throwable cause = e.getCause(); // if SomeException was thrown by the background task,it's wrapped into the ExecutionException if (cause instanceof SomeException) { // TODO handle SomeException as you want to } else { // the wrapped throwable is a runtime exception or an error // TODO handle any other exception as you want to } } catch (InterruptedException ie) { // TODO handle the case where the background task was interrupted as you want to } } }