有没有办法让Runnable的run()抛出异常?

时间:2012-07-20 17:25:31

标签: java android runnable throws

我在实现run()的类中调用Runnable的方法,旨在抛出异常。

但Java编译器不允许我这样做,并建议我用try / catch包围它。

问题在于,通过try / catch包围它,我使特定的 run()无用。我想要抛出异常。

如果我为run()本身指定throws,编译器会抱怨Exception is not compatible with throws clause in Runnable.run()

通常我完全没有让run()抛出异常。但我有独特的情况,我必须具备这种功能。

如何解决此限制?

9 个答案:

答案 0 :(得分:68)

您可以使用Callable,将其提交给ExecutorService并等待FutureTask.isDone()返回ExecutorService.submit()的结果。

isDone()返回true时,您拨打FutureTask.get()。现在,如果您的Callable已经抛出了Exception,那么FutureTask.get()也会抛出Exception,而原始的异常则可以使用Exception.getCause()进行访问。

答案 1 :(得分:20)

如果run()抛出一个已检查的异常,会有什么结果呢?由于您没有编写调用它的代码,因此无法将run()调用封装在处理程序中。

您可以在run()方法中捕获已检查的异常,并在其位置抛出未经检查的异常(即RuntimeException)。这将使用堆栈跟踪终止线程;也许那就是你所追求的。

如果您希望run()方法在某处报告错误,那么您只需为run()方法的catch块提供回调方法即可调用;该方法可以在某处存储异常对象,然后您感兴趣的线程可以在该位置找到该对象。

答案 2 :(得分:17)

如果你想将一个实现Runnable的类传递到Thread框架中,那么你必须按照该框架的规则进行游戏,参见Ernest Friedman-Hill的回答为什么要这样做,否则是一个坏主意

我有一种预感,你想直接在你的代码中调用run方法,所以你的调用代码可以处理异常。

这个问题的答案很简单。不要使用来自线程库的Runnable接口,而是使用修改后的签名创建自己的接口,以允许抛出已检查的异常,例如。

public interface MyRunnable
{
    void myRun ( ) throws MyException;
}

您甚至可以创建一个适配器,将此接口转换为适用于Thread框架的真实Runnable(通过处理已检查的异常)。

答案 3 :(得分:16)

是的,有一种方法可以从run()方法中抛出已检查的异常,但它太可怕了,我不会分享它。

这是你可以做的事情;它使用与运行时异常相同的机制:

@Override
public void run() {
  try {
    /* Do your thing. */
    ...
  } catch (Exception ex) {
    Thread t = Thread.currentThread();
    t.getUncaughtExceptionHandler().uncaughtException(t, ex);
  }
}

正如其他人所指出的那样,如果你的run()方法确实是Thread的目标,那么抛出异常是没有意义的,因为它是不可观察的;抛出异常与不抛出异常(无)具有相同的效果。

如果它不是Thread目标,请不要使用Runnable。例如,或许Callable更适合。

答案 4 :(得分:2)

@FunctionalInterface
public interface CheckedRunnable<E extends Exception> extends Runnable {

    @Override
    default void run() throws RuntimeException {
        try {
            runThrows();
        }
        catch (Exception ex) {
            throw new RuntimeException(ex);
        }
    }

    void runThrows() throws E;

}

答案 5 :(得分:0)

我认为listener pattern可能会帮助您解决此问题。如果您的run()方法发生异常,请使用try-catch块并在catch中发送异常事件的通知。然后处理您的通知事件。我认为这将是一种更清洁的方法。 This SO link为您提供指向该方向的有用指针。

答案 6 :(得分:0)

有些人试图说服您必须遵守规则。听,但是无论您是否服从,都应根据自己的情况决定自己。现实是“您应该遵守规则”(而不是“您必须遵守规则”)。请注意,如果您不遵守规则,可能会造成后果。

这种情况不仅适用于Runnable的情况,对于Java 8,在Streams和其他引入了功能接口而无法处理检查异常的地方的情况下,Java 8也非常常见。例如,ConsumerSupplierFunctionBiFunction等都已声明为没有处理已检查异常的便利。

那么情况和选择是什么? 在下面的文本中,Runnable代表任何不声明异常或声明对于当前用例而言太有限的异常的功能接口。

  1. 您已经在自己的某个地方声明了Runnable,并可以用其他内容代替Runnable
    1. 请考虑将Runnable替换为Callable<Void>。基本上是一样的,但是允许抛出异常;并且最后必须return null,这是个小麻烦。
    2. 请考虑使用您自己的自定义Runnable替换@FunctionalInterface,该自定义Callable<Void>可能会引发您想要的异常。
  2. 您已经使用了API,并且可以使用其他替代方法。例如,某些Java API重载,因此您可以使用Runnable代替RuntimeException
  3. 您已经使用了API,没有其他选择。在那种情况下,您仍然没有选择余地。
    1. 您可以将异常包装在@FunctionalInterface public interface ThrowingRunnable extends Runnable { @Override default void run() { try { tryRun(); } catch (final Throwable t) { throwUnchecekd(t); } } private static <E extends RuntimeException> void throwUnchecked(Throwable t) { throw (E) t; } void tryRun() throws Throwable; } 中。
    2. 您可以通过使用未经检查的强制转换将异常黑客入侵到RuntimeException中。

您可以尝试以下方法。这有点hack,但是有时候我们需要hack。因为,是否应该检查或不检查异常是由其类型定义的,但实际上实际上应由情况定义。

new RuntimeException(t)

我更喜欢executorService.submit((ThrowingRunnable) () -> {throw new Exception()}); ,因为它具有较短的堆栈跟踪。

您现在可以这样做:

File file = new File("file location");
Sheet sheet = SpreadSheet.createFromFile(file).getSheet(0)MutableCell domain = null;
sheet.getCellAt(row index,column index).setValue(value you want to write in the cell) / getvalue()-fetches the value in the cell;
sheet.getSpreadSheet().saveAs(file);

免责声明:当泛型类型信息不仅在编译时而且在运行时都得到处理时,在Java的未来版本中实际上可能会取消以这种方式执行未经检查的强制转换的功能。

答案 7 :(得分:-1)

您的要求没有任何意义。如果要通知线程调用者发生的异常,可以通过回调机制来实现。这可以通过处理程序或广播或您能想到的任何其他内容。

答案 8 :(得分:-1)

最简单的方法是定义自己的异常对象,扩展RuntimeException类而不是Exception类。

相关问题