[英]Is there a way to make Runnable's run() throw an exception?
A method I am calling in run() in a class that implements Runnable ) is designed to be throwing an exception.我在实现Runnable的 class 中调用run()的方法)旨在引发异常。
But the Java compiler won't let me do that and suggests that I surround it with try/catch.但是 Java 编译器不允许我这样做,并建议我用 try/catch 包围它。
The problem is that by surrounding it with a try/catch I make that particular run() useless.问题是,通过用 try/catch 包围它,我使那个特定的 run()变得无用。 I do want to throw that exception.
我确实想抛出那个异常。
If I specify throws
for run() itself, the compiler complains that Exception is not compatible with throws clause in Runnable.run()
.如果我为run()本身指定
throws
,编译器会抱怨Exception is not compatible with throws clause in Runnable.run()
。
Ordinarily I'm totally fine with not letting run() throw an exception.通常我完全可以不让run()抛出异常。 But I have unique situation in which I must have that functionality.
但是我有一个独特的情况,我必须拥有该功能。
How to I work around this limitation?我该如何解决这个限制?
You can use a Callable
instead, submitting it to an ExecutorService
and waiting for result with FutureTask.isDone()
returned by the ExecutorService.submit()
. 您可以使用
Callable
相反,它提交给ExecutorService
,并等待结果FutureTask.isDone()
的返回ExecutorService.submit()
When isDone()
returns true you call FutureTask.get()
. 当
isDone()
返回true时,您调用FutureTask.get()
。 Now, if your Callable
has thrown an Exception
then FutureTask.get()
wiill throw an Exception
too and the original Exception you will be able to access using Exception.getCause()
. 现在,如果你的
Callable
抛出了一个Exception
那么FutureTask.get()
也会抛出一个Exception
并且你可以使用Exception.getCause()
来访问原始的Exception。
If run()
threw a checked exception, what would catch it? 如果
run()
抛出一个已检查的异常,那会有什么结果呢? There's no way for you to enclose that run()
call in a handler, since you don't write the code that invokes it. 您无法在处理程序中包含该
run()
调用,因为您没有编写调用它的代码。
You can catch your checked exception in the run()
method, and throw an unchekced exception (ie, RuntimeException
) in its place. 您可以在
run()
方法中捕获已检查的异常,并在其位置抛出未检查的异常(即RuntimeException
)。 This will terminate the thread with a stack trace; 这将使用堆栈跟踪终止线程; perhaps that's what you're after.
也许这就是你所追求的。
If instead you want your run()
method to report the error somewhere, then you can just provide a callback method for the run()
method's catch
block to call; 如果您希望
run()
方法在某处报告错误,那么您可以为run()
方法的catch
块提供一个回调方法来调用; that method could store the exception object somewhere, and then your interested thread could find the object in that location. 该方法可以在某处存储异常对象,然后您感兴趣的线程可以在该位置找到该对象。
If you want to pass a class that implements Runnable
into the Thread
framework, then you have to play by that framework's rules, see Ernest Friedman-Hill's answer why doing it otherwise is a bad idea. 如果你想将一个实现
Runnable
的类传递给Thread
框架,那么你必须遵循该框架的规则,参见Ernest Friedman-Hill的答案,为什么这样做是一个坏主意。
I have a hunch, though, that you want to call run
method directly in your code, so your calling code can process the exception. 不过,我有一种预感,你想直接在代码中调用
run
方法,因此你的调用代码可以处理异常。
The answer to this problem is easy. 这个问题的答案很简单。 Do not use
Runnable
interface from Thread library, but instead create your own interface with the modified signature that allows checked exception to be thrown, eg 不要使用Thread库中的
Runnable
接口,而是使用修改后的签名创建自己的接口,该签名允许抛出已检查的异常,例如
public interface MyRunnable
{
void myRun ( ) throws MyException;
}
You may even create an adapter that converts this interface to real Runnable
( by handling checked exception ) suitable for use in Thread framework. 您甚至可以创建一个适配器,将此接口转换为适合在Thread框架中使用的真实
Runnable
(通过处理已检查的异常)。
Yes, there is a way to throw a checked exception from the run()
method, but it's so terrible I won't share it. 是的,有一种方法可以从
run()
方法中抛出一个已检查的异常,但它太可怕了,我不会分享它。
Here's what you can do instead; 这是你可以做的事情; it uses the same mechanism that a runtime exception would exercise:
它使用与运行时异常相同的机制:
@Override
public void run() {
try {
/* Do your thing. */
...
} catch (Exception ex) {
Thread t = Thread.currentThread();
t.getUncaughtExceptionHandler().uncaughtException(t, ex);
}
}
As others have noted, if your run()
method is really the target of a Thread
, there's no point in throwing an exception because it is unobservable; 正如其他人所指出的,如果你的
run()
方法确实是Thread
的目标,那么抛出异常是没有意义的,因为它是不可观察的; throwing an exception has the same effect as not throwing an exception (none). 抛出异常与不抛出异常(无)具有相同的效果。
If it's not a Thread
target, don't use Runnable
. 如果它不是
Thread
目标,请不要使用Runnable
。 For example, perhaps Callable
is a better fit. 例如,也许
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;
}
Some people try to convince you that you have to play by the rules. 有些人试图说服你必须遵守规则。 Listen, but whether you obey, you should decide yourself depending on your situation.
听着,但不管你是否服从,你应该根据自己的情况决定自己。 The reality is "you SHOULD play by the rules" (not "you MUST play by the rules").
现实是“你应该遵守规则”(而不是“你必须遵守规则”)。 Just be aware that if you do not play by the rules, there might be consequences.
请注意,如果您不遵守规则,可能会产生后果。
The situation not only applies in the situation of Runnable
, but with Java 8 also very frequently in the context of Streams and other places where functional interfaces have been introduced without the possibility to deal with checked exceptions. 这种情况不仅适用于
Runnable
的情况,而且在Streams和其他已引入功能接口的地方也非常频繁地使用Java 8,而无法处理已检查的异常。 For example, Consumer
, Supplier
, Function
, BiFunction
and so on have all been declared without facilities to deal with checked exceptions. 例如,
Consumer
, Supplier
, Function
, BiFunction
等都已声明,没有设施来处理已检查的异常。
So what are the situations and options? 那么情况和选择是什么? In the below text,
Runnable
is representative of any functional interface that doesn't declare exceptions, or declares exceptions too limited for the use case at hand. 在下面的文本中,
Runnable
代表没有声明异常的任何功能接口,或者声明对于手头的用例来说太有限的异常。
Runnable
somewhere yourself, and could replace Runnable
with something else. Runnable
,并且可以用其他东西替换Runnable
。
Runnable
with Callable<Void>
. Callable<Void>
替换Runnable
。 Basically the same thing, but allowed to throw exceptions; return null
in the end, which is a mild annoyance. return null
,这是一个轻微的烦恼。 Runnable
with your own custom @FunctionalInterface
that can throw exactly those exceptions that you want. @FunctionalInterface
替换Runnable
,它可以准确地抛出您想要的那些异常。 Callable<Void>
instead of Runnable
. Callable<Void>
而不是Runnable
。 RuntimeException
. RuntimeException
包装异常。 You can try the following. 您可以尝试以下方法。 It's a bit of a hack, but sometimes a hack is what we need.
这有点像黑客,但有时黑客是我们需要的。 Because, whether an exception should be checked or unchecked is defined by its type, but practically should actually be defined by the situation.
因为,是否应该检查或取消选中例外是由其类型定义的,但实际上应该根据情况来定义。
@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;
}
I prefer this over new RuntimeException(t)
because it has a shorter stack trace. 我比
new RuntimeException(t)
更喜欢它,因为它有一个较短的堆栈跟踪。
You can now do: 你现在可以这样做:
executorService.submit((ThrowingRunnable) () -> {throw new Exception()});
Disclaimer: The ability to perform unchecked casts in this way might actually be removed in future versions of Java, when generics type information is processed not only at compile time, but also at runtime. 免责声明:在Java的未来版本中,当不仅在编译时处理泛型类型信息,而且在运行时处理泛型类型信息时,实际上可以删除以这种方式执行未经检查的强制转换的能力。
I think a listener pattern might help you with this scenario. 我认为听众模式可能会帮助您解决这个问题。 In case of an exception happening in your
run()
method, use a try-catch block and in the catch send a notification of an exception event. 如果在
run()
方法中发生异常,请使用try-catch块并在catch中发送异常事件的通知。 And then handle your notification event. 然后处理您的通知事件。 I think this would be a cleaner approach.
我认为这将是一种更清洁的方法。 This SO link gives you a helpful pointer to that direction.
这个SO链接为您提供指向该方向的有用指针。
Yes, you can throw checked exceptions from the run() method.是的,您可以从 run() 方法中抛出已检查的异常。 It can be done with generics by tricking the compiler.
可以通过欺骗编译器使用 generics 来完成。 Look at this code:
看看这段代码:
public static void main(String[] args) {
new Main().throwException();
}
public void throwException() {
Runnable runnable = () -> throwAs(new Exception());
new Thread(runnable).start();
}
private <T extends Throwable> void throwAs(Throwable t) throws T {
throw ( T ) t;
}
This might be helpful if you want to throw checked exceptions from the run() method of Runnable如果您想从 Runnable 的 run() 方法中抛出已检查的异常,这可能会有所帮助
Your requirement doesn't make any sense. 你的要求没有任何意义。 If you want to notify the called of the thread about an exception that happened, you could do that through a call back mechanism.
如果要通知线程调用者发生的异常,可以通过回调机制来实现。 This can be through a Handler or a broadcast or whatever else you can think of.
这可以通过处理程序或广播或您能想到的任何其他内容。
最简单的方法是定义自己的异常对象,该对象扩展RuntimeException
类而不是Exception
类。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.