我在调用一个方法的run()在实现类Runnable接口 )被设计成抛出异常。
但Java编译器不会让我这样做,并建议我围绕着它与try / catch语句。
问题是,用一个try / catch周围我作出这样的特定 的run()也没用。 我想抛出该异常。
如果我指定throws
的run()的本身,编译器会抱怨Exception is not compatible with throws clause in Runnable.run()
按说我和不让完全正常的run()抛出异常。 但我有独特的情况中,我必须有这个功能。
如何我解决这个限制?
如果你想传递一个实现类Runnable
到Thread
架构,那么你必须通过该框架的规则玩,看欧内斯特·弗里德曼-希尔的回答,为什么这样做,否则是一个坏主意。
我有一种预感,虽然,你要调用run
,直接在你的代码的方法,所以调用代码可以处理异常。
这个问题的答案的问题是容易的。 不要使用Runnable
接口的线程库,而是与允许checked异常被抛出修改后的签名,例如,创建自己的界面
public interface MyRunnable
{
void myRun ( ) throws MyException;
}
你甚至可以创建真正该接口转换适配器Runnable
(通过处理检查除外)适用于线程框架使用。
您可以使用Callable
相反,它提交给ExecutorService
,并等待结果FutureTask.isDone()
的返回ExecutorService.submit()
当isDone()
返回true调用FutureTask.get()
现在,如果你的Callable
已抛出Exception
,然后FutureTask.get()
家业抛出一个Exception
也和原来的异常,你将能够使用访问Exception.getCause()
如果run()
抛出检查异常,你会抓住它? 有没有办法让你罩住run()
调用中的处理程序,因为你不写调用它的代码。
你能赶上在您检查异常run()
方法,并抛出一个异常unchekced(即RuntimeException
在它的位置)。 这将终止与堆栈跟踪线程; 也许这就是你以后。
相反,如果你希望你run()
方法的地方报告错误,那么你可以只为提供一个回调方法run()
方法的catch
模块调用; 该方法可以存储一些例外对象,然后你感兴趣的线程可以发现在该位置的对象。
是的,有扔从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
是一个更适合。
@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;
}
我认为一个监听器模式可以帮助你用了这种情况。 在异常在发生的情况下run()
方法中,使用try-catch块,并在catch发送异常事件的通知。 然后处理您的通知事件。 我认为这将是一个更简洁的方法。 这个所谓的链接给你一个有用的指针,它指向的方向。
有些人试图说服你,你必须遵守游戏规则。 听着,但无论你服从,你应该自己决定根据您的情况。 现实情况是,“你应该遵守游戏规则”(不是“你必须按规则行事”)。 要知道,如果你不遵守游戏规则,可能会有后果。
这种情况不仅适用于情况Runnable
,但与Java 8同样在功能接口已经被引入,而不应对checked异常的可能性流和其他地方的情况下非常频繁。 例如, Consumer
, Supplier
, Function
, BiFunction
等等都被宣布没有设施,以应付检查的异常。
那么什么是情况和选择? 在下面的文字, Runnable
代表不声明异常,或声明例外非常有限的情况下,使用手头的任何功能接口。
- 你已经声明
Runnable
某处自己,可取代Runnable
别的东西。 - 考虑更换
Runnable
与Callable<Void>
。 基本上是一回事,但允许抛出异常; 并已return null
到底,这是一个温和的烦恼。 - 考虑更换
Runnable
与自己的自定义@FunctionalInterface
会抛出正是你想要这些例外。
- 你使用的API,以及替代品可供选择。 例如,一些Java API是超载,所以你可以使用
Callable<Void>
,而不是Runnable
。 - 你使用的API,而且没有替代品。 在这种情况下,你仍然没有跳出选项。
- 你可以用在异常
RuntimeException
。 - 您可以通过使用一个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中的未来版本中,当泛型类型的信息进行处理,不仅在编译的时候,而且在运行时被删除。
您的要求不作任何意义。 如果你想通知被叫有关所发生的异常的线程,你可以做到这一点通过回拨机制。 这可以通过一个处理程序,或者你能想到的广播或任何其他。
最简单的方法是定义扩展自己的异常对象RuntimeException
类,而不是Exception
类。