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);
}
};
Why can't I throw an exception in a Java 8 lambda expression?
You are not allowed to throw checked exceptions because the accept(T t, U u)
method in the java.util.function.BiConsumer<T, U>
interface doesn't declare any exceptions in its throws
clause. And, as you know, Map#forEach
takes such a type.
public interface Map<K, V> {
default void forEach(BiConsumer<? super K, ? super V> action) { ... }
} |
|
V
@FunctionalInterface
public interface BiConsumer<T, U> {
void accept(T t, U u); // <-- does throw nothing
}
That is true when we are talking about checked exceptions. But you still can throw an unchecked exception (e.g. a java.lang.IllegalArgumentException
):
new HashMap<String, String>()
.forEach((a, b) -> { throw new IllegalArgumentException(); });
Throwing exception from lambda
My approach would be to sneakily throw it from the lambda, but take care to have the send
method declare it in its throws
clause. Using the Exceptional
class I posted here:
public Server send(String message) throws IOException {
sessions.parallelStream()
.map(Session::getBasicRemote)
.forEach(basic -> Exceptional.from(() -> basic.sendText(message)).get());
return this;
}
This way you're effectively making the compiler "look away" for just a bit, disabling its exception checking at one spot in your code, but by declaring the exception on your send
method, you restore the regular behavior for all its callers.
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 *
Java8 Lambda Function assignment with exception
I think your problem is NotFoundException is a checked exception. Checked Exceptions (not RuntimeException subclasses) can not be thrown in a lambda.
A workaround is to catch it and rethrown inside a RuntimeException as its cause.
Eg:
Function<Long, ShoppingCart> func = e -> {
try {
return fetchCart(e);
} catch (NotFoundException ex) {
RuntimeException re = new RuntimeException();
re.initCause(ex);
throw re;
}
return null;
};
Then, when you will catch the runtimeException, you will have to handle its cause.
try {
/// call func here
} catch(Exception e) {
((NotFoundException)e.getCause()).printStackTrace();
}
Why can't Java Lambda throw an checked exception
It's pretty much a method. If the method signature is declared to throw a checked exception, then a checked exception can be thrown inside of the lambda.
Imagine if you could.
Runnable r = ()->{ throw new CheckedException();};
Now our imaginary runnable.run can be called, but the caller will not know it has to handle a checked exception.
Callable on the other hand does throw an Exception.
Callable c = ()->{ throw new CheckedException();};
This works fine, because Callable.call is declared to throw an exception. You don't know the specific type of exception, but you have to handle one.
Exception handling using Lambda in Java 8
Your lambda needs to return a MyObject
. If the try
block completes successfully that is the case, but if it doesn't the catch
block is executed which does not return anything. So you could write:
Creatable<MyObject> creator = () -> {
try {
return new MyObject();
} catch (IOException e) {
e.printStackTrace();
return null;
}
};
But then you will get another compile error: "IOException is never thrown in try block". So you would also need to have a constructor in MyObject
that throws an IOException
:
class MyObject { MyObject() throws IOException {} }
In the end, unless MyObject
actually throws an exception, you can simply use:
Creatable<MyObject> creator = () -> new MyObject();
which you can also write:
Creatable<MyObject> creator = MyObject::new;
Java why exception handling needed in lambda when use curly braces
List#forEach
expects a Consumer
.
Consumer
is a (single-abstract-method) interface that looks like this (simplified):
@FunctionalInterface
public interface Consumer<T>{
void accept(T t);
}
As you see, accept
does not throw any checked exceptions.
The lambda expression is an implementation of that interface so it cannot throw any exceptions, no matter what the other code does.
Why doesn't Lambda understand throws in method signature?
Remember that lambdas are supposed to be implementations of functional interfaces. In this case, forEach
takes the functional interface Consumer<T>
as a parameter.
void forEach(Consumer<? super T> action)
So your lambda is actually implementing the single abstract method in the Consumer
interface - accept
. This method is not declared to throw any exceptions:
void accept(T t); // no throws clause here at all!
Therefore, the IOException
that the write
call could throw is considered to be unhandled. The fact that you have added a throws
clause to your saveTodoItems
method is irrelevant.
On the other hand, if you have declared your own functional interface that does have a throws
clause in its single abstract method:
interface IOConsumer<T> {
void accept(T t) throws IOException;
}
It is possible to write:
IOConsumer<TodoItem> consumer = todoItem -> {
outputStream.write(todoItem.getShortDescription() + "\t"
+ todoItem.getDetail() + "\t"
+ todoItem.getDeadLine()+"\n");
};
Of course, you would not be able to use this in forEach
, because it only accepts a Consumer
, not an IOConsumer
. You should surround the write
with a try...catch, or see here for more alternatives.
Related Topics
How to Implement a Tree Data-Structure in Java
"Error: Main Method Not Found in Class Myclass, Please Define the Main Method As..."
What's the Difference Between ".Equals" and "=="
How to Get the Separate Digits of an Int Number
403 Forbidden With Java But Not Web Browser
Value Change Listener to Jtextfield
A Java Collection of Value Pairs? (Tuples)
Causes of Getting a Java.Lang.Verifyerror
Type List VS Type Arraylist in Java
How to Check If a File Exists in Java
Nullpointerexception When Creating an Array of Objects
Java Arrays Printing Out Weird Numbers and Text