Java 8: How can I work with exception methods in threads?

Suppose I have a class and a method

class A { void foo() throws Exception() { ... } } 

Now, I would like to call foo for each instance of A passed by the stream, for example:

 void bar() throws Exception { Stream<A> as = ... as.forEach(a -> a.foo()); } 

Question: How to handle the exception? The code does not compile on my machine because I do not handle possible exceptions that foo () may throw. throws Exception of bar seems useless here. Why is this?

+105
java java-8 java-stream unhandled-exception
May 8 '14 at 17:24
source share
7 answers

You need to wrap the method call in another, where you did not select checked exceptions. You can still throw everything that is a subclass of RuntimeException .

A normal wrapping idiom is something like:

 private void safeFoo(final A a) { try { a.foo(); } catch (Exception ex) { throw new RuntimeException(ex); } } 

(Supertype Exception used only as an example, never try to catch it)

Then you can call it with: as.forEach(this::safeFoo) .

+96
May 08 '14 at 17:35
source share

If you want to use foo , and you prefer to throw the exception as is (without wrapping), you can just use the Java for loop instead (after turning Stream into Iterable with some trickery ):

 for (A a : (Iterable<A>) as::iterator) { a.foo(); } 

This is at least what I do in my JUnit tests, where I don't want to worry about wrapping my checked exceptions (and actually prefer my tests throwing deployed original ones)

+21
Sep 19 '15 at 13:30
source share

This question may be a little old, but since I think the β€œright” answer here is only one way that can lead to some problems that are hidden in the future. Even if there is a slight controversy , checked exceptions exist for some reason.

The most elegant way, in my opinion, you can find here, Misha here. Cumulative runtime exceptions in Java 8 threads by simply performing actions in the "futures". Thus, you can start all working parts and collect broken Exceptions as one. Otherwise, you can collect them all on the list and process them later.

A similar approach comes from Benji Weber . He suggests creating his own type for collecting workers and non-working parts.

Depending on what you really want to achieve, a simple mapping between input values ​​and Output values. Values ​​may also work for you.

If you do not like any of these methods, consider using (depending on the Original Exception) at least your own exception.

+13
Oct 19 '15 at 15:51
source share

I suggest using the Google Guava Throwables class

spread ( Throwable )

It propagates as if it is an instance of RuntimeException or Error, or, in extreme cases, it wraps it in a RuntimeException and then throws it. **

 void bar() { Stream<A> as = ... as.forEach(a -> { try { a.foo() } catch(Exception e) { throw Throwables.propagate(e); } }); } 
+9
Dec 01 '16 at 13:32
source share

You can wrap and deploy exceptions this way.

 class A { void foo() throws Exception { throw new Exception(); } }; interface Task { void run() throws Exception; } static class TaskException extends RuntimeException { private static final long serialVersionUID = 1L; public TaskException(Exception e) { super(e); } } void bar() throws Exception { Stream<A> as = Stream.generate(()->new A()); try { as.forEach(a -> wrapException(() -> a.foo())); // or a::foo instead of () -> a.foo() } catch (TaskException e) { throw (Exception)e.getCause(); } } static void wrapException(Task task) { try { task.run(); } catch (Exception e) { throw new TaskException(e); } } 
+7
May 13 '14 at 15:48
source share

You might want to do one of the following:

  • throw a checked exception
  • wrap it and throw an unchecked exception, or
  • catch the exception and stop spreading.

Several libraries make this easy. The example below is written using the NoException library.

 // Propagate checked exception as.forEach(Exceptions.sneak().consumer(A::foo)); // Wrap and propagate unchecked exception as.forEach(Exceptions.wrap().consumer(A::foo)); as.forEach(Exceptions.wrap(MyUncheckedException::new).consumer(A::foo)); // Catch the exception and stop propagation (using logging handler for example) as.forEach(Exceptions.log().consumer(Exceptions.sneak().consumer(A::foo))); 
+4
Jun 16 '17 at 3:56 on
source share

More readable way:

 class A { void foo() throws MyException() { ... } } 

Just hide it in a RuntimeException to get past forEach()

  void bar() throws MyException { Stream<A> as = ... try { as.forEach(a -> { try { a.foo(); } catch(MyException e) { throw new RuntimeException(e); } }); } catch(RuntimeException e) { throw (MyException) e.getCause(); } } 

Although at the moment I will not be against someone if they say skip threads and go with a for loop if:

  • you do not create your stream using Collection.stream() , i.e. not a straightforward translation into a for loop.
  • you are trying to use parallelstream()
+1
Mar 25 '18 at 1:39
source share



All Articles