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

219,564

Solution 1

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

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

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

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

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);
        }
    });
}
Share:
219,564

Related videos on Youtube

Bastian
Author by

Bastian

Updated on October 27, 2020

Comments

  • Bastian
    Bastian over 3 years

    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?

  • aalku
    aalku almost 10 years
    If you want it to be a wrapper method I would declare it static. It does not use anything from 'this'.
  • Erich
    Erich about 9 years
    It's sad we have to do this instead of using our native exceptions.... oh Java, it gives and then takes away
  • Stephan
    Stephan almost 9 years
    @kdubb Have a look to marcg's answer: stackoverflow.com/a/27661475/363573. His UtilException helper class provides some work around...
  • Michael Mrozek
    Michael Mrozek over 8 years
    @Stephan That answer was deleted, but it's still available here: stackoverflow.com/a/27661562/309308
  • Gangnus
    Gangnus about 7 years
    This should be marked as a correct answer. +. But I can't say it is a good post. You should elaborate it greatly. How could the own exception help? What are the occurred exceptions? Why haven't you brought the different variants here? Having all example code in references is considered an even forbidden post style here on SO. Your text looks rather as a bunch of comments.
  • Robert Važan
    Robert Važan almost 7 years
    This method was deprecated (unfortunately).
  • aalku
    aalku about 6 years
    You should be able to choose at which level you want to catch them and streams mess with that. The Stream API should let you carry the exception until the final operation (like collect) and be handled there with a handler or be thrown otherwise. stream.map(Streams.passException(x->mightThrowException(x)))‌​.catch(e->whatToDo(e‌​)).collect(...). It sholud expect exceptions and allow you to handle them like futures do.
  • Stelios Adamantidis
    Stelios Adamantidis almost 6 years
    That would instantly fail code review in my company: we are not allowed to throw unchecked exceptions.
  • spi
    spi over 5 years
    @SteliosAdamantidis that rule is incredibly restrictive and counter productive. are you aware that all methods, in all api are authorized to throw all flavours of runtime exceptions without you even having to know it (of course you are)? did you ban javascript for not having the concept of checked exceptions implemented? If I were your lead developer, I would ban checked exceptions instead.
  • Stelios Adamantidis
    Stelios Adamantidis over 5 years
    @spi good thing to know! If I was lead developer I would have done the same! I've banned js for totally different reasons. The wisest thing to do is Remove checked exceptions from Java but there is a big literature on that and it's better not to spam with non-constructive comments.
  • Bruno Carneiro
    Bruno Carneiro almost 5 years
    The Railway pattern (fsharpforfunandprofit.com/posts/recipe-part2) is an alternative to Exceptions patterns. It can be implemented in Java using Either (ibm.com/developerworks/library/j-ft13/index.html). The drawback is that Either is not a native Java class and, when working in legacy code, to add a new feature or pattern could be unacceptable.
  • Jasper de Vries
    Jasper de Vries over 4 years
    Good job on the library! I was about to write something similar.
  • guymac
    guymac over 3 years
    You can also use a traditional for loop, e.g. for (Iterator <A> it = astream.iterator() ; it.hasNext() ;) { it.next().foo(); }