有没有办法让Runnable的run()抛出一个异常?(Is there a way to make

2019-06-26 10:51发布

我在调用一个方法的run()在实现类Runnable接口 )被设计成抛出异常。

但Java编译器不会让我这样做,并建议我围绕着它与try / catch语句。

问题是,用一个try / catch周围我作出这样的特定 的run()也没用。 想抛出该异常。

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

按说我和不让完全正常的run()抛出异常。 但我有独特的情况中,我必须有这个功能。

如何我解决这个限制?

Answer 1:

如果你想传递一个实现类RunnableThread架构,那么你必须通过该框架的规则玩,看欧内斯特·弗里德曼-希尔的回答,为什么这样做,否则是一个坏主意。

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

这个问题的答案的问题是容易的。 不要使用Runnable接口的线程库,而是与允许checked异常被抛出修改后的签名,例如,创建自己的界面

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

你甚至可以创建真正该接口转换适配器Runnable (通过处理检查除外)适用于线程框架使用。



Answer 2:

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

isDone()返回true调用FutureTask.get() 现在,如果你的Callable已抛出Exception ,然后FutureTask.get()家业抛出一个Exception也和原来的异常,你将能够使用访问Exception.getCause()



Answer 3:

如果run()抛出检查异常,你会抓住它? 有没有办法让你罩住run()调用中的处理程序,因为你不写调用它的代码。

你能赶上在您检查异常run()方法,并抛出一个异常unchekced(即RuntimeException在它的位置)。 这将终止与堆栈跟踪线程; 也许这就是你以后。

相反,如果你希望你run()方法的地方报告错误,那么你可以只为提供一个回调方法run()方法的catch模块调用; 该方法可以存储一些例外对象,然后你感兴趣的线程可以发现在该位置的对象。



Answer 4:

是的,有扔从checked异常的方式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是一个更适合。



Answer 5:

@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;

}


Answer 6:

我认为一个监听器模式可以帮助你用了这种情况。 在异常在发生的情况下run()方法中,使用try-catch块,并在catch发送异常事件的通知。 然后处理您的通知事件。 我认为这将是一个更简洁的方法。 这个所谓的链接给你一个有用的指针,它指向的方向。



Answer 7:

有些人试图说服你,你必须遵守游戏规则。 听着,但无论你服从,你应该自己决定根据您的情况。 现实情况是,“你应该遵守游戏规则”(不是“你必须按规则行事”)。 要知道,如果你不遵守游戏规则,可能会有后果。

这种情况不仅适用于情况Runnable ,但与Java 8同样在功能接口已经被引入,而不应对checked异常的可能性流和其他地方的情况下非常频繁。 例如, ConsumerSupplierFunctionBiFunction等等都被宣布没有设施,以应付检查的异常。

那么什么是情况和选择? 在下面的文字, Runnable代表不声明异常,或声明例外非常有限的情况下,使用手头的任何功能接口。

  1. 你已经声明Runnable某处自己,可取代Runnable别的东西。
    1. 考虑更换RunnableCallable<Void> 。 基本上是一回事,但允许抛出异常; 并已return null到底,这是一个温和的烦恼。
    2. 考虑更换Runnable与自己的自定义@FunctionalInterface会抛出正是你想要这些例外。
  2. 你使用的API,以及替代品可供选择。 例如,一些Java API是超载,所以你可以使用Callable<Void> ,而不是Runnable
  3. 你使用的API,而且没有替代品。 在这种情况下,你仍然没有跳出选项。
    1. 你可以用在异常RuntimeException
    2. 您可以通过使用一个unchecked投破解例外成一个RuntimeException。

你可以尝试以下。 这是一个黑客攻击的一位,但有时黑客正是我们需要的。 因为,一个异常是否应该被选中或取消选中由它的类型定义,但实际上应该通过实际情况来确定。

@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;
}

我宁愿这些new RuntimeException(t)因为它有一个较短的堆栈跟踪。

现在你可以这样做:

executorService.submit((ThrowingRunnable) () -> {throw new Exception()});

免责声明:以这种方式执行未经检查的强制转换的能力实际上可能在Java中的未来版本中,当泛型类型的信息进行处理,不仅在编译的时候,而且在运行时被删除。



Answer 8:

您的要求不作任何意义。 如果你想通知被叫有关所发生的异常的线程,你可以做到这一点通过回拨机制。 这可以通过一个处理程序,或者你能想到的广播或任何其他。



Answer 9:

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



文章来源: Is there a way to make Runnable's run() throw an exception?