Question

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?

Was it helpful?

Solution

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

OTHER TIPS

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)

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.

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

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);
        }
    });
}

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);
    }
}

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()
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top