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

时间:2021-11-07 23:02:33

A method I am calling in run() in a class that implements Runnable) is designed to be throwing an exception.

我在实现Runnable的类中调用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. I do want to throw that exception.

问题是,通过try / catch包围它,我使特定的run()无用。我确实想抛出那个例外。

If I specify throws for run() itself, the compiler complains that Exception is not compatible with throws clause in Runnable.run().

如果我为run()本身指定throws,编译器会抱怨Exception与Runnable.run()中的throws子句不兼容。

Ordinarily I'm totally fine with not letting run() throw an exception. But I have unique situation in which I must have that functionality.

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

How to I work around this limitation?

如何解决这个限制?

8 个解决方案

#1


15  

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, e.g.

这个问题的答案很简单。不要使用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(通过处理已检查的异常)。

#2


59  

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并使用ExecutorService.submit()返回的FutureTask.isDone()等待结果。

When isDone() returns true you call 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().

当isDone()返回true时,您调用FutureTask.get()。现在,如果你的Callable抛出了一个Exception,那么FutureTask.get()也将抛出一个Exception,并且你将能够使用Exception.getCause()访问原始的Exception。

#3


16  

If run() threw a checked exception, what would catch it? 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()抛出一个已检查的异常,那会有什么结果呢?由于您没有编写调用它的代码,因此无法将该run()调用括在处理程序中。

You can catch your checked exception in the run() method, and throw an unchekced exception (i.e., RuntimeException) in its place. This will terminate the thread with a stack trace; perhaps that's what you're after.

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

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; that method could store the exception object somewhere, and then your interested thread could find the object in that location.

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

#4


13  

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; throwing an exception has the same effect as not throwing an exception (none).

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

If it's not a Thread target, don't use Runnable. For example, perhaps Callable is a better fit.

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

#5


0  

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. 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.

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

#6


0  

Here's how you could wrap a class with checked exceptions and still be able to cover/test the whole class

以下是如何使用已检查的异常包装类,并且仍然能够覆盖/测试整个类

public final class Json {

private Json() {
}

public static ObjectMapper standard() {
    final ObjectMapper objectMapper = new ObjectMapper();
    objectMapper.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);
    objectMapper.enable(DeserializationFeature.READ_UNKNOWN_ENUM_VALUES_AS_NULL);
    objectMapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
    objectMapper.setDefaultSetterInfo(JsonSetter.Value.construct(Nulls.AS_EMPTY, Nulls.AS_EMPTY));
    objectMapper.findAndRegisterModules();
    return objectMapper;
}

public static String writeValueAsString(final Object value) {
    return transformException(() -> standard().writeValueAsString(value));
}

public static String writeValueAsStringPretty(final Object value) {
    return transformException(() -> standard().writerWithDefaultPrettyPrinter().writeValueAsString(value));
}

static String transformException(final Callable<String> action) {
    try {
        return action.call();
    } catch (Exception e) {
        throw new IllegalStateException(e);
    }
}

}

}

#7


-1  

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.

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

#8


-1  

The easiest way is to define your own exception object which extend the RuntimeException class instead of the Exception class.

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

#1


15  

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, e.g.

这个问题的答案很简单。不要使用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(通过处理已检查的异常)。

#2


59  

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并使用ExecutorService.submit()返回的FutureTask.isDone()等待结果。

When isDone() returns true you call 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().

当isDone()返回true时,您调用FutureTask.get()。现在,如果你的Callable抛出了一个Exception,那么FutureTask.get()也将抛出一个Exception,并且你将能够使用Exception.getCause()访问原始的Exception。

#3


16  

If run() threw a checked exception, what would catch it? 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()抛出一个已检查的异常,那会有什么结果呢?由于您没有编写调用它的代码,因此无法将该run()调用括在处理程序中。

You can catch your checked exception in the run() method, and throw an unchekced exception (i.e., RuntimeException) in its place. This will terminate the thread with a stack trace; perhaps that's what you're after.

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

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; that method could store the exception object somewhere, and then your interested thread could find the object in that location.

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

#4


13  

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; throwing an exception has the same effect as not throwing an exception (none).

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

If it's not a Thread target, don't use Runnable. For example, perhaps Callable is a better fit.

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

#5


0  

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. 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.

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

#6


0  

Here's how you could wrap a class with checked exceptions and still be able to cover/test the whole class

以下是如何使用已检查的异常包装类,并且仍然能够覆盖/测试整个类

public final class Json {

private Json() {
}

public static ObjectMapper standard() {
    final ObjectMapper objectMapper = new ObjectMapper();
    objectMapper.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);
    objectMapper.enable(DeserializationFeature.READ_UNKNOWN_ENUM_VALUES_AS_NULL);
    objectMapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
    objectMapper.setDefaultSetterInfo(JsonSetter.Value.construct(Nulls.AS_EMPTY, Nulls.AS_EMPTY));
    objectMapper.findAndRegisterModules();
    return objectMapper;
}

public static String writeValueAsString(final Object value) {
    return transformException(() -> standard().writeValueAsString(value));
}

public static String writeValueAsStringPretty(final Object value) {
    return transformException(() -> standard().writerWithDefaultPrettyPrinter().writeValueAsString(value));
}

static String transformException(final Callable<String> action) {
    try {
        return action.call();
    } catch (Exception e) {
        throw new IllegalStateException(e);
    }
}

}

}

#7


-1  

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.

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

#8


-1  

The easiest way is to define your own exception object which extend the RuntimeException class instead of the Exception class.

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