How can I throw CHECKED exceptions from inside Java 8 streams?
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's 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 2 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:
- http://www.philandstuff.com/2012/04/28/sneakily-throwing-checked-exceptions.html
- http://www.mail-archive.com/javaposse@googlegroups.com/msg05984.html
- Project Lombok annotation: @SneakyThrows
- Brian Goetz opinion (against) here: How can I throw CHECKED exceptions from inside Java 8 streams?
- https://softwareengineering.stackexchange.com/questions/225931/workaround-for-java-checked-exceptions?newreg=ddf0dd15e8174af8ba52e091cf85688e *
Handle checked exceptions in Java8 streams
You've basically listed two viable options.
One more option is to make the checked exceptions be thrown out of the stream processing function ("propagate" or "sneak" a checked exception). This is done by catching a checked exception and re-throwing it as a RuntimeException
(by casting). Take a look at this great answer for details.
Multiple libraries have been developed to deal with exception handling in stream API.
For example, you may take a look at the NoException library: https://noexception.machinezoo.com/
It gives you a convenient way to wrap / sneak / log / ignore checked or unchecked exceptions.
For example, in your case it would be:
.map(value -> Exceptions.sneak().function(mapper::doMap))
or
.map(value -> Exceptions.wrap().function(mapper::doMap))
P.S.: I'm NOT the author of the library, nor a contributor, but I've used this library in several projects.
Java 8 streams with checked exceptions
Short answer: No.
Longer answer: Yes, but with caveats.
Java's functional interfaces and streams were meant to facilitate functional programming. Functional programming focusses on immutable data and pure functions (that is, functions which have no side effects and always return the same result on the same arguments). If your method throws an IOException, this is apparently not a pure function, because it apparently reads from an external source. You should think about whether a functional programming style suits your needs in this case.
But if you really want to use streams and Java's functional interfaces, you can do one of the following:
- Wrap the checked exception in unchecked ones. (If you
compute
function is under your control, it could throw your ownUncheckedIOException
with the realIOException
wrapped in it). - Write your own functional interfaces which declare checked exceptions (but then, you won't be able to use them in a Java stream).
- Catch the exception within your lambda and handle it yourself. This is not very readable however, and it defeats one of the purposes of exceptions, namely that you can perform error handling outside of the method producing the error.
There are some third-party libraries which help you doing this.
Java 8: How do I work with exception throwing methods in streams?
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)
.
Why can't we throw exception inside Java 8 stream?
your code is working perfectly, apart from a missing semi colon at the end of the throw new ...
line, and from a missing a return statement that may be hidden in // code here
.
What you can't do is throw a checked exception (which RuntimeException is not) because checked exception are part of the method signature and the Predicate.test method do not declare one.
EDIT :
To see more precisely what is happening and why you can't throw a checked exception here, here is how you could have written the code without lambda :
From this :
public Person myMethod() throws IOException {
Person result = persons.stream()
.filter(x -> {
if ("test".equals(x.getName() ) ) {
throw new IOException("not possible inside stream y ?"); //any checked exception
}
//code here
return true;
});
return person;
}
to this :
public Person myMethod() throws IOException {
Person result = persons.stream()
.filter(new Predicate<Person>() {
public boolean test(Person x) {
if ("test".equals(x.getName() ) ) {
throw new IOException("not possible inside stream y ?"); //any checked exception
}
//code here
return true;
}
});
return person;
}
As you can see, the code inside the lambda expression is now inside the test
method of an anonymous Predicate
class, which is not declaring any checked exception.
Why Predicate
? Because it is what the filter
method is expecting, and you can use a lambda instead of a conventional object because it is a single method interface : only test
is abstract, and your lambda signature should be the same as the Predicate.test
method.
If you really wish to be able to handle checked exceptions, the linked post (in a comment from Frederico) show some ways to bypass these limitations.
How to handle Exception in Java 8 Stream?
You probably have too many responsibilities in your method. You should think about splitting it into a method that only maps and another one that gathers them.
private List<Result> getResultList(List<String> names) throws ResultClassException {
try {
return names.stream()
.map(this::getOrCreateResult)
.collect(collectingAndThen(toList(), Collections::unmodifiableList));
} catch (RuntimeException e) {
if (e.getCause() instanceof CustomException) {
throw new ResultClassException("Error", e.getCause());
}
throw e;
// Or use Guava's propagate
}
}
private Result getOrCreateResult(String name) {
if (!resultRepository.contains(name)) {
try {
return createResult(name);
} catch (CustomException e) {
throw new RuntimeException(e);
}
} else {
log.info("Result {} already exists.", name);
return resultRepository.get(name);
}
}
Java 8 Lambda function that throws exception?
You'll need to do one of the following.
If it's your code, then define your own functional interface that declares the checked exception:
@FunctionalInterface
public interface CheckedFunction<T, R> {
R apply(T t) throws IOException;
}and use it:
void foo (CheckedFunction f) { ... }
Otherwise, wrap
Integer myMethod(String s)
in a method that doesn't declare a checked exception:public Integer myWrappedMethod(String s) {
try {
return myMethod(s);
}
catch(IOException e) {
throw new UncheckedIOException(e);
}
}and then:
Function<String, Integer> f = (String t) -> myWrappedMethod(t);
or:
Function<String, Integer> f =
(String t) -> {
try {
return myMethod(t);
}
catch(IOException e) {
throw new UncheckedIOException(e);
}
};
Java 8: Mandatory checked exceptions handling in lambda expressions. Why mandatory, not optional?
Not sure I really answer your question, but couldn't you simply use something like that?
public final class SupplierUtils {
private SupplierUtils() {
}
public static <T> Supplier<T> wrap(Callable<T> callable) {
return () -> {
try {
return callable.call();
}
catch (RuntimeException e) {
throw e;
}
catch (Exception e) {
throw new RuntimeException(e);
}
};
}
}
public class JdbcConnectionPool extends ObjectPool<Connection> {
public JdbcConnectionPool(int maxConnections, String url) {
super(SupplierUtils.wrap(() -> DriverManager.getConnection(url)), maxConnections);
}
}
Java 8: Lambda-Streams, Filter by Method with Exception
You must catch the exception before it escapes the lambda:
s = s.filter(a -> {
try {
return a.isActive();
} catch (IOException e) {
throw new UncheckedIOException(e);
}
});
Consider the fact that the lambda isn't evaluated at the place you write it, but at some completely unrelated place, within a JDK class. So that would be the point where that checked exception would be thrown, and at that place it isn't declared.
You can deal with it by using a wrapper of your lambda that translates checked exceptions to unchecked ones:
public static <T> T uncheckCall(Callable<T> callable) {
try {
return callable.call();
} catch (RuntimeException e) {
throw e;
} catch (Exception e) {
throw new RuntimeException(e);
}
}
Your example would be written as
return s.filter(a -> uncheckCall(a::isActive))
.map(Account::getNumber)
.collect(toSet());
In my projects I deal with this issue without wrapping; instead I use a method which effectively defuses compiler's checking of exceptions. Needless to say, this should be handled with care and everybody on the project must be aware that a checked exception may appear where it is not declared. This is the plumbing code:
public static <T> T uncheckCall(Callable<T> callable) {
try {
return callable.call();
} catch (Exception e) {
sneakyThrow(e);
return null; // Unreachable but needed to satisfy compiler
}
}
public static void uncheckRun(RunnableExc r) {
try {
r.run();
} catch (Exception e) {
sneakyThrow(e);
}
}
public interface RunnableExc {
void run() throws Exception;
}
@SuppressWarnings("unchecked")
private static <T extends Throwable> void sneakyThrow(Throwable t) throws T {
throw (T) t;
}
and you can expect to get an IOException
thrown in your face, even though collect
does not declare it. In most, but not all real-life cases you would want to just rethrow the exception, anyway, and handle it as a generic failure. In all those cases, nothing is lost in clarity or correctness. Just beware of those other cases, where you would actually want to react to the exception on the spot. The developer will not be made aware by the compiler that there is an IOException
to catch there and the compiler will in fact complain if you try to catch it because we have fooled it into believing that no such exception can be thrown.
Related Topics
Connect to SQL Server from Linux via Jdbc Using Integratedsecurity (Windows Authentication)
Find Directory for "Application Data" on Linux and MACintosh
Why Does Reading from Process' Inputstream Block Altough Data Is Available
Arval SQLexception: Fatal: Sorry, Too Many Clients Already in Postgres
How to Store Unix Permissions in a Zip File (Built with Apache Ant)
Javafx: Could Not Find or Load Main Class Only on Linux
Cross-Platform Way to Open a File Using Java 1.5
How to Get Desktop Class Supported Under Linux
How to Open a Unc Path from Linux in Java
How to Use Chef to Update-Alternatives for Java Using Execute
Execute a Linux Terminal Command in Java
Kiosk Mode for Linux Java Swing Application
Why Stringbuilder Stops Adding Elements After Using the Null Character
How to Set Ld_Library_Path for Java Process