365

How can I throw CHECKED exceptions from inside Java 8 lambda, used in a stream for example?

In other words, I want to make code like this compile:

public List<Class> getClasses() throws ClassNotFoundException {     

    List<Class> classes = 
        Stream.of("java.lang.Object", "java.lang.Integer", "java.lang.String")
              .map(className -> Class.forName(className))
              .collect(Collectors.toList());                  
    return classes;
    }

This code does not compile, since the Class.forName() method above throws ClassNotFoundException, which is checked.

Please note I do NOT want to wrap the checked exception inside a runtime exception and throw the wrapped unchecked exception instead. I want to throw the checked exception itself, and without adding ugly try/catches to the stream.

GhostCat
  • 137,827
  • 25
  • 176
  • 248
Marcelo Glasberg
  • 29,013
  • 23
  • 109
  • 133

18 Answers18

342

The simple answer to your question is: You can't, at least not directly. And it's not your fault. Oracle messed it up. They cling on the concept of checked exceptions, but inconsistently forgot to take care of checked exceptions when designing the functional interfaces, streams, lambda etc. That's all grist to the mill of experts like Robert C. Martin who call checked exceptions a failed experiment.

In my opinion, this is a huge bug in the API and a minor bug in the language specification.

The bug in the API is that it provides no facility for forwarding checked exceptions where this actually would make an awful lot of sense for functional programming. As I will demonstrate below, such a facility would've been easily possible.

The bug in the language specification is that it does not allow a type parameter to infer a list of types instead of a single type as long as the type parameter is only used in situations where a list of types is permissable (throws clause).

Our expectation as Java programmers is that the following code should compile:

import java.util.ArrayList;
import java.util.List;
import java.util.stream.Stream;

public class CheckedStream {
    // List variant to demonstrate what we actually had before refactoring.
    public List<Class> getClasses(final List<String> names) throws ClassNotFoundException {
        final List<Class> classes = new ArrayList<>();
        for (final String name : names)
            classes.add(Class.forName(name));
        return classes;
    }

    // The Stream function which we want to compile.
    public Stream<Class> getClasses(final Stream<String> names) throws ClassNotFoundException {
        return names.map(Class::forName);
    }
}

However, it gives:

cher@armor1:~/playground/Java/checkedStream$ javac CheckedStream.java 
CheckedStream.java:13: error: incompatible thrown types ClassNotFoundException in method reference
        return names.map(Class::forName);
                         ^
1 error

The way in which the functional interfaces are defined currently prevents the Compiler from forwarding the exception - there is no declaration which would tell Stream.map() that if Function.apply() throws E, Stream.map() throws E as well.

What's missing is a declaration of a type parameter for passing through checked exceptions. The following code shows how such a pass-through type parameter actually could have been declared with the current syntax. Except for the special case in the marked line, which is a limit discussed below, this code compiles and behaves as expected.

import java.io.IOException;
interface Function<T, R, E extends Throwable> {
    // Declare you throw E, whatever that is.
    R apply(T t) throws E;
}   

interface Stream<T> {
    // Pass through E, whatever mapper defined for E.
    <R, E extends Throwable> Stream<R> map(Function<? super T, ? extends R, E> mapper) throws E;
}   

class Main {
    public static void main(final String... args) throws ClassNotFoundException {
        final Stream<String> s = null;

        // Works: E is ClassNotFoundException.
        s.map(Class::forName);

        // Works: E is RuntimeException (probably).
        s.map(Main::convertClass);

        // Works: E is ClassNotFoundException.
        s.map(Main::throwSome);

        // Doesn't work: E is Exception.
        s.map(Main::throwSomeMore);  // error: unreported exception Exception; must be caught or declared to be thrown
    }   
    
    public static Class convertClass(final String s) {
        return Main.class;
    }   

    static class FooException extends ClassNotFoundException {}

    static class BarException extends ClassNotFoundException {}

    public static Class throwSome(final String s) throws FooException, BarException {
        throw new FooException();
    }   

    public static Class throwSomeMore(final String s) throws ClassNotFoundException, IOException  {
        throw new FooException();
    }   
}   

In the case of throwSomeMore we would like to see IOException being missed, but it actually misses Exception.

This is not perfect because type inference seems to be looking for a single type, even in the case of exceptions. Because the type inference needs a single type, E needs to resolve to a common super of ClassNotFoundException and IOException, which is Exception.

A tweak to the definition of type inference is needed so that the compiler would look for multiple types if the type parameter is used where a list of types is permissible (throws clause). Then the exception type reported by the compiler would be as specific as the original throws declaration of the checked exceptions of the referenced method, not a single catch-all super type.

The bad news is that this means that Oracle messed it up. Certainly they won't break user-land code, but introducing exception type parameters to the existing functional interfaces would break compilation of all user-land code that uses these interfaces explicitly. They'll have to invent some new syntax sugar to fix this.

The even worse news is that this topic was already discussed by Brian Goetz in 2010 (https://blogs.oracle.com/briangoetz/entry/exception_transparency_in_java, http://mail.openjdk.java.net/pipermail/lambda-dev/2010-June/001484.html) but I'm informed that this investigation ultimately did not pan out, and that there is no current work at Oracle that I know of to mitigate the interactions between checked exceptions and lambdas.

vladr
  • 65,483
  • 18
  • 129
  • 130
Christian Hujer
  • 17,035
  • 5
  • 40
  • 47
  • 22
    Interesting. I believe some people appreciate streams for allowing easier parallel code, while others for allowing cleaner code. Brian Goetz obviously cares more about parallelism (since he authored Java Concurrency in Practice), while Robert Martin cares more about clean code (since he authored the Clean Code book). Boilerplate try/catches are a minor price to pay for parallelism, so it's no wonder Brian Goetz is not appalled by the problems of using checked exceptions inside streams. Also no wonder Robert Martin hates checked exceptions since they add to the clutter. – Marcelo Glasberg Dec 27 '14 at 17:30
  • 7
    I predict that, in a few years, the difficulty of dealing with checked exceptions inside streams will lead to one of these two outcomes: People will just stop using checked exceptions, OR everybody will start using some hack very much like the one I posted in my UtilException answer. I would have bet Java-8 streams are the last nail on the coffin of checked exceptions, were not for the fact that checked exceptions are part of the JDK. Although I like and use checked exceptions in business code (for some specific use cases), I would have preferred all common JDK exceptions extended Runtime. – Marcelo Glasberg Dec 27 '14 at 17:32
  • 5
    I wonder why Oracle thinks it's OK to create new functionality which is fundamentally incompatible with other important old functionality, and respond to the criticism by saying: just add try/catches! Maybe (conspiracy theory warning!!!) they also decided they are a failed experiment, and are creating problems so that the consensus builds that checked should be deprecated. Then, in a few years, they may just remove the syntactic sugar that forces us to add the throws clause. – Marcelo Glasberg Dec 27 '14 at 17:34
  • Small suggestion: Why not replace `for (final String name : names) classes.add(Class.forName(name));` with a `forEach` lambda? – Unihedron Dec 28 '14 at 12:10
  • 11
    @Unihedro The problem remains that the functional interfaces do not forward exceptions. I would need the `try-catch` block *inside* the lambda, and that simply doesn't make any sense. As soon as `Class.forName` is used in some way in the lambda, for example in `names.forEach(Class::forName)`, the problem is there. Basically, methods which throw checked exceptions have been excluded from participating in functional programming as functional interfaces directly, by (poor!) design. – Christian Hujer Dec 28 '14 at 17:15
  • 2
    Since the `Stream` intermediate operations are lazily evaluated (when the terminal operation is executed), the proposition for a `map` operation that rethrows the lambda exception would not work: `map` does not immediately call the `lambda`. The only way to circumvent this would be to have a second type parameter on `Stream` for the exception, and have all terminal operations throw this exception type. But I think this would only clutter the API without much added value in most cases. Maybe a `Stream` wrapper could do this? (with specific functional interfaces) – Didier L Jun 22 '15 at 17:03
  • 3
    That the `Stream` operations are lazily evaluated isn't the problem. I wouldn't expect the `map` operation to throw the exception, I would expect the `Stream` to throw the exception whereever it occurs. For that, the exception would need to be propagated through the interfaces. With unchecked exceptions it works that way because propagation is implciit because of the implicit `throws RuntimeException, Error`. For checked exceptions, the propagation would need an exception type parameter and just a little extension of the smartness already introduced with Java 7 multi-catch. – Christian Hujer Jun 22 '15 at 17:10
  • 32
    @ChristianHujer The "Exception transparency" exploration was just that -- an exploration (one which originated in the BGGA proposal). Upon deeper analysis, we found it to offer a poor balance of value and complexity, and it had some serious problems (led to undecidable inference problems, and "catch X" was unsound, among others.) It is extremely common that a language idea seems promising -- even "obvious" -- but after deeper exploration, turned out to be flawed. This was one of those cases. – Brian Goetz Oct 07 '15 at 16:39
  • 14
    @BrianGoetz Is there some public information available on the undecidable inference problems that you mentioned? I'm curious and would like to understand it. – Christian Hujer Oct 13 '15 at 07:22
  • There are a couple of long threads about it in the [lambda-dev mailing list](http://mail.openjdk.java.net/pipermail/lambda-dev/2010-June/thread.html#1484). @BrianGoetz, the link to your blog post is dead. Is it available somewhere else? – shmosel Oct 17 '18 at 04:30
  • *I wouldn't expect the `map` operation to throw the exception, I would expect the `Stream` to throw the exception whereever it occurs.* Your examples don't indicate that. – shmosel Oct 17 '18 at 04:32
  • @shmosel Congratulations, finally somebody who figured that one out, I wondered when somebody would spot this. The point remains, it's just that the terminal operation would have to carry forward the combined potential throw clauses of all higher order functions passed to the stream in all previous non-terminal operations. – Christian Hujer Oct 17 '18 at 05:47
  • 1
    using a generic super-interface for those functional interfaces could resolve the problem in a lot of places without breaking user code. e.g. `Consumer extends EConsumer` with `class EConsumer`. methods that do accept `Consumer` can be easily changed to accept `EConsumer` and will still compile to use the 'old consumer'. at least new methods could be added and old methods can be marked deprecated. better to fix the problem sooner than to never deal with it. – benez Mar 01 '19 at 13:58
  • 3
    @MarcG Regarding your two suggested outcomes, there's now a third one possible as well: That people move on to languages that do not have these issues. Like Kotlin. – Christian Hujer Aug 11 '20 at 16:25
  • 1
    @BrianGoetz we can all agree this is horribly painful to work with though right? – indigo Oct 25 '22 at 05:00
203

This LambdaExceptionUtil helper class lets you use any checked exceptions in Java streams, like this:

Stream.of("java.lang.Object", "java.lang.Integer", "java.lang.String")
      .map(rethrowFunction(Class::forName))
      .collect(Collectors.toList());

Note Class::forName throws ClassNotFoundException, which is checked. The stream itself also throws ClassNotFoundException, and NOT some wrapping unchecked exception.

public final class LambdaExceptionUtil {

@FunctionalInterface
public interface Consumer_WithExceptions<T, E extends Exception> {
    void accept(T t) throws E;
    }

@FunctionalInterface
public interface BiConsumer_WithExceptions<T, U, E extends Exception> {
    void accept(T t, U u) throws E;
    }

@FunctionalInterface
public interface Function_WithExceptions<T, R, E extends Exception> {
    R apply(T t) throws E;
    }

@FunctionalInterface
public interface Supplier_WithExceptions<T, E extends Exception> {
    T get() throws E;
    }

@FunctionalInterface
public interface Runnable_WithExceptions<E extends Exception> {
    void run() throws E;
    }

/** .forEach(rethrowConsumer(name -> System.out.println(Class.forName(name)))); or .forEach(rethrowConsumer(ClassNameUtil::println)); */
public static <T, E extends Exception> Consumer<T> rethrowConsumer(Consumer_WithExceptions<T, E> consumer) throws E {
    return t -> {
        try { consumer.accept(t); }
        catch (Exception exception) { throwAsUnchecked(exception); }
        };
    }

public static <T, U, E extends Exception> BiConsumer<T, U> rethrowBiConsumer(BiConsumer_WithExceptions<T, U, E> biConsumer) throws E {
    return (t, u) -> {
        try { biConsumer.accept(t, u); }
        catch (Exception exception) { throwAsUnchecked(exception); }
        };
    }

/** .map(rethrowFunction(name -> Class.forName(name))) or .map(rethrowFunction(Class::forName)) */
public static <T, R, E extends Exception> Function<T, R> rethrowFunction(Function_WithExceptions<T, R, E> function) throws E {
    return t -> {
        try { return function.apply(t); }
        catch (Exception exception) { throwAsUnchecked(exception); return null; }
        };
    }

/** rethrowSupplier(() -> new StringJoiner(new String(new byte[]{77, 97, 114, 107}, "UTF-8"))), */
public static <T, E extends Exception> Supplier<T> rethrowSupplier(Supplier_WithExceptions<T, E> function) throws E {
    return () -> {
        try { return function.get(); }
        catch (Exception exception) { throwAsUnchecked(exception); return null; }
        };
    }

/** uncheck(() -> Class.forName("xxx")); */
public static void uncheck(Runnable_WithExceptions t)
    {
    try { t.run(); }
    catch (Exception exception) { throwAsUnchecked(exception); }
    }

/** uncheck(() -> Class.forName("xxx")); */
public static <R, E extends Exception> R uncheck(Supplier_WithExceptions<R, E> supplier)
    {
    try { return supplier.get(); }
    catch (Exception exception) { throwAsUnchecked(exception); return null; }
    }

/** uncheck(Class::forName, "xxx"); */
public static <T, R, E extends Exception> R uncheck(Function_WithExceptions<T, R, E> function, T t) {
    try { return function.apply(t); }
    catch (Exception exception) { throwAsUnchecked(exception); return null; }
    }

@SuppressWarnings ("unchecked")
private static <E extends Throwable> void throwAsUnchecked(Exception exception) throws E { throw (E)exception; }

}

Many other examples on how to use it (after statically importing LambdaExceptionUtil):

@Test
public void test_Consumer_with_checked_exceptions() throws IllegalAccessException {
    Stream.of("java.lang.Object", "java.lang.Integer", "java.lang.String")
          .forEach(rethrowConsumer(className -> System.out.println(Class.forName(className))));

    Stream.of("java.lang.Object", "java.lang.Integer", "java.lang.String")
          .forEach(rethrowConsumer(System.out::println));
    }

@Test
public void test_Function_with_checked_exceptions() throws ClassNotFoundException {
    List<Class> classes1
          = Stream.of("Object", "Integer", "String")
                  .map(rethrowFunction(className -> Class.forName("java.lang." + className)))
                  .collect(Collectors.toList());

    List<Class> classes2
          = Stream.of("java.lang.Object", "java.lang.Integer", "java.lang.String")
                  .map(rethrowFunction(Class::forName))
                  .collect(Collectors.toList());
    }

@Test
public void test_Supplier_with_checked_exceptions() throws ClassNotFoundException {
    Collector.of(
          rethrowSupplier(() -> new StringJoiner(new String(new byte[]{77, 97, 114, 107}, "UTF-8"))),
          StringJoiner::add, StringJoiner::merge, StringJoiner::toString);
    }

@Test    
public void test_uncheck_exception_thrown_by_method() {
    Class clazz1 = uncheck(() -> Class.forName("java.lang.String"));

    Class clazz2 = uncheck(Class::forName, "java.lang.String");
    }

@Test (expected = ClassNotFoundException.class)
public void test_if_correct_exception_is_still_thrown_by_method() {
    Class clazz3 = uncheck(Class::forName, "INVALID");
    }    

UPDATE as of Nov 2015 The code has been improved with the help of @PaoloC, please check his answer below and upvote it. He helped solve the last problem: now the compiler will ask you to add throw clauses and everything is as if you could throw checked exceptions natively on Java 8 streams.

Note 1

The rethrow methods of the LambdaExceptionUtil class above may be used without fear, and are OK to use in any situation.

Note 2

The uncheck methods of the LambdaExceptionUtil class above are bonus methods, and may be safely removed them from the class if you don't want to use them. If you do used them, do it with care, and not before understanding the following use cases, advantages/disadvantages and limitations:

  • You may use the uncheck methods if you are calling a method which literally can never throw the exception that it declares. For example: new String(byteArr, "UTF-8") throws UnsupportedEncodingException, but UTF-8 is guaranteed by the Java spec to always be present. Here, the throws declaration is a nuisance and any solution to silence it with minimal boilerplate is welcome:

    String text = uncheck(() -> new String(byteArr, "UTF-8"));
    
  • You may use the uncheck methods if you are implementing a strict interface where you don't have the option for adding a throws declaration, and yet throwing an exception is entirely appropriate. Wrapping an exception just to gain the privilege of throwing it results in a stacktrace with spurious exceptions which contribute no information about what actually went wrong. A good example is Runnable.run(), which does not throw any checked exceptions.

  • In any case, if you decide to use the uncheck methods, be aware of these two consequences of throwing CHECKED exceptions without a throws clause:

    1. The calling-code won't be able to catch it by name (if you try, the compiler will say: "Exception is never thrown in body of corresponding try statement"). It will bubble and probably be caught in the main program loop by some catch Exception or catch Throwable, which may be what you want anyway.
    2. It violates the principle of least surprise: it will no longer be enough to catch RuntimeException to be able to guarantee catching all possible exceptions. For this reason, I believe this should not be done in framework code, but only in business code that you completely control.

References

MC Emperor
  • 22,334
  • 15
  • 80
  • 130
Marcelo Glasberg
  • 29,013
  • 23
  • 109
  • 133
  • 5
    I feel this answer was unjustly downvoted. The code works. Checked exceptions are supposed to be thrown or dealt with. If you want to throw them, just keep the "throws clause" in the method that contains the stream. But if you want to deal with them by simply wrapping and rethrowing, I guess I prefer to use the code above to "unckeck" the exceptions and let them bubble by themselves. The only difference I am aware of is that the bubbling exception won't extend RuntimeException. I know purists won't like that, but will this "inevitably come back to bite someone"? Doesn't seem likely. – Marcelo Glasberg Dec 25 '14 at 18:37
  • 5
    @Christian Hujer, to be honest with the downvoter, he downvoted a previous version before I added the "advantages, disadvantages, and limitations" explanation. So maybe it was deserved at the time. You cannot teach someone how to break the rules without at least trying to understand and explain the consequences. The main reason why I posted this question was to get feedback for the disadvantages of my answer. I ended up getting this feedback not here, but from another question in programmers.stackexchange. Then I came back here and updated my answer. – Marcelo Glasberg Dec 27 '14 at 18:16
  • 14
    @Unihedro but why does it became unmaintainable? I can't see why. Any examples? – Marcelo Glasberg Dec 28 '14 at 17:29
  • Hi @marcg i couldnt post here but i extended your UtilException to cast and launch the declared checked exception you were already handling. Does that stick to your original idea? Any feedback welcome – PaoloC Jun 22 '15 at 08:22
  • If you are using Lombok, I'd just define a function with `@SneakyThrows` on it. – Justin Sep 05 '15 at 19:46
  • 1
    This solution should be updated with @PaoloC small changes. It really becomes a complete solution since the compiler will then enforce the calling code to handle (throw or catch) the original exception type. – Skystrider Sep 23 '15 at 18:40
  • 2
    In my opinion the `@SuppressWarnings ("unchecked")` compiler trickery is completely unacceptable. – Thorbjørn Ravn Andersen Sep 24 '15 at 15:54
  • 2
    @ThorbjørnRavnAndersen and @Unihedron please note that `@SuppressWarning` is confined in one util class only, and remaining code is much cleaner and easier to maintain/develop than _not using any trick_, where do you see the clutter/evil? Even unit testing is way more effective (take a look at `LambdaExceptionUtilTest` below). We're trying to find a good and clean compromise here. So, do you guys have a better solution than MarcG+mine's or are you simply saying "do not use lambda in those cases"? Thanks – PaoloC Oct 05 '15 at 07:45
  • 2
    @PaoloC even if you only break the rules in one place you still break them. When the Word of God is "Don't do that, but write wrappers", I think that the best way to ensure long term maintainability is to do so. You might have a different focus, if your code does not live very long before being replaced or discarded anyway, but I cannot afford to ignore this. – Thorbjørn Ravn Andersen Oct 05 '15 at 15:52
  • 2
    @ThorbjørnRavnAndersen thanks for your reply, but i dont see your God; i think Oracle&Community might deliver either better or worse solutions from jdk to jdk, but that can be fixed over time (with ideas and contributions from developers around the world.. see Joda Time or Scala). In the meantime, my code has to be long term, and that's why I way prefer to cheat 1 class and shorten/clean tons of code with Lambdas&FunctionalInterfaces (keeping the same contract, which included throwing exceptions), instead of burdening my team with maintaining tons of java7 code. – PaoloC Oct 06 '15 at 19:04
  • 2
    Moreover, we'll do that until Oracle will develop an equivalent (and i really suspect that to come, too many threads on this around); then, we'll just inline `LambdaExceptionUtil` to have _native_ clean code again. The difference is just in the middle: for a few years, you'll either catch-checked-and-rethrow-runtimes (which is a nightmare, you know) or just work around simple code not to throw exceptions (constantly increasing your technical debt). My 2c. – PaoloC Oct 06 '15 at 19:05
  • 1
    @PaoloC Let us call it the word of the Java Language Architect then: http://stackoverflow.com/a/27648758/53897. Time will tell what will end up being the best idea to handle this. – Thorbjørn Ravn Andersen Oct 07 '15 at 08:45
  • 2
    @ThorbjørnRavnAndersen i always pay respect to great developers as Brian, but code proposed by him in the below answer is manifestly unacceptable to cleanly solve this problem, it is just **a** workaround to avoid warnings, surely not a encouraging way to use checked exceptions inside streams. I dare you to write so much code each time you need to throw exceptions. – PaoloC Oct 07 '15 at 09:28
  • 3
    @PaoloC: Sorry for the time it took me to review this. I have updated my answer accordingly. I believe now even Brian Goetz' complaint of "breaking the type system" no longer applies. – Marcelo Glasberg Nov 12 '15 at 19:09
  • This is great. I made just one "improvement": Declare `throwAsUnchecked` to return `RuntimeException`. Then instead of following up calls to `throwAsUnchecked` with return null, you can just throw the result of `throwAsUnchecked`. It's a better indication of what is actually happening (i.e. that the point after the call is unreachable), but still avoids throwing a checked exception. – John Freeman Jul 01 '16 at 22:51
  • 1
    OK, you want a concrete reason why this is risky; I'll provide you with one: I can take your example stream code that throws `ClassCastException` and put it in a method that doesn't declare `throws ClassCastException`. Anyone on your dev team can use this wrapper without knowing that this is a consequence; they can avoid even finding out what checked exceptions are thrown by the enclosed call. You _can_ declare a throws clause, but nothing will make your brand new trainee do that. Although--if you're comfortable with wrapping everything in `RuntimeException`, this isn't hugely worse. – Mark McKenna Nov 23 '17 at 02:08
  • @MarkMcKenna See NOTE 1 above: The compiler will ask you to add throw clauses and everything's as if you could throw checked exceptions natively on Java 8 streams. My original code had the problem you described, but it has since been updated with PaoloC's suggestion. – Marcelo Glasberg Nov 23 '17 at 15:42
  • 1
    @MarcG that's odd. I didn't get the prompt to add a throws clause from the compiler, which makes sense because the typology on all top level Stream methods doesn't indicate that a checked exception is throwable in that location. I'll try that more thoroughly and, if you're right and the compiler does force a throws clause, then this looks totally fine to me. – Mark McKenna Nov 24 '17 at 16:24
  • 1
    This does not seem to work in Java 1.8.0_111 on Windows. My compiler does not complain about a missing `throws` declaration in a method which contains `Stream.of(new Object()).forEach(rethrowConsumer(o -> o.wait(0)));`. If it once worked then it was extremely clever, but it seems to no longer work. – Colin P. Hill Feb 26 '18 at 16:57
  • @Malnormalulo Can you please check again with the updated code? There was a mistake, but now it's fixed and tested. Sorry for that. – Marcelo Glasberg Feb 26 '18 at 19:00
  • @MarkMcKenna Can you please check again with the updated code? There was a mistake, but now it's fixed and tested. Sorry for that. – Marcelo Glasberg Feb 26 '18 at 19:01
  • 2
    It does work now, and now that it does work I understand why it works. I'm not super comfortable with this personally because Note 1 is simply incorrect; this is not universally safe, because it requires you to handle the exception where the function is _created_, not where it's _invoked_. When those are the same place, as in these examples, it's fine, but nothing prevents a developer from wrapping a function in a rethrower, handling the exception there (where it won't ever even be thrown), and passing the dangerous unchecked-but-should-be-checked function to some other piece of code. – Colin P. Hill Feb 27 '18 at 18:02
  • @Malnormalulo I'm not sure I understand what you just said. Could you please provide a simple code example of a bad situation where the developer passes a unchecked-but-should-be-checked function to some other piece of code? – Marcelo Glasberg Feb 28 '18 at 01:21
  • 2
    The pass-around-problem is explained at https://blog.codefx.org/java/repackaging-exceptions-streams/. – mm759 Mar 07 '18 at 10:00
  • 1
    @mm759 I didn't even think of it happening like that! What I had in mind was something like this: https://gist.github.com/malnormalulo/a84e1993849ea901702ff7482510fa1a – Colin P. Hill Mar 25 '18 at 17:33
  • @MarcG I'm using this for years now, but re-throwing is bad. Will the following fail and why? `@SuppressWarnings("unchecked") public static Consumer rethrowConsumer(final ConsumerWithExceptions consumer) throws E {return ((ConsumerWithExceptions) consumer)::accept; }` – basin Aug 05 '20 at 15:43
  • For the rethrowing function, it is a bad idea as the checked exception affects the map method in the stream. However, the map method is not a terminal operation, and the actual exception will be thrown on the collect method. This means the try/catch is going around the wrong method, and its only the fact that it is a one liner that it works.. – Solubris Jan 24 '21 at 03:27
  • Was it just an oversight that `uncheck(Runnable_WithExceptions t)` function was not parametrized (with `` and ``), or was there a particular reason to single that one out? (being the only one with no type parameter by default?) Eclipse 4.20 with JDK8 emits a warning there... – OzgurH Oct 02 '21 at 00:17
38

You can!

Extending @marcg 's UtilException and adding throw E where necessary: this way, the compiler will ask you to add throw clauses and everything's as if you could throw checked exceptions natively on java 8's streams.

Instructions: just copy/paste LambdaExceptionUtil in your IDE and then use it as shown in the below LambdaExceptionUtilTest.

public final class LambdaExceptionUtil {

    @FunctionalInterface
    public interface Consumer_WithExceptions<T, E extends Exception> {
        void accept(T t) throws E;
    }

    @FunctionalInterface
    public interface Function_WithExceptions<T, R, E extends Exception> {
        R apply(T t) throws E;
    }

    /**
     * .forEach(rethrowConsumer(name -> System.out.println(Class.forName(name))));
     */
    public static <T, E extends Exception> Consumer<T> rethrowConsumer(Consumer_WithExceptions<T, E> consumer) throws E {
        return t -> {
            try {
                consumer.accept(t);
            } catch (Exception exception) {
                throwActualException(exception);
            }
        };
    }

    /**
     * .map(rethrowFunction(name -> Class.forName(name))) or .map(rethrowFunction(Class::forName))
     */
    public static <T, R, E extends Exception> Function<T, R> rethrowFunction(Function_WithExceptions<T, R, E> function) throws E  {
        return t -> {
            try {
                return function.apply(t);
            } catch (Exception exception) {
                throwActualException(exception);
                return null;
            }
        };
    }

    @SuppressWarnings("unchecked")
    private static <E extends Exception> void throwActualException(Exception exception) throws E {
        throw (E) exception;
    }

}

Some test to show usage and behaviour:

public class LambdaExceptionUtilTest {

    @Test(expected = MyTestException.class)
    public void testConsumer() throws MyTestException {
        Stream.of((String)null).forEach(rethrowConsumer(s -> checkValue(s)));
    }

    private void checkValue(String value) throws MyTestException {
        if(value==null) {
            throw new MyTestException();
        }
    }

    private class MyTestException extends Exception { }

    @Test
    public void testConsumerRaisingExceptionInTheMiddle() {
        MyLongAccumulator accumulator = new MyLongAccumulator();
        try {
            Stream.of(2L, 3L, 4L, null, 5L).forEach(rethrowConsumer(s -> accumulator.add(s)));
            fail();
        } catch (MyTestException e) {
            assertEquals(9L, accumulator.acc);
        }
    }

    private class MyLongAccumulator {
        private long acc = 0;
        public void add(Long value) throws MyTestException {
            if(value==null) {
                throw new MyTestException();
            }
            acc += value;
        }
    }

    @Test
    public void testFunction() throws MyTestException {
        List<Integer> sizes = Stream.of("ciao", "hello").<Integer>map(rethrowFunction(s -> transform(s))).collect(toList());
        assertEquals(2, sizes.size());
        assertEquals(4, sizes.get(0).intValue());
        assertEquals(5, sizes.get(1).intValue());
    }

    private Integer transform(String value) throws MyTestException {
        if(value==null) {
            throw new MyTestException();
        }
        return value.length();
    }

    @Test(expected = MyTestException.class)
    public void testFunctionRaisingException() throws MyTestException {
        Stream.of("ciao", null, "hello").<Integer>map(rethrowFunction(s -> transform(s))).collect(toList());
    }

}
PaoloC
  • 3,817
  • 1
  • 23
  • 27
  • I get `Exception in thread "main" java.lang.ClassCastException: java.io.IOException cannot be cast to java.lang.RuntimeException` when my consumer throws an `IOException`. – steffen Jun 23 '15 at 13:28
  • Hi @steffen I've just made a fix on the "throwing/casting" method, and also added a unit test to show how that can work: class compile and test is green on my machine. If you still have the error, try to simplify your case and then post differences between that and my test case so that we can investigate. Thanks – PaoloC Jun 23 '15 at 15:01
  • I'm geting 'unreported Exception E; must be caught or declared to be thrown" – Setheron Aug 06 '15 at 02:02
  • 1
    Sorry @setheron you're right, just add `` before `map`. In fact, java compiler cannot infer the `Integer` return type. Everything else should be correct. – PaoloC Aug 07 '15 at 14:19
  • 1
    This worked for me. It made MarcG's answer perfect by enforcing handling the exception. – Skystrider Sep 23 '15 at 18:24
  • This doesn't work inside another stream expression. myStream.foreach(rethrowConsumer(someSet -> someSet.stream.foreach(rethrowConsumer(thing -> thing.clone())))); This complains that the exception isn't handled. If I don't have the inner stream inside the outer exception then there is no complaint (the method with this code throws the CloneNotSupportedException. – Skystrider Sep 29 '15 at 17:35
  • 1
    Solution to above issue: Declare variable like this Consumer expression = rethrowConsumer((ThingType thing) -> thing.clone()); then use that expression inside the inner foreach. – Skystrider Sep 29 '15 at 18:03
  • @PaoloC: Sorry for the time it took me to review this. I have updated my answer accordingly. I believe now even Brian Goetz' complaint of "breaking the type system" no longer applies. – Marcelo Glasberg Nov 12 '15 at 19:04
  • 1
    @Skychan: Since in this modified new version you are not suppressing any exceptions anymore, it's probably a bit more difficult to the inference system. In some comment below Brian Goetz talks about the "exception transparency" leading to "undecidable inference problems". – Marcelo Glasberg Nov 12 '15 at 19:08
  • This is great. I made just one "improvement": Declare `throwActualException` to return `RuntimeException`. Then instead of following up calls to `throwActualException` with `return null`, you can just throw the result of `throwActualException`. It's a better indication of what is actually happening (i.e. that the point after the call is unreachable), but still avoids throwing a checked exception. – John Freeman Jul 01 '16 at 22:45
  • 3
    Very nice. The only unfortunate thing is that is does not work perfectly with a method that throw multiple checked exceptions. In this case the compiler will make you catch a common supertype, eg `Exception`. – wvdz Jul 05 '17 at 15:52
  • 1
    @Setheron I ran into the same issue re: 'unreported Exception E; must be caught or declared to be thrown". For me this only occurred when compiling under 1.8.0_91. It seems this was a [type inference JDK bug fixed in 1.8.0_92](https://bugs.openjdk.java.net/browse/JDK-8066974) This solution works much better with recent Java 8. – Gary Aug 06 '17 at 04:32
  • Thanks for your work and this should be java standard. I faced a bug in `rethrowFunction` in case the function returns `null` on purpose. It throws a NPE instead of just returning null. I want to get bean property values by reflection inside a lambda collector. `foo -> PropertyUtils.getProperty(source, foo.propertyName)` which may return null as valid outcome. – djmj Feb 28 '20 at 00:25
  • 1
    @djmj The below is working on my side, using Oracle JDK 1.8.0_201-b09 `List sizes = Stream.of("a", "b").map(rethrowFunction(foo -> (String) null)).collect(toList()); assertEquals(2, sizes.size()); assertNull(sizes.get(0)); assertNull(sizes.get(1));` Maybe the NPE is somewhere else in your code? – PaoloC Apr 25 '20 at 19:02
  • @PaoloC Yes you were right the reason was in my own code but it was hard to find out with the debugger. I should have deleted my comment after i found out but i forgot my post that busy day. – djmj Apr 27 '20 at 11:56
  • Thank you. Very good. But I want it to be able to convert a checked exception to a RuntimeException. To that end, I added some code to my copy: – user2367418 Feb 10 '22 at 01:18
28

You can't do this safely. You can cheat, but then your program is broken and this will inevitably come back to bite someone (it should be you, but often our cheating blows up on someone else.)

Here's a slightly safer way to do it (but I still don't recommend this.)

class WrappedException extends RuntimeException {
    Throwable cause;

    WrappedException(Throwable cause) { this.cause = cause; }
}

static WrappedException throwWrapped(Throwable t) {
    throw new WrappedException(t);
}

try 
    source.stream()
          .filter(e -> { ... try { ... } catch (IOException e) { throwWrapped(e); } ... })
          ...
}
catch (WrappedException w) {
    throw (IOException) w.cause;
}

Here, what you're doing is catching the exception in the lambda, throwing a signal out of the stream pipeline that indicates that the computation failed exceptionally, catching the signal, and acting on that signal to throw the underlying exception. The key is that you are always catching the synthetic exception, rather than allowing a checked exception to leak out without declaring that exception is thrown.

Brian Goetz
  • 90,105
  • 23
  • 150
  • 161
  • 24
    Just a question; what was the design decision which led to lambdas not being able to propagate checked exceptions out of their context? Note that I do understand that the functional interfaces such as `Function` etc don't `throws` anything; I'm just curious. – fge Dec 27 '14 at 18:06
  • 4
    That `throw w.cause;` wouldn't make the compiler complain that the method do not throws nor catch `Throwable`? So, it is likely that a cast to `IOException` would be needed there. Further, if the lambda throws more than one type of checked exception, the body of the catch would became somewhat ugly with some `instanceof` checks (or something else with a similar purpose) to verify which checked exception was throw. – Victor Stafusa - BozoNaCadeia Apr 20 '15 at 08:40
  • (with the necessary cast proposed by @VictorStafusa) this could become a _working answer_, but surely not a correct solution to the problem. Writing so much code to throw exceptions inside streams will either decuplicate boilerplate code or force developers not to use checkedExceptions inside lambdas. What about solution http://stackoverflow.com/a/30974991/2365724 derived from MarcG's one? – PaoloC Oct 07 '15 at 09:33
  • @Brian why is this method only *slightly* safer, what is the risk here? – schatten Aug 24 '16 at 00:20
  • 11
    @schatten One reason is that you could forget to catch WE, and then a weird exception (which no one knows how to deal with) would leak out. (You might say "but you caught the exception, so its safe." In this toy example. But every time I've seen a codebase adopt this approach, eventually someone forgets. The temptation to ignore exceptions knows no bounds.) Another risk is that using it safely is specific to a particular (use site, exception) combination. It doesn't scale well to multiple exceptions or nonhomegeneous uses. – Brian Goetz Aug 24 '16 at 12:31
  • 1
    @PaoloC - if your workplace is forcing you to use Java, then wrapping checked exceptions is just something you have to live with. That is not the fault of lambdas. – hoodaticus Jun 09 '17 at 18:50
  • 2
    @hoodaticus I agree with you. Said that, do you prefer wrapping more and more (as shown above, increasing the risk of "forgetting") or just create 4 clever interfaces and using lambdas w/o wrapping, as shown in http://stackoverflow.com/a/30974991/2365724? Thanks – PaoloC Jun 12 '17 at 12:47
  • 15
    Frankly, this solution is just completely unworkable. I thought the point of streams was to reduce boilerplate, not increase it. – wvdz Jul 05 '17 at 14:43
  • Does the streams API documentation (or other specification) guarantee that exceptions thrown by e.g. a `filter` predicate are relayed to the caller somehow, or is the catch outside the stream relying on implementation behavior? – Radiodef Aug 09 '18 at 01:38
  • "The temptation to ignore exceptions knows no bounds."... and yet an API is introduced that requires wrapping of checked exceptions... – john16384 Apr 09 '20 at 20:57
  • What has worked for me using Java 11 is to catch Exception to catch all possible checked exceptions. E.g. Jackson's ObjectMapper throws JsonProcessingException, that can be dealt with like: `return ... .stream() .peek(s -> { try { s.set( objectMapper.writeValueAsString("write someting"))); } catch(Exception e) {};}) .collect(Collectors.toList());` – nkmuturi Aug 08 '20 at 10:50
15

Just use any one of NoException (my project), jOOλ's Unchecked, throwing-lambdas, Throwable interfaces, or Faux Pas.

// NoException
stream.map(Exceptions.sneak().function(Class::forName));

// jOOλ
stream.map(Unchecked.function(Class::forName));

// throwing-lambdas
stream.map(Throwing.function(Class::forName).sneakyThrow());

// Throwable interfaces
stream.map(FunctionWithThrowable.aFunctionThatUnsafelyThrowsUnchecked(Class::forName));

// Faux Pas
stream.map(FauxPas.throwingFunction(Class::forName));
Robert Važan
  • 3,399
  • 2
  • 25
  • 31
10

I wrote a library that extends the Stream API to allow you to throw checked exceptions. It uses Brian Goetz's trick.

Your code would become

public List<Class> getClasses() throws ClassNotFoundException {     
    Stream<String> classNames = 
        Stream.of("java.lang.Object", "java.lang.Integer", "java.lang.String");

    return ThrowingStream.of(classNames, ClassNotFoundException.class)
               .map(Class::forName)
               .collect(Collectors.toList());
}
Jeffrey
  • 44,417
  • 8
  • 90
  • 141
7

This answer is similar to 17 but avoiding wrapper exception definition:

List test = new ArrayList();
        try {
            test.forEach(obj -> {

                //let say some functionality throws an exception
                try {
                    throw new IOException("test");
                }
                catch(Exception e) {
                    throw new RuntimeException(e);
                }
            });
        }
        catch (RuntimeException re) {
            if(re.getCause() instanceof IOException) {
                //do your logic for catching checked
            }
            else 
                throw re; // it might be that there is real runtime exception
        }
  • 2
    This is exactly what Op did not want: try blocks in the lambda. Futhermore, it only works as expected as long as no other code outside the try block wraps an IOException in a RuntimeException. To avoid this, a custom wrapper-RuntimeException (defined as a private inner class) could be used. – Malte Hartwig Dec 06 '17 at 13:13
5

You cannot.

However, you may want to have a look at one of my projects which allows you to more easily manipulate such "throwing lambdas".

In your case, you would be able to do that:

import static com.github.fge.lambdas.functions.Functions.wrap;

final ThrowingFunction<String, Class<?>> f = wrap(Class::forName);

List<Class> classes =
    Stream.of("java.lang.Object", "java.lang.Integer", "java.lang.String")
          .map(f.orThrow(MyException.class))
          .collect(Collectors.toList());

and catch MyException.

That is one example. Another example is that you could .orReturn() some default value.

Note that this is STILL a work in progress, more is to come. Better names, more features etc.

fge
  • 119,121
  • 33
  • 254
  • 329
  • 2
    But then, if you want to throw the original checked exception you will have to add the try/catch around the stream, to unwrap it, which is still terrible! I like the idea that you MAY throw an unchecked exception if you want, and that you MAY return a default value to the stream if you want, but I also think you should add some `.orThrowChecked()` method to your project that allows the checked exception itself be thrown. Please have a look at my `UtilException` answer in this page, and see if you like the idea of adding this third possibility to your project. – Marcelo Glasberg Dec 27 '14 at 17:47
  • "But then, if you want to throw the original checked exception you will have to add the try/catch around the stream, to unwrap it, which is still terrible!" <-- yes but you have no choice. Lambdas _cannot_ propagate checked exceptions out of their context, that's a design "decision" (I view it as a flaw, personally, but ohwell) – fge Dec 27 '14 at 17:58
  • As to your idea, I don't very well follow what it does, sorry; after all you _still_ throw as unchecked, so how is this different from what I do? (except that I have a different interface for it) – fge Dec 27 '14 at 18:02
  • Anyway, you are welcome to contribute to the project! Also, have you noticed that `Stream` implements `AutoCloseable`? – fge Dec 27 '14 at 18:04
  • Let me ask you this: Does your `MyException` above need to be an unchecked exception? – Marcelo Glasberg Dec 27 '14 at 18:07
  • Yes it does. No choice. Otherwise it is unusable in a stream. And it will capture any _checked exception_ in the wrapped lambda and make it its cause. Which is why you can do `wrap(Path::toRealPath).orRethrow(MyException.class)` (in the next version you'll be able to write `rethrow(Path::toRealPath).as(MyException.class)`) – fge Dec 27 '14 at 18:11
  • Seriously, though; you are welcome to join. Note that I'm in the [Java chatroom on SO](http://chat.stackoverflow.com/rooms/139/java), but also on IRC (freenode, channel ##java, nick idletask) if you want to discuss things further. I'd be happy to share ideas! – fge Dec 27 '14 at 18:15
  • Ok. What my code does is that it "unchecks" the checked exception, so that YES, it becomes usable in a stream. It does NOT wrap the checked exception inside an unchecked one. It just throws the checked exception itself. So, you see, you can add the choice to your project, if you want. It has some limitations, reason why Brian Goetz says it's not completely safe. But I updated my answer to explain the limitations, which in my opinion are not serious, and then it's up to the programmer deciding to break the rules or not. – Marcelo Glasberg Dec 27 '14 at 18:30
  • And how do you "uncheck" it? This is the part that I don't really understand... And what I'd like to know – fge Dec 27 '14 at 18:44
  • Have a look: http://www.philandstuff.com/2012/04/28/sneakily-throwing-checked-exceptions.html – Marcelo Glasberg Dec 27 '14 at 18:59
5

TL;DR Just use Lombok's @SneakyThrows.

Christian Hujer has already explained in detail why throwing checked exceptions from a stream is, strictly speaking, not possible due to Java's limitations.

Some other answers have explained tricks to get around the limitations of the language but still being able to fulfil the requirement of throwing "the checked exception itself, and without adding ugly try/catches to the stream", some of them requiring tens of additional lines of boilerplate.

I am going to highlight another option for doing this that IMHO is far cleaner than all the others: Lombok's @SneakyThrows. It has been mentioned in passing by other answers but was a bit buried under a lot of unnecessary detail.

The resulting code is as simple as:

public List<Class> getClasses() throws ClassNotFoundException {
    List<Class> classes =
        Stream.of("java.lang.Object", "java.lang.Integer", "java.lang.String")
                .map(className -> getClass(className))
                .collect(Collectors.toList());
    return classes;
}

@SneakyThrows                                 // <= this is the only new code
private Class<?> getClass(String className) {
    return Class.forName(className);
}

We just needed one Extract Method refactoring (done by the IDE) and one additional line for @SneakyThrows. The annotation takes care of adding all the boilerplate to make sure that you can throw your checked exception without wrapping it in a RuntimeException and without needing to declare it explicitly.

sergut
  • 289
  • 2
  • 8
  • 4
    Usage of lombok should be discouraged. – Dragas Dec 19 '19 at 08:50
  • 1
    @Dragas designing a language in a way that people feel the need to come up with something like Lombok should be discouraged ;) – Christian Hujer Aug 05 '20 at 13:26
  • Ah, yes. You have the ability to define things in any way you want, turn all the knobs and even add your own. But instead you opt to throw it all out for some mess that hacks itself into the compiler and generates some implicit garbage that cannot be read unless you had read a bit about lombok's internals and what is the pattern that it generates things in. No, tools like lombok should be discouraged in favor of generating code. At least then I won't need some IDE plugin to see all the getters that you are too lazy to generate with the very same IDE. – Dragas Aug 05 '20 at 17:54
4

You can do it with apache commons-lang3 library.

https://commons.apache.org/proper/commons-lang/javadocs/api-release/org/apache/commons/lang3/function/Failable.html

public List<Class> getClasses() throws ClassNotFoundException {
    List<Class> classes =
            Stream.of("java.lang.Object", "java.lang.Integer", "java.lang.String")
                    .map(Failable.asFunction(Class::forName))
                    .collect(Collectors.toList());
    return classes;
}
E.H.
  • 326
  • 1
  • 7
3

Summarizing the comments above the advanced solution is to use a special wrapper for unchecked functions with builder like API which provides recovering, rethrowing and suppresing.

Stream.of("java.lang.Object", "java.lang.Integer", "java.lang.String")
          .map(Try.<String, Class<?>>safe(Class::forName)
                  .handle(System.out::println)
                  .unsafe())
          .collect(toList());

Code below demonstrates it for Consumer, Supplier and Function interfaces. It can be easly expanded. Some public keywords were removed for this example.

Class Try is the endpoint for client code. Safe methods may have unique name for each function type. CheckedConsumer, CheckedSupplier and CheckedFunction are checked analogs of lib functions which can be used independently of Try

CheckedBuilder is the interface for handling exceptions in some checked function. orTry allows execute another same type function if previous was failed. handle provides exception handling including exception type filtering. The order of handlers is important. Reduce methods unsafe and rethrow rethrows last exception in the execution chain. Reduce methods orElse and orElseGet return alternate value like Optional ones if all functions failed. Also there is method suppress. CheckedWrapper is the common implementation of CheckedBuilder.

final class Try {

    public static <T> CheckedBuilder<Supplier<T>, CheckedSupplier<T>, T> 
        safe(CheckedSupplier<T> supplier) {
        return new CheckedWrapper<>(supplier, 
                (current, next, handler, orResult) -> () -> {
            try { return current.get(); } catch (Exception ex) {
                handler.accept(ex);
                return next.isPresent() ? next.get().get() : orResult.apply(ex);
            }
        });
    }

    public static <T> Supplier<T> unsafe(CheckedSupplier<T> supplier) {
        return supplier;
    }

    public static <T> CheckedBuilder<Consumer<T>, CheckedConsumer<T>, Void> 
        safe(CheckedConsumer<T> consumer) {
        return new CheckedWrapper<>(consumer, 
                (current, next, handler, orResult) -> t -> {
            try { current.accept(t); } catch (Exception ex) {
                handler.accept(ex);
                if (next.isPresent()) {
                    next.get().accept(t);
                } else {
                    orResult.apply(ex);
                }
            }
        });
    }

    public static <T> Consumer<T> unsafe(CheckedConsumer<T> consumer) {
        return consumer;
    }

    public static <T, R> CheckedBuilder<Function<T, R>, CheckedFunction<T, R>, R> 
        safe(CheckedFunction<T, R> function) {
        return new CheckedWrapper<>(function, 
                (current, next, handler, orResult) -> t -> {
            try { return current.applyUnsafe(t); } catch (Exception ex) {
                handler.accept(ex);
                return next.isPresent() ? next.get().apply(t) : orResult.apply(ex);
            }
        });
    }

    public static <T, R> Function<T, R> unsafe(CheckedFunction<T, R> function) {
        return function;
    }

    @SuppressWarnings ("unchecked")
    static <T, E extends Throwable> T throwAsUnchecked(Throwable exception) throws E { 
        throw (E) exception; 
    }
}

@FunctionalInterface interface CheckedConsumer<T> extends Consumer<T> {
    void acceptUnsafe(T t) throws Exception;
    @Override default void accept(T t) {
        try { acceptUnsafe(t); } catch (Exception ex) {
            Try.throwAsUnchecked(ex);
        }
    }
}

@FunctionalInterface interface CheckedFunction<T, R> extends Function<T, R> {
    R applyUnsafe(T t) throws Exception;
    @Override default R apply(T t) {
        try { return applyUnsafe(t); } catch (Exception ex) {
            return Try.throwAsUnchecked(ex);
        }
    }
}

@FunctionalInterface interface CheckedSupplier<T> extends Supplier<T> {
    T getUnsafe() throws Exception;
    @Override default T get() {
        try { return getUnsafe(); } catch (Exception ex) {
            return Try.throwAsUnchecked(ex);
        }
    }
}

interface ReduceFunction<TSafe, TUnsafe, R> {
    TSafe wrap(TUnsafe current, Optional<TSafe> next, 
            Consumer<Throwable> handler, Function<Throwable, R> orResult);
}

interface CheckedBuilder<TSafe, TUnsafe, R> {
    CheckedBuilder<TSafe, TUnsafe, R> orTry(TUnsafe next);

    CheckedBuilder<TSafe, TUnsafe, R> handle(Consumer<Throwable> handler);

    <E extends Throwable> CheckedBuilder<TSafe, TUnsafe, R> handle(
            Class<E> exceptionType, Consumer<E> handler);

    CheckedBuilder<TSafe, TUnsafe, R> handleLast(Consumer<Throwable> handler);

    <E extends Throwable> CheckedBuilder<TSafe, TUnsafe, R> handleLast(
            Class<E> exceptionType, Consumer<? super E> handler);

    TSafe unsafe();
    TSafe rethrow(Function<Throwable, Exception> transformer);
    TSafe suppress();
    TSafe orElse(R value);
    TSafe orElseGet(Supplier<R> valueProvider);
}

final class CheckedWrapper<TSafe, TUnsafe, R> 
        implements CheckedBuilder<TSafe, TUnsafe, R> {

    private final TUnsafe function;
    private final ReduceFunction<TSafe, TUnsafe, R> reduceFunction;

    private final CheckedWrapper<TSafe, TUnsafe, R> root;
    private CheckedWrapper<TSafe, TUnsafe, R> next;

    private Consumer<Throwable> handlers = ex -> { };
    private Consumer<Throwable> lastHandlers = ex -> { };

    CheckedWrapper(TUnsafe function, 
            ReduceFunction<TSafe, TUnsafe, R> reduceFunction) {
        this.function = function;
        this.reduceFunction = reduceFunction;
        this.root = this;
    }

    private CheckedWrapper(TUnsafe function, 
            CheckedWrapper<TSafe, TUnsafe, R> prev) {
        this.function = function;
        this.reduceFunction = prev.reduceFunction;
        this.root = prev.root;
        prev.next = this;
    }

    @Override public CheckedBuilder<TSafe, TUnsafe, R> orTry(TUnsafe next) {
        return new CheckedWrapper<>(next, this);
    }

    @Override public CheckedBuilder<TSafe, TUnsafe, R> handle(
            Consumer<Throwable> handler) {
        handlers = handlers.andThen(handler);
        return this;
    }

    @Override public <E extends Throwable> CheckedBuilder<TSafe, TUnsafe, R> 
        handle(Class<E> exceptionType, Consumer<E> handler) {
        handlers = handlers.andThen(ex -> {
            if (exceptionType.isInstance(ex)) {
                handler.accept(exceptionType.cast(ex));
            }
        });
        return this;
    }

    @Override public CheckedBuilder<TSafe, TUnsafe, R> handleLast(
            Consumer<Throwable> handler) {
        lastHandlers = lastHandlers.andThen(handler);
        return this;
    }

    @Override public <E extends Throwable> CheckedBuilder<TSafe, TUnsafe, R> 
        handleLast(Class<E> exceptionType, Consumer<? super E> handler) {
        lastHandlers = lastHandlers.andThen(ex -> {
            if (exceptionType.isInstance(ex)) {
                handler.accept(exceptionType.cast(ex));
            }
        });
        return this;
    }

    @Override public TSafe unsafe() {
        return root.reduce(ex -> Try.throwAsUnchecked(ex));
    }

    @Override
    public TSafe rethrow(Function<Throwable, Exception> transformer) {
        return root.reduce(ex -> Try.throwAsUnchecked(transformer.apply(ex)));
    }

    @Override public TSafe suppress() {
        return root.reduce(ex -> null);
    }

    @Override public TSafe orElse(R value) {
        return root.reduce(ex -> value);
    }

    @Override public TSafe orElseGet(Supplier<R> valueProvider) {
        Objects.requireNonNull(valueProvider);
        return root.reduce(ex -> valueProvider.get());
    }

    private TSafe reduce(Function<Throwable, R> orResult) {
        return reduceFunction.wrap(function, 
                Optional.ofNullable(next).map(p -> p.reduce(orResult)), 
                this::handle, orResult);
    }

    private void handle(Throwable ex) {
        for (CheckedWrapper<TSafe, TUnsafe, R> current = this; 
                current != null; 
                current = current.next) {
            current.handlers.accept(ex);
        }
        lastHandlers.accept(ex);
    }
}
introspected
  • 159
  • 1
  • 7
3

Here is a different view or solution for the original problem. Here I show that we have an option to write a code that will process only a valid subset of values with an option to detect and handle caseses when the exception was thrown.

    @Test
    public void getClasses() {

        String[] classNames = {"java.lang.Object", "java.lang.Integer", "java.lang.Foo"};
        List<Class> classes =
                Stream.of(classNames)
                        .map(className -> {
                            try {
                                return Class.forName(className);
                            } catch (ClassNotFoundException e) {
                                // log the error
                                return null;
                            }
                        })
                        .filter(c -> c != null)
                        .collect(Collectors.toList());

        if (classes.size() != classNames.length) {
            // add your error handling here if needed or process only the resulting list
            System.out.println("Did not process all class names");
        }

        classes.forEach(System.out::println);
    }
OSGI Java
  • 545
  • 7
  • 21
2

Probably, a better and more functional way is to wrap exceptions and propagate them further in the stream. Take a look at the Try type of Vavr for example.

Example:

interface CheckedFunction<I, O> {
    O apply(I i) throws Exception; }

static <I, O> Function<I, O> unchecked(CheckedFunction<I, O> f) {
    return i -> {
        try {
            return f.apply(i);
        } catch(Exception ex) {

            throw new RuntimeException(ex);
        }
    } }

fileNamesToRead.map(unchecked(file -> Files.readAllLines(file)))

OR

@SuppressWarnings("unchecked")
private static <T, E extends Exception> T throwUnchecked(Exception e) throws E {
    throw (E) e;
}

static <I, O> Function<I, O> unchecked(CheckedFunction<I, O> f) {
    return arg -> {
        try {
            return f.apply(arg);
        } catch(Exception ex) {
            return throwUnchecked(ex);
        }
    };
}

2nd implementation avoids wrapping the exception in a RuntimeException. throwUnchecked works because almost always all generic exceptions are treated as unchecked in java.

Mikhail Kholodkov
  • 23,642
  • 17
  • 61
  • 78
2

You can also write a wrapper method to wrap unchecked exceptions, and even enhance wrapper with additional parameter representing another functional interface (with the same return type R). In this case you can pass a function that would be executed and returned in case of exceptions. See example below:

private void run() {
    List<String> list = Stream.of(1, 2, 3, 4).map(wrapper(i ->
            String.valueOf(++i / 0), i -> String.valueOf(++i))).collect(Collectors.toList());
    System.out.println(list.toString());
}

private <T, R, E extends Exception> Function<T, R> wrapper(ThrowingFunction<T, R, E> function, 
Function<T, R> onException) {
    return i -> {
        try {
            return function.apply(i);
        } catch (ArithmeticException e) {
            System.out.println("Exception: " + i);
            return onException.apply(i);
        } catch (Exception e) {
            System.out.println("Other: " + i);
            return onException.apply(i);
        }
    };
}

@FunctionalInterface
interface ThrowingFunction<T, R, E extends Exception> {
    R apply(T t) throws E;
}
Piotr Niewinski
  • 1,298
  • 2
  • 15
  • 27
1

I agree with the comments above, in using Stream.map you are limited to implementing Function which doesn't throw Exceptions.

You could however create your own FunctionalInterface that throws as below..

@FunctionalInterface
public interface UseInstance<T, X extends Throwable> {
  void accept(T instance) throws X;
}

then implement it using Lambdas or references as shown below.

import java.io.FileWriter;
import java.io.IOException;

//lambda expressions and the execute around method (EAM) pattern to
//manage resources

public class FileWriterEAM  {
  private final FileWriter writer;

  private FileWriterEAM(final String fileName) throws IOException {
    writer = new FileWriter(fileName);
  }
  private void close() throws IOException {
    System.out.println("close called automatically...");
    writer.close();
  }
  public void writeStuff(final String message) throws IOException {
    writer.write(message);
  }
  //...

  public static void use(final String fileName, final UseInstance<FileWriterEAM, IOException> block) throws IOException {

    final FileWriterEAM writerEAM = new FileWriterEAM(fileName);    
    try {
      block.accept(writerEAM);
    } finally {
      writerEAM.close();
    }
  }

  public static void main(final String[] args) throws IOException {

    FileWriterEAM.use("eam.txt", writerEAM -> writerEAM.writeStuff("sweet"));

    FileWriterEAM.use("eam2.txt", writerEAM -> {
        writerEAM.writeStuff("how");
        writerEAM.writeStuff("sweet");      
      });

    FileWriterEAM.use("eam3.txt", FileWriterEAM::writeIt);     

  }


 void writeIt() throws IOException{
     this.writeStuff("How ");
     this.writeStuff("sweet ");
     this.writeStuff("it is");

 }

}
JohnnyO
  • 527
  • 9
  • 21
1

The only built-in way of handling checked exceptions that can be thrown by a map operation is to encapsulate them within a CompletableFuture. (An Optional is a simpler alternative if you don't need to preserve the exception.) These classes are intended to allow you to represent contingent operations in a functional way.

A couple of non-trivial helper methods are required, but you can arrive at code that's relatively concise, while still making it apparent that your stream's result is contingent on the map operation having completed successfully. Here's what it looks like:

    CompletableFuture<List<Class<?>>> classes =
            Stream.of("java.lang.String", "java.lang.Integer", "java.lang.Double")
                  .map(MonadUtils.applyOrDie(Class::forName))
                  .map(cfc -> cfc.thenApply(Class::getSuperclass))
                  .collect(MonadUtils.cfCollector(ArrayList::new,
                                                  List::add,
                                                  (List<Class<?>> l1, List<Class<?>> l2) -> { l1.addAll(l2); return l1; },
                                                  x -> x));
    classes.thenAccept(System.out::println)
           .exceptionally(t -> { System.out.println("unable to get class: " + t); return null; });

This produces the following output:

[class java.lang.Object, class java.lang.Number, class java.lang.Number]

The applyOrDie method takes a Function that throws an exception, and converts it into a Function that returns an already-completed CompletableFuture -- either completed normally with the original function's result, or completed exceptionally with the thrown exception.

The second map operation illustrates that you've now got a Stream<CompletableFuture<T>> instead of just a Stream<T>. CompletableFuture takes care of only executing this operation if the upstream operation succeeded. The API makes this explict, but relatively painless.

Until you get to the collect phase, that is. This is where we require a pretty significant helper method. We want to "lift" a normal collection operation (in this case, toList()) "inside" the CompletableFuture -- cfCollector() lets us do that using a supplier, accumulator, combiner, and finisher that don't need to know anything at all about CompletableFuture.

The helper methods can be found on GitHub in my MonadUtils class, which is very much still a work in progress.

Matt McHenry
  • 20,009
  • 8
  • 65
  • 64
1

I use this kind of wrapping exception:

public class CheckedExceptionWrapper extends RuntimeException {
    ...
    public <T extends Exception> CheckedExceptionWrapper rethrow() throws T {
        throw (T) getCause();
    }
}

It will require handling these exceptions statically:

void method() throws IOException, ServletException {
    try { 
        list.stream().forEach(object -> {
            ...
            throw new CheckedExceptionWrapper(e);
            ...            
        });
    } catch (CheckedExceptionWrapper e){
        e.<IOException>rethrow();
        e.<ServletExcepion>rethrow();
    }
}

Try it online!

Though exception will be anyway re-thrown during first rethrow() call (oh, Java generics...), this way allows to get a strict statical definition of possible exceptions (requires to declare them in throws). And no instanceof or something is needed.

Colin D Bennett
  • 11,294
  • 5
  • 49
  • 66
Taras
  • 507
  • 1
  • 6
  • 17
-1

I think this approach is the right one:

public List<Class> getClasses() throws ClassNotFoundException {
    List<Class> classes;
    try {
        classes = Stream.of("java.lang.Object", "java.lang.Integer", "java.lang.String").map(className -> {
            try {
                return Class.forName(className);
            } catch (ClassNotFoundException e) {
                throw new UndeclaredThrowableException(e);
            }
        }).collect(Collectors.toList());
    } catch (UndeclaredThrowableException e) {
        if (e.getCause() instanceof ClassNotFoundException) {
            throw (ClassNotFoundException) e.getCause();
        } else {
            // this should never happen
            throw new IllegalStateException(e.getMessage(), e);
        }
    }
    return classes;
}

Wrapping the checked exception inside the Callable in a UndeclaredThrowableException (that’s the use case for this exception) and unwrapping it outside.

Yes, I find it ugly, and I would advise against using lambdas in this case and just fall back to a good old loop, unless you are working with a parallel stream and paralellization brings an objective benefit that justifies the unreadability of the code.

As many others have pointed out, there are solutions to this situation, and I hope one of them will make it into a future version of Java.

Matthias Ronge
  • 9,403
  • 7
  • 47
  • 63
  • 1
    (1) There are already several answers showing an example like this, so what does your answer add to the Q&A that's not already covered? Posting duplicate answers like this just adds clutter to the site. (2) The OP specifically says they *don't* want to do this. *"Please note I do NOT want to wrap the checked exception inside a runtime exception and throw the wrapped unchecked exception instead."* – Radiodef Aug 09 '18 at 19:09