How to throw a checked exception from a java thread?
Asked Answered
D

10

44

Hey, I'm writing a network application, in which I read packets of some custom binary format. And I'm starting a background thread to wait for incoming data. The problem is, that the compiler doesn't let me to put any code throwing (checked) exceptions into run(). It says:

run() in (...).Listener cannot implement run() in java.lang.Runnable; overridden method does not throw java.io.IOException

I want the exception to kill the thread, and let it be caught somewhere in the parent thread. Is this possible to achieve or do I have to handle every exception inside the thread?

Dental answered 2/9, 2009 at 17:54 Comment(1)
Have a look at following answer: [How to catch an Exception from a thread][1] [1]: #6546693Neubauer
L
44

Caveat: this may not meet your needs if you have to use the exception mechanism.

If I understand you correctly, you don't actually need the exception to be checked (you've accepted the answer suggesting an unchecked exception) so would a simple listener pattern be more appropriate?

The listener could live in the parent thread, and when you've caught the checked exception in the child thread, you could simply notify the listener.

This means that you have a way of exposing that this will happen (through public methods), and will be able to pass more information than an exception will allow. But it does mean there will be a coupling (albeit a loose one) between the parent and the child thread. It would depend in your specific situation whether this would have a benefit over wrapping the checked exception with an unchecked one.

Here's a simple example (some code borrowed from another answer):

public class ThingRunnable implements Runnable {
    private SomeListenerType listener;
    // assign listener somewhere

    public void run() {
        try {
            while(iHaveMorePackets()) { 
                doStuffWithPacket();
            }
        } catch(Exception e) {
            listener.notifyThatDarnedExceptionHappened(...);
        }
    }
 }

The coupling comes from an object in the parent thread having to be of type SomeListenerType.

Latham answered 2/9, 2009 at 20:3 Comment(3)
Good idea. And yes, you're right, I don't care whether the exception is checked or not, I just wanted a simple way to bring an exception out.Dental
Does the listener code not still actually run in the child thread? I understand that it now has to much of the scope in the parent thread...but it still runs in the child thread.Endothecium
It would run in the child thread, but it matches what's been asked for, I think.Latham
C
50

To be able to send the exception to the parent thread, you can put your background thread in a Callable (it allows throwing also checked exceptions) which you then pass to the submit method of some Executor. The submit method will return a Future which you can then use to get the exception (its get method will throw an ExecutionException which contains the original exception).

Cobber answered 2/9, 2009 at 20:19 Comment(0)
L
44

Caveat: this may not meet your needs if you have to use the exception mechanism.

If I understand you correctly, you don't actually need the exception to be checked (you've accepted the answer suggesting an unchecked exception) so would a simple listener pattern be more appropriate?

The listener could live in the parent thread, and when you've caught the checked exception in the child thread, you could simply notify the listener.

This means that you have a way of exposing that this will happen (through public methods), and will be able to pass more information than an exception will allow. But it does mean there will be a coupling (albeit a loose one) between the parent and the child thread. It would depend in your specific situation whether this would have a benefit over wrapping the checked exception with an unchecked one.

Here's a simple example (some code borrowed from another answer):

public class ThingRunnable implements Runnable {
    private SomeListenerType listener;
    // assign listener somewhere

    public void run() {
        try {
            while(iHaveMorePackets()) { 
                doStuffWithPacket();
            }
        } catch(Exception e) {
            listener.notifyThatDarnedExceptionHappened(...);
        }
    }
 }

The coupling comes from an object in the parent thread having to be of type SomeListenerType.

Latham answered 2/9, 2009 at 20:3 Comment(3)
Good idea. And yes, you're right, I don't care whether the exception is checked or not, I just wanted a simple way to bring an exception out.Dental
Does the listener code not still actually run in the child thread? I understand that it now has to much of the scope in the parent thread...but it still runs in the child thread.Endothecium
It would run in the child thread, but it matches what's been asked for, I think.Latham
F
37

This answer is based on Esko Luontola one but it provides a working example.

Unlike the run() method of the Runnable interface the call() method of Callable allows to throw some exceptions. Here is an implementation example :

public class MyTask implements Callable<Integer> {

    private int numerator;
    private int denominator;

    public MyTask(int n, int d) {
        this.numerator = n;
        this.denominator = d;
    }

    @Override
    // The call method may throw an exception
    public Integer call() throws Exception {
        Thread.sleep(1000);
        if (denominator == 0) {
            throw new Exception("cannot devide by zero");
        } else {
            return numerator / denominator;
        }
    }

}

Executor provides a mechanism to run a Callable inside a thread and to handle any kind of exceptions :

public class Main {

    public static void main(String[] args) {

        // Build a task and an executor
        MyTask task = new MyTask(2, 0);
        ExecutorService threadExecutor = Executors.newSingleThreadExecutor();

        try {
            // Start task on another thread
            Future<Integer> futureResult = threadExecutor.submit(task);

            // While task is running you can do asynchronous operations
            System.out.println("Something that doesn't need the tasks result");

            // Now wait until the result is available
            int result = futureResult.get();
            System.out.println("The result is " + result);
        } catch (ExecutionException e) {
            // Handle the exception thrown by the child thread
            if (e.getMessage().contains("cannot devide by zero"))
                System.out.println("error in child thread caused by zero division");
        } catch (InterruptedException e) {
            // This exception is thrown if the child thread is interrupted.
            e.printStackTrace();
        }
    }
}
Forbearance answered 24/9, 2011 at 13:24 Comment(3)
This solves the problem of uncaught exceptions, but might introduce problems of its own. The call to get() will block until the callable task returns. This means that you're no longer getting any parallelism out of the background thread. Worse, if the task is continuous/long-running (like waiting for network packets in a loop), the Callable will never return and your main thread is permanently blocked. I don't mean to imply that there are no applications where this pattern makes sense (I'm sure there are plenty), just that you need to be careful.Forensic
Good point. In a real example you wouldn't call get right after submit.Forbearance
In a real example, you might initiate N background operations in parallel and wait on the results of M background operations where M <= N to make a decision. In that case, you would call get right after submit.Bary
W
9

What I do is to catch the exception in the thread and store it as a member variable of the Runnable. This exception is then exposed via a getter on the Runnable. I then scan all the threads from the parent to see if any had exceptions, and take the appropriate action.

Whimsey answered 2/9, 2009 at 19:37 Comment(4)
May I ask (in case my answer is wrong), why store a variable as a getter and scan for it rather than using a listener mechanism?Latham
Fair question. Either approach works. I think I'll try your suggestion next time around, and see If I prefer that.Whimsey
See my comment on Grundlefleck's answer - I believe this solution does actually get the exception handling back in to the parent thread, whereas Grundlefleck's solution doesn't. (Grundlefleck's fixes scope problems - but this one fixes problems that are really related to thread context.)Endothecium
The advantage to this approach is there's no coupling. Whereas Grundlefleck's solution a reference to a Listener class, Don Branson's solution makes the ´Runnable´ completely independent of other code.Harmonious
H
6

If you really cannot do anything useful when the exception is raised you can wrap the checked exception in a RuntimeException.

try {
    // stuff
} catch (CheckedException yourCheckedException) {
    throw new RuntimeException("Something to explain what is happening", yourCheckedException);
}
Harrisharrisburg answered 2/9, 2009 at 18:3 Comment(1)
Always add a description when throwing an exception, even if it just is to wrap. throw new RuntimeException("Wrapping exception to allow it to bubble up to the catcher in foo.bar.Main()", e); The ones called at 3 AM when the code breaks will appreciate it when they stare at the stacktrace.Pained
I
3

the thread can't throw the exception to any other thread (nor to the main thread). and you cannot make the inherited run() method throw any checked exceptions since you can only throw less than the inherited code, not more.

Installation answered 2/9, 2009 at 18:6 Comment(1)
Good point about not being able to directly "throw" the exception to the parent thread.Gamic
S
1

If your thread's code throw a RuntimeExpection, you doesn't need to add run() throw Exception.

But use this solution only when appropriate because this can be a bad pratice: http://java.sun.com/docs/books/tutorial/essential/exceptions/runtime.html

Any RuntimeException or unchecked Exception can help you. Maybe you'll need to create your own RuntimeException

Scroggins answered 2/9, 2009 at 18:5 Comment(1)
Note that this approach will hide the exception from the parent thread.Gamic
Y
0

On the assumption that your code is in some kind of loop, you'd write:

public class ThingRunnable implements Runnable {
  public void run() {
    try {
      while(iHaveMorePackets()) { 
        doStuffWithPacket()
      }
    } catch(Exception e) {
      System.out.println("Runnable terminating with exception" + e );
    }
  }
}

The exception will automatically break you out of your loop, and at the end of the run() method, the thread will stop.

Yuonneyup answered 2/9, 2009 at 18:10 Comment(2)
Small point: your example has an interface with implementation in it, should probably be "public class ThingRunnable implements Runnable".Latham
Thanks, Grundlefleck, you're absolutely right :-) Goes to show what happens when you answer questions before you've had enough coffee in the day. I've updated the text to say 'class' instead.Yuonneyup
R
0

Use this Runnable to create your Thread:

public abstract class TryRunner implements Runnable{
    protected abstract void tryToRun();
    protected void onException(Exception e){}

    @Override 
    final public void run() { 
        try{ tryToRun(); }catch(Exception e){ e.printStackTrace(); onException(e); } 
    }
}
Rigby answered 1/4, 2021 at 5:7 Comment(0)
R
-1

Wrapping your exception inside a RuntimeException seems to do the trick.

someMethod() throws IOException
{
    try
    {
        new Thread(() ->
        {
            try
            {
                throw new IOException("a checked exception thrown from within a running thread");
            }
            catch(IOException ex)
            {
                throw new RuntimeException("a wrapper exception", ex); // wrap the checked exception inside an unchecked exception and throw it
            }
        }).start();
    }
    catch(RuntimeException ex) // catch the wrapped exception sent from within the thread
    {
        if(ex.getCause() instanceof IOException)
            throw ex.getCause; // unwrap the checked exception using getCause method and use it however you need
        else
            throw ex;
    }
}
Ratcliff answered 18/4, 2016 at 7:33 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.