2

I currently have the following sample code that I am trying to convert OutputStream to InputStream, which I got the idea from Method 2 in http://blog.ostermiller.org/convert-java-outputstream-inputstream

But my question here is, the save method could throw IOException, and I would like to catch that and re-throw that as part of this getInputStream method.

I am trying to wrap the IOException thrown by save(out) to a runtime exception, but I know that this runtime exception cannot be caught by the parent thread. So I am stuck on this, can anyone point me some directions?

public InputStream getInputStream() throws IOException { PipedInputStream in = new PipedInputStream(); PipedOutputStream out = new PipedOutputStream(in); Thread t = new Thread(new Runnable() { public void run () { try { save(out); // this save method can throw IOException } catch (IOException e) { throw new RuntimeException("Failed to save entries to output stream", e); } } }); t.start(); return in; } private void save(OutputStream out) throws IOException {...} 

I have read How to catch an Exception from a thread but felt my question is still different, because I want to re-throw the exception in parent thread, the question above solves the problem that catches the exception only

6
  • Possible duplicate, check answers here, especially second one : stackoverflow.com/questions/10351926/… Commented May 17, 2018 at 18:52
  • 1
    It feels like you're duplicating the machinery of Future, Callable and ExecutorService. I'd like to know why those don't work for you before trying to re-invent them. Commented May 17, 2018 at 18:53
  • @markspace thx for pointing out these, I am new to multi-threading, let me dig into those concepts a bit! Commented May 17, 2018 at 18:56
  • 1
    Basically, Runnable doesn't throw exceptions, but Callable does (it's the new improved Runnable) and if you pass a Callable to an ExecutorService you get back a Future that does the work of passing any exception back to you. Commented May 17, 2018 at 19:02
  • 1
    @markspace, Better to say that the Runnable interface and the classes that use it were not designed with exceptions in mind. In fact, a Runnable object's run() method can throw unchecked exceptions and other Throwable objects, and that is the reason why every Thread has to have an uncaught exception handler. Commented May 17, 2018 at 20:10

2 Answers 2

1

But my question here is, the save method could throw IOException, and I would like to catch that and re-throw that as part of this getInputStream method.

You can't do that, because an exception can be raised in the background thread executing save() long after getInputStream() returns.

If save() can throw an exception for some reason other than an IOException from its PipedOutputStream, and you want to convey some information about that failure to the thread that is reading from the PipedInputStream, submitting a Callable to an ExecutorService is probably the right approach. An example of this case would be that save() queries a database, and writes the results to a stream; if query fails, you want to log that SQLException in the thread that is reading that stream. The reading thread could read the PipedInputStream, and then check the Future it received from submitting the task to the ExecutorService to see if it completed abnormally.

But if you don't need any information from the exception thrown by save(), and just want to throw an exception in the thread reading from the corresponding PipedInputStream, simply let the background thread die. This will raise a "broken pipe" IOException in the main thread when it attempts to read from its PipedInputStream.

Sign up to request clarification or add additional context in comments.

Comments

0

While all the comments that lead to uncaught exception handler and similar stuff are correct, I would like to post this answer as an alternative.

You can use an ExecutorService which will return you a Future and then you can catch ExecutionException when getting the result, something like this (typing directly here, might need some validation):

ExecutorService pool = Executors.newFixedThreadPool(1); Future result = pool.submit(this::save); result.get(); // will throw ExecutionException 

1 Comment

Thx! one more bit, save(out) method here will throw IOException, so Runnable is not fit here, we need to wrap that with Callable instead.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.