Is there a way to make Runnable's run() throw an exception?

87,248

Solution 1

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.

I have a hunch, though, that you want to call run method directly in your code, so your calling code can process the exception.

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.

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.

Solution 2

You can use a Callable instead, submitting it to an ExecutorService and waiting for result with FutureTask.isDone() returned by the ExecutorService.submit().

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

Solution 3

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.

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.

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.

Solution 4

Yes, there is a way to throw a checked exception from the run() method, but it's so terrible I won't share it.

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

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

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

}
Share:
87,248
Regex Rookie
Author by

Regex Rookie

Fascinated by this new (to me) world of regular expressions.

Updated on September 17, 2020

Comments

  • Regex Rookie
    Regex Rookie over 3 years

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

    But the Java compiler won't let me do that and suggests that I surround it with 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.

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

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

    How to I work around this limitation?

  • Dormouse
    Dormouse about 7 years
    And how would you get hold of this RuntimeException when it occurs my dear sir?
  • Dinesh
    Dinesh over 6 years
    But does this cause the process to crash when it throws??
  • brady
    brady over 6 years
    @DineshVG No, only a bug in the JVM can cause a true crash. The default exception handler just prints the exception. If you are used to seeing the process exit after that, it's because that thread was the only thread running, and it terminated.
  • Dinesh
    Dinesh over 6 years
    I tried (in android instrumentation test cases) using this for a soap call, where if I get a 400 from Soap call, I throw an exception. This soap call is called from a thread while starting the test case. This thread uses this t.getUncaughtExceptionHandler().uncaughtException(t, ex); to throw it to the instrumentation test case. Adding this one line causes the process to crash!. Don't know why.
  • brady
    brady over 6 years
    @DineshVG In that environment, does Thread.getDefaultUncaughtExceptionHandler() return null? If not, what is the type of the result? What happens if, instead of calling uncaughtException(), you wrap the checked exception in a RuntimeException and throw that?
  • Dinesh
    Dinesh over 6 years
    RuntimeException also causes the application to crash.
  • brady
    brady over 6 years
    @DineshVG Android may be setting a default uncaught exception handler that does this. That's why I asked if Thread.getDefaultUncaughtExceptionHandler() returns null; if not, Android is providing a default, in order to offer reporting, etc. But you can set it to do what you want. There's more info here.
  • Kalle Richter
    Kalle Richter about 6 years
    That alone doesn't answer the question.
  • Richard Le Mesurier
    Richard Le Mesurier about 6 years
    Such a simple solution arrived at just by not thinking "in the box". Of course, a Runnable is just a simple interface and we can make our own. Not useful for the thread use-case but for passing different "runnable" chunks of code around this is perfect.
  • Christian Hujer
    Christian Hujer over 5 years
    The first part is not a good argument. "If main() threw a checked exception, what would catch it?" "If run() threw an unchecked exception, what would catch it?"
  • Shrdi
    Shrdi about 3 years
    That means we have to create another MyTimerTask or MyThread to use MyRunable ....