Java 8: How do I work with exception throwing methods in streams?

JavaJava 8Unhandled ExceptionJava Stream

Java Problem Overview


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 delivered by a stream like:

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

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

Java Solutions


Solution 1 - Java

You need to wrap your method call into another one, where you do not throw checked exceptions. You can still throw anything 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 Exception is only used as example, never try to catch it yourself)

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

Solution 2 - Java

If all you want is to invoke foo, and you prefer to propagate the exception as is (without wrapping), you can also just use Java's for loop instead (after turning the Stream into an 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 go through the trouble of wrapping my checked exceptions (and in fact prefer my tests to throw the unwrapped original ones)

Solution 3 - Java

This question may be a little old, but because I think the "right" answer here is only one way which can lead to some issues hidden Issues later in your code. Even if there is a little Controversy, Checked Exceptions exist for a reason.

The most elegant way in my opinion can you find was given by Misha here Aggregate runtime exceptions in Java 8 streams by just performing the actions in "futures". So you can run all the working parts and collect not working Exceptions as a single one. Otherwise you could collect them all in a List and process them later.

A similar approach comes from Benji Weber. He suggests to create an own type to collect working and not working parts.

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

If you don't like any of these ways consider using (depending on the Original Exception) at least an own exception.

Solution 4 - Java

You might want to do one of the following:

  • propagate checked exception,
  • wrap it and propagate unchecked exception, or
  • catch the exception and stop propagation.

Several libraries let you do that easily. Example below is written using my 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)));

Solution 5 - Java

I suggest to use Google Guava Throwables class

> propagate(Throwable throwable) > > Propagates throwable as-is if it is an > instance of RuntimeException or Error, or else as a last resort, wraps > it in a RuntimeException and then propagates.**

void bar() {
    Stream<A> as = ...
    as.forEach(a -> {
        try {
            a.foo()
        } catch(Exception e) {
            throw Throwables.propagate(e);
        }
    });
}

UPDATE:

Now that it is deprecated use:

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

Solution 6 - Java

You can wrap and unwrap 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);
	}
}

Solution 7 - Java

More readable way:

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

Just hide it in a RuntimeException to get it 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 this point I won't hold against someone if they say skip the streams and go with a for loop, unless:

  • you're not creating your stream using Collection.stream(), i.e. not straight forward translation to a for loop.
  • you're trying to use parallelstream()

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionBastianView Question on Stackoverflow
Solution 1 - JavaskiwiView Answer on Stackoverflow
Solution 2 - JavaavandeursenView Answer on Stackoverflow
Solution 3 - JavaMarianoView Answer on Stackoverflow
Solution 4 - JavaRobert VažanView Answer on Stackoverflow
Solution 5 - JavayanefedorView Answer on Stackoverflow
Solution 6 - JavaaalkuView Answer on Stackoverflow
Solution 7 - JavaKashyapView Answer on Stackoverflow