I appreciate a lot the new Java 8 features about lambdas and default methods interfaces. Yet, I still get bored with checked exceptions. For instance, if I just want to list all the visible fields of an object I would like to simply write this:
Arrays.asList(p.getClass().getFields()).forEach(
f -> System.out.println(f.get(p))
);
Yet, since the get
method might throw a checked exception, which does not agrees with the Consumer
interface contract, then I must catch that exception and write the following code:
Arrays.asList(p.getClass().getFields()).forEach(
f -> {
try {
System.out.println(f.get(p));
} catch (IllegalArgumentException | IllegalAccessException ex) {
throw new RuntimeException(ex);
}
}
);
However in most cases I just want the exception to be thrown as a RuntimeException
and let the program handle, or not, the exception without compilation errors.
So, I would like to have your opinion about my controversial workaround for checked exceptions annoyance. To that end, I created an auxiliary interface ConsumerCheckException<T>
and an utility function rethrow
(updated according to the sugestion of Doval's comment ) as follows:
@FunctionalInterface
public interface ConsumerCheckException<T>{
void accept(T elem) throws Exception;
}
public class Wrappers {
public static <T> Consumer<T> rethrow(ConsumerCheckException<T> c) {
return elem -> {
try {
c.accept(elem);
} catch (Exception ex) {
/**
* within sneakyThrow() we cast to the parameterized type T.
* In this case that type is RuntimeException.
* At runtime, however, the generic types have been erased, so
* that there is no T type anymore to cast to, so the cast
* disappears.
*/
Wrappers.<RuntimeException>sneakyThrow(ex);
}
};
}
/**
* Reinier Zwitserloot who, as far as I know, had the first mention of this
* technique in 2009 on the java posse mailing list.
* http://www.mail-archive.com/[email protected]/msg05984.html
*/
public static <T extends Throwable> T sneakyThrow(Throwable t) {
throw (T) t;
}
}
And now I can just write:
Arrays.asList(p.getClass().getFields()).forEach(
rethrow(f -> System.out.println(f.get(p)))
);
I am not sure that this is the best idiom to turn around the checked exceptions, but as I explained, I would like to have a more convenient way of achieving my first example without dealing with checked exceptions and this is the simpler way that I found to do it.
7 Answers 7
Advantages, disadvantages, and limitations of your technique:
If the calling-code is to handle the checked exception you MUST add it to the throws clause of the method that contains the stream. The compiler will not force you to add it anymore, so it's easier to forget it. For example:
public void test(Object p) throws IllegalAccessException { Arrays.asList(p.getClass().getFields()).forEach(rethrow(f -> System.out.println(f.get(p)))); }
If the calling-code already handles the checked exception, the compiler WILL remind you to add the throws clause to the method declaration that contains the stream (if you don't it will say: Exception is never thrown in body of corresponding try statement).
In any case, you won't be able to surround the stream itself to catch the checked exception INSIDE the method that contains the stream (if you try, the compiler will say: Exception is never thrown in body of corresponding try statement).
If you are calling a method which literally can never throw the exception that it declares, then you should not include the throws clause. 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.
If you hate checked exceptions and feel they should never be added to the Java language to begin with (a growing number of people think this way, and I am NOT one of them), then just don't add the checked exception to the throws clause of the method that contains the stream. The checked exception will, then, behave just like an UNchecked exception.
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, then 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 this case, you may decide not to add the checked exception to the throws clause of the method that contains the stream.
In any case, if you decide NOT to add (or forget to add) the checked exception to the throws clause of the method that contains the stream, be aware of these 2 consequences of throwing CHECKED exceptions:
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 catched in the main program loop by some "catch Exception" or "catch Throwable", which may be what you want anyway.
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:
- http://www.philandstuff.com/2012/04/28/sneakily-throwing-checked-exceptions.html
- http://www.mail-archive.com/[email protected]/msg05984.html
- Project Lombok annotation: @SneakyThrows
- Brian Goetz opinion (against) here: https://stackoverflow.com/questions/27644361/how-can-i-throw-checked-exceptions-from-inside-java-8-streams
- Workaround for Java checked exceptions *
NOTE: If you decide to use this technique, you may copy the LambdaExceptionUtil
helper class from StackOverflow: https://stackoverflow.com/questions/27644361/how-can-i-throw-checked-exceptions-from-inside-java-8-streams . It gives you the complete implementation (Function, Consumer, Supplier...), with examples.
In this example, can it ever really fail? Don't think so, but maybe your case is special. If it really "can't fail", and its just an annoying compiler thing, I like to wrap the exception and throw an Error
with a comment "cannot happen". Makes things very clear for maintenance. Otherwise they will wonder "how can this happen" and "who the heck handles this?"
This in a controversial practice so YMMV. I'll probably get some downvotes.
-
3+1 because you will throw an Error. How many times have I ended up after hours of debugging at a catch block containing just a single line comment "can't happen"...Axel– Axel01/30/2014 13:31:48Commented Jan 30, 2014 at 13:31
-
3-1 because you will throw an Error. Errors are to indicate that something is wrong in JVM and upper levels may handle them accordingly. If you choose that way, you should throw RuntimeException. Another possible workarounds are asserts (need -ea flag enabled) or logging.duros– duros03/28/2014 15:31:19Commented Mar 28, 2014 at 15:31
-
3@duros: Depending upon why the exception "can't happen", the fact that it gets thrown may indicate that something is severely wrong. Suppose, for example, if one calls
clone
on a sealed typeFoo
which is known to support it, and it throwsCloneNotSupportedException
. How could that happen unless the code got linked with some other unexpected kind ofFoo
? And if that happens, can anything be trusted?supercat– supercat07/09/2014 20:46:36Commented Jul 9, 2014 at 20:46 -
1@supercat excellent example. Others are throwing exceptions from missing String Encodings or MessageDigests If UTF-8 or SHA are missing your runtime is likely corrupted.user949300– user94930007/10/2014 00:52:34Commented Jul 10, 2014 at 0:52
-
1@duros That's a complete misconception.
An Error is a subclass of Throwable that indicates serious problems that a reasonable application should not try to catch.
(quoted from the Javadoc ofError
) This is exactly that kind of situation, therefore far from being inadequate, throwing anError
here is the most appropriate option.biziclop– biziclop11/27/2015 10:46:34Commented Nov 27, 2015 at 10:46
another version of this code where checked exception is just delayed :
public class Cocoon {
static <T extends Throwable> T forgetThrowsClause(Throwable t) throws T{
throw (T) t;
}
public static <X, T extends Throwable> Consumer<X> consumer(PeskyConsumer<X,T> touchyConsumer) throws T {
return new Consumer<X>() {
@Override
public void accept(X t) {
try {
touchyConsumer.accept(t);
} catch (Throwable exc) {
Cocoon.<RuntimeException>forgetThrowsClause(exc) ;
}
}
} ;
}
// and so on for Function, and other codes from java.util.function
}
the magic is that if you call:
myArrayList.forEach(Cocoon.consumer(MyClass::methodThatThrowsException)) ;
then your code will be obliged to catch the exception
-
What happens if this is run on a parallel stream where elements are consumed in different threads?prunge– prunge01/15/2015 04:05:01Commented Jan 15, 2015 at 4:05
sneakyThrow is cool! I totally feel your pain.
If you have to stay in Java...
Paguro has functional interfaces that wrap checked exceptions so you don't have to think about this any more. It includes immutable collections and functional transformations along the lines of Clojure transducers (or Java 8 Streams) that take the functional interfaces and wrap checked exceptions.
There is also VAVr and The Eclipse Collections to try out.
Otherwise, use Kotlin
Kotlin is 2-way compatible with Java, has no checked exceptions, no primitives (well, not the the programmer has to think about), a better type system, assumes immutability, etc. Even though I curate the Paguro library above, I'm converting all the Java code I can to Kotlin. Anything I used to do in Java I now prefer to do in Kotlin.
-
Somebody down-voted this, which is fine, but I won't learn anything unless you tell me why you down-voted it.GlenPeterson– GlenPeterson02/25/2016 18:56:45Commented Feb 25, 2016 at 18:56
-
1+1 for your library in github, You can check also eclipse.org/collections or project vavr which provide functional and immutable collections. What are your thoughts on these ?firephil– firephil03/16/2019 05:13:43Commented Mar 16, 2019 at 5:13
-
Kotlin solves the problem by throwing the baby out with the bath water.john16384– john1638405/03/2020 11:16:41Commented May 3, 2020 at 11:16
First let me say that there is absolutely nothing stopping you in Java to have checked exceptions work with Lambda's. The current implementation of Stream
, Optional
and some default methods on the collection classes however were created without allowing for checked exceptions.
It is however perfectly possible to have a Function
class that allows you to throw a checked exception.
public interface ThrowingFunction<T, R, E extends Exception> {
R apply(T t) throws E;
}
This has some limitations (you can only declare one exception), but this will often suffice. In cases where it doesn't one can declare a common superclass of the exceptions involved and still have the compiler remind you to deal with it.
Now, some of the answers given are a bit dubious and rely on compiler trickery to make it seems like the compiler is helping you not to forget to deal with a checked exception.
Take:
list.forEach(compilerTrickery(this::myCheckedExceptionThrowingFunction))
The exception is declared to be thrown from the compilerTrickery
method so "magically" you must declare it be thrown or catch it... but when running this code, you will find that the exception is actually thrown by forEach
. You can see this if you assign the consumer first to a variable:
try {
Consumer x = compilerTrickery(this::myCheckedExceptionThrowingFunction);
}
catch(Exception e) {
throw new RuntimeException(e);
}
list.forEach(x); // <-- checked exception thrown from here
Running the above code will drop a checked exception bomb on you at the forEach
call.
The only correct way to solve this is wrap the List
, and redefine the signature of the forEach
call to include an exception generic parameter. A lot of effort.
For streams this is a bit simpler, and there are some implementations written that do exactly that.
It can result in code like:
CheckedStream.forIOException(List.of("a", "b", "c").stream())
.map(this::someFunctionThatThrowsIOException)
.collect(Collectors.toList());
Only collect
here is throwing a checked exception, all intermediate steps donot, so this code compiles:
// Does not throw an exception:
CheckedStream<String, IOException> s1 = CheckedStream.forIOException(List.of("a", "b", "c").stream())
.map(this::someFunctionThatThrowsIOException);
try {
// Exception is declared here, so surround with try/catch:
s1.collect(Collectors.toList());
}
catch(IOException e) {
// handle exception
}
The advantage over approaches that use a Try
or Either
is that you donot need to change your entire program flow when you want to use a stream somewhere. Your method can still declare the IOException
and have it handled in the usual way helping callers to remember to deal with these cases.
Also, when processing streams, you may not want to continue processing when a step fails or have to check all results for an error.
Checked exceptions are very useful and their handling depends on the kind of product you code is part of:
- a library
- a desktop application
- a server running within some box
- an academical exercise
Usually a library must not handle checked exceptions, but declare as thrown by public API. The rare case when they could wrapped into plain RuntimeExcepton is, for example, creating inside of library code some private xml document and parsing it, creating some temporary file and then reading that.
For desktop applications you must start the development of product by creating your own exception handling framework. Using you own framework usually you will wrap a checked exception into some of two to four wrappers (your custom sub-classes of RuntimeExcepion) and handle them by a single Exception Handler.
For servers usually your code will run inside of some framework. If you don't use any (a bare server) create your own framework similar (based on Runtimes) described above.
For academical exercises you can always wrap them directly into RuntimeExcepton. Somebody can create a tiny framework too.
You may want to have a look at this project; I created it specifically because of the problem of checked exceptions and functional interfaces.
With it you can do this instead of writing your custom code:
// I don't know the type of f, so it's Foo...
final ThrowingConsumer<Foo> consumer = f -> System.out.println(f.get(p));
Since all those Throwing* interfaces extend their non Throwing counterparts, you can then use them directly in stream:
Arrays.asList(p.getClass().getFields()).forEach(consumer);
Or you can just:
import static com.github.fge.lambdas.consumers.Consumers.wrap;
Arrays.asList(p.getClass().getFields())
.forEach(wrap(f -> System.out.println(f.get(p)));
And other things.
-
Better still
fields.forEach((ThrowingConsumer<Field>) f -> out.println(f.get(o)))
user2418306– user241830601/05/2016 17:23:57Commented Jan 5, 2016 at 17:23 -
Explore related questions
See similar questions with these tags.
sneakyThrow
inside ofrethrow
to throw the original, checked exception instead of wrapping it in aRuntimeException
. Alternatively you could use the@SneakyThrows
annotation from Project Lombok that does the same thing.Consumer
s inforEach
may be executed in parallel fashion when using parallelStream
s. A throwable raised from withing the consumer will then propagate to the calling thread, which 1) won't stop the other concurrently running consumers, which may or may not be appropriate, and 2) if more than one of the consumers throw something, only one of the throwables will be seen by the calling thread.