I'm doing some tests using lambda expressions but my code does not compile. My lambda implementation is wrong or the exception handling? What would be the correct implementation of the following code?
class MyObject { }
interface Creatable<T> {
T create() throws IOException;
}
/* Using the code: */
Creatable<MyObject> creator = () -> {
try {
return new MyObject();
} catch (IOException e) {
e.printStackTrace();
}
};
MyObject obj1 = creator.create();
If i remove the try catch block and declare the exception to throw in the method, the code compiles and runs normally.
Creatable<MyObject> creator = () -> new MyObject();
The compilation error is:
incompatible types: bad return type in lambda expression
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;
Lambda needs all paths to return the value as mentioned in the previous answer the easy solution is to return at the end of the catch block
However there is a more elegant way to handle exception when using lambda
you can wrap a lambda with another
Example
wrap(((x,y)->x/y))
Biconsumer<Integer,Integer> consumer wrap(Biconsumer<Integer,Integer> consumer)
{
return (v,k)->{try
{consumer.apply()}
catch(){};
}
https://www.youtube.com/watch?v=YLKMCPMLv60&list=PLqq-6Pq4lTTa9YGfyhyW2CqdtW9RtY-I3&index=18
#FunctionalInterface
public interface CreateThrowable<T, R, E extends Throwable> {
R create(T t) throws E;
static <T, R, E extends Throwable> Function<T, R> uncheckedException(ThrowingFunction<T, R, E> f) {
return t -> {
try {
return f.create(t);
} catch (Throwable e) {
throw new RuntimeException(e);
}
};
}
}
Related
I have the below code
import java.util.function.BiConsumer;
public class ExceptionHandlingLambda {
public static void main(String[] args) {
int [] someNumbers = { 1, 2, 3, 4 };
int key = 2;
process(someNumbers, key, (v,k) -> {
try{
System.out.println(v/k);
}
catch(ArithmeticException e){
//handle exception
}
});
}
private static void process(int[] someNumbers, int key, BiConsumer<Integer, Integer> consumer) {
for (int i : someNumbers) {
//can put a try catch here but this is generic and we don't know what exception we are catching.
consumer.accept(i, key);
}
}
}
I am trying to handle some exception in a lambda. From above I have handled an exception within a lambda.
I think it makes my lambda look kind of messy.
I could also handle the exception in the process method but it would be generic and we wouldn't know what exception we are handling for.
Any other better way to handle this in lambda to have cleaner code? Any suggestions would be much appreciated.
After the suggestion from some great and kind minds I have an answer. Hope this helps someone.
process(someNumbers, key, wrapperLambda((v, k) -> System.out.println(v / k)));
//with method reference
process(someNumbers, key, ExceptionHandlingLambda::wrapperLambda);
A wrapper function for lambda which accepts a lambda and return a lambda with a try catch which makes it much cleaner.
private static BiConsumer<Integer, Integer> wrapperLambda(BiConsumer<Integer, Integer> consumer) {
//creating a new lambda and return.
// return (v,k) -> System.out.println(v+k); this would replace the lambda with addition lambda (v+k)
return (v, k) -> {
try {
consumer.accept(v, k); //execute whatever is passed in.
}
catch (ArithmeticException e) {
System.out.println("Exception caught in wrapper lambda");
}
};
}
Apply try catch in your process method and pass an additional argument to the method i.e. the exception class for which you want to handle the exception.
Process method would look like
private static void process(int[] someNumbers, int key, BiConsumer<Integer, Integer> consumer, Class<E> clazz) {
for (int i : someNumbers) {
try{
consumer.accept(i, key);
} catch(Exception ex) {
try {
E exCast = clazz.cast(ex);
System.err.println(
"Exception occured : " + exCast.getMessage());
} catch (ClassCastException ccEx) {
throw ex;
}
}
}
}
This way your lambda would not look messy and you can decide which exception to be handled at the time of calling.
I am new to CompletableFuture, I will like to call a method MetadataLoginUtil::login which can throw an exception. However, the code below is not compiled although I have 'exceptionally' written. It says that I must wrap the MetadataLoginUtil::login' within try & catch.
Please advise.
Thanks ahead !
public void run() throws ConnectionException {
CompletableFuture<Void> mt = CompletableFuture.supplyAsync(MetadataLoginUtil::login)
.exceptionally(e -> {
System.out.println(e);
return null;
})
.thenAccept(e -> System.out.println(e));
}
This is not a deficiency of how CompletableFuture works in general, but of the convenience methods, all using functional interfaces not allowing checked exceptions. You can solve this with an alternative supplyAsync method:
public static <T> CompletableFuture<T> supplyAsync(Callable<T> c) {
CompletableFuture<T> f=new CompletableFuture<>();
CompletableFuture.runAsync(() -> {
try { f.complete(c.call()); } catch(Throwable t) { f.completeExceptionally(t); }
});
return f;
}
This is basically doing the same as the original supplyAsync, but allowing checked exceptions. So you can use it right like in your original attempt, only redirecting the initial supplyAsync call.
CompletableFuture<Void> mt = supplyAsync(MetadataLoginUtil::login)
.exceptionally(e -> { System.out.println(e); return null; } )
.thenAccept(e -> System.out.println(e));
CompletableFuture.supplyAsync(Supplier<U>) expects a java.util.function.Supplier<U> instance, and Supplier.get() method's signature does not allow for checked exceptions. To see this clearly, notice that CompletableFuture.supplyAsync(MetadataLoginUtil::login) is equivalent to
CompletableFuture<Void> mt = CompletableFuture.supplyAsync(new Supplier<Void>() {
#Override
public Void get() {
return MetadataLoginUtil.login();
}
})
which clearly cannot compile.
You can handle the exception inside your Supplier, changing CompletableFuture.supplyAsync(MetadataLoginUtil::login).exceptionally(e -> {System.out.println(e); return null; } ) to
CompletableFuture.supplyAsync(() -> {
try {
return MetadataLoginUtil.login();
} catch (Exception e) {
System.out.println(e);
return null;
}
})
It's not pretty, but CompletableFuture's API doesn't seem to work with checked exceptions very well.
I'm using Java 8 Stream API, and as we know it doesn't supports checked exceptions inside any functional interface inside java.util.function.
I usually have to use method with checked exceptions inside streams operations and I've wrote CheckedFunction decorator to use inside those operations:
import java.util.function.BiFunction;
import java.util.function.Function;
public interface CheckedFunction<T, R, E extends Throwable> {
R apply(T t) throws E;
static <T, R, CE extends Throwable, UCE extends RuntimeException> Function<T, R> checked(
CheckedFunction<T, R, CE> checked, Function<CE, UCE> exceptionHandler) {
return (t) -> {
try {
return checked.apply(t);
}
catch (RuntimeException | Error e) {
throw e;
}
catch (Throwable e) {
// can't catch - compiler error
if (e instanceof InterruptedException) {
Thread.currentThread().interrupt();
}
throw exceptionHandler.apply((CE) e);
}
};
}
}
so I can use it in such cases:
entities.stream()
.map(checked((entity) -> someResultChecked(entity), // throws IOException
(entity, e) -> { // e is of type IOException
log.error("exception during checked method of " + entity, e);
return new UncheckedIOException(e);
}))
.map(checked((entity) -> saveToDb(entity), // throws SQLException
(entity, e) -> { // e is of type SQLException
log.error("exception during saving " + entity, e);
return new UncheckedSQLException(e);
}))
.map(checked((entity) -> manyExceptionMethod(entity), // throws IOException, SQLException
(entity, e) -> { // e is of type Throwable
return new RuntimeException(e);
}))
It will wrap any checked exception to unchecked, but I know if method is throws more than one exception it will erase to Throwable, I'm going to use it in simple cases.
Is it good idea, or I can run into hidden obstacles?
UPDATED: Rethrowing RuntimeExceptions.
Also I found more clear solution in jOOL with handling InterruptedException which can cause inconsistent behavior if will be ignored:
https://github.com/jOOQ/jOOL/blob/master/src/main/java/org/jooq/lambda/Unchecked.java
You'll get a ClassCastException if anything other than an IOException gets thrown, since you're catching all Throwable and passing them into the UncheckedIOException constructor, which only takes an IOException as a parameter. Since catching IOException within a functional type is such a common need, rather than trying to generalize, it may be best to keep it simple and make one just for that checked exception. I would imagine you would rarely need to duplicate code to do the same for other checked exceptions.
#FunctionalInterface
public interface CheckedIOFunction<T,R> {
R apply(T t) throws IOException;
static <T, R> Function<T, R> toUnchecked(CheckedIOFunction<T, R> function) {
return t -> {
try {
return function.apply(t);
} catch (IOException ioe) {
throw new UncheckedIOException(ioe);
}
};
}
}
This code gives me a compile error on the line processBatch(batch, this::backupMetacard); The process batch method wraps the consumer in a try/catch block, but Java will not compile the call.
private synchronized void drain() {
for (List<Metacard> batch : Lists.partition(metacards, BATCH_SIZE)) {
getExecutor().submit(() -> {
processBatch(batch, this::backupMetacard);
});
}
metacards.clear();
}
void processBatch(List<Metacard> metacards, Consumer<Metacard> operation) {
List<String> errors = new ArrayList<>();
for (Metacard metacard : metacards) {
try {
operation.accept(metacard);
} catch (IOException e) {
errors.add(metacard.getId());
}
}
if (!errors.isEmpty()) {
LOGGER.info("Plugin processing failed. This is allowable. Skipping to next plugin.",
pluginExceptionWith(errors));
}
}
private void backupMetacard(Metacard metacard) throws IOException {...}
The problem is that in the following snippet, the method backupMetacard declares to throw the checked IOException.
getExecutor().submit(() -> {
processBatch(batch, this::backupMetacard);
^^^^^^^^^^^^^^^^^^^^ // <-- this throws a checked exception
});
As such, it does not comply anymore with the contract of the functional method of Consumer, which is apply and doesn't declare to throw checked exceptions.
Wrap this into a try-catch, where you can throw an unchecked exception instead UncheckedIOException:
getExecutor().submit(() -> {
processBatch(batch, metacard -> {
try {
backupMetacard(metacard);
} catch (IOException e) {
throw new UncheckedIOException(e);
}
});
});
Consumer.accept() does not declare an exception whereas your backupMetacard method does, so you can't pass this::backupMetacard as Consumer parameter.
You can have an adapter functional interface
interface ConsumerX<T>
{
void consumeX(T) throws Exception;
void default consume(T t)
{
try{ consumeX(t); }
catch.... // handle exception
}
}
And use it like
processBatch( batch, (ConsumerX<Metacard>)this::backupMetacard )
The type argument <Metacard> seems redundant, unfortunately it's needed in current Java. We could however have a helper method instead
static <T> ConsumerX<T> of(ConsumerX<T> c){ return c; }
processBatch( batch, ConsumerX.of(this::backupMetacard) )
There are more things to consider. Currently, ConsumerX throws a fixed, overreaching Exception. We would rather have it throw the same exception that the lambda body throws, i.e. exception transparency. This could be done by consumeX() throws a type variable.
Another thing is to provide custom exception handling, e.g.
ConsumerX.of( lambda, ex->{ ... } )
or my preferred syntax --
ConsumerX.of(...).catch_(FooException.class, fe->{ ... });
Below are snippet codes that is basically wrapped try-catch block and being consumed Exception object.
public static <T> T unchecked(final ExceptionBearingAction<T> template, Consumer<Exception> exceptionConsumer) {
T results = null;
try {
results = template.doAction();
} catch (Exception ex) {
exceptionConsumer.accept(ex);
}
return results;
}
ExceptionBearingAction.Java - It's a Functional Interface that perform and Exception bearing action.
#FunctionalInterface
public interface ExceptionBearingAction<T> {
T doAction() throws Exception;
}
How to used it
unchecked(() -> Files.copy(srcPath, Paths.get(distFileUrl), StandardCopyOption.REPLACE_EXISTING), (ex) -> LOGGER.warn("Oops!! copy failed due to {}", ex));
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
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>3.12.0</version>
</dependency>
Change method: processBatch
void processBatch(List<Metacard> metacards, FailableConsumer<Metacard, IOException> operation) {
List<String> errors = new ArrayList<>();
for (Metacard metacard : metacards) {
try {
operation.accept(metacard);
} catch (IOException e) {
errors.add(metacard.getId());
}
}
if (!errors.isEmpty()) {
LOGGER.info("Plugin processing failed. This is allowable. Skipping to next plugin.",
pluginExceptionWith(errors));
}
}
method which throws at first and second call:
public void foo() throws Exception
test:
#test
public void testFooThrowsAtFirstAndSecondTime(){
boolean thrown;
try {
foo();
} catch (Exception e) {
thrown = true;
}
assertTrue(thrown);
thrown = false;
try {
foo();
} catch (Exception e) {
thrown = true;
}
assertTrue(thrown);
foo();
}
Could you help me find a better solution for this?
Use of Mockito for a better solution would be also acceptable.
With better i mean, if i could avoid try/catch or even multiple try/catch in my test. In other languages or in jAssert i think even in spring there are statements like:
assertThrows(method(..)) //PseudoCode
I thought with Mockito or JUnit 4.x there is a similar thing.
I know about
#Test(expected=Exception)
But this would only be acceptable if i expect one throw and the test ends after that.
I don't think a one-liner per method invocation is possible.
I would write the test like this:
#Test
public void testFooThrowsAtFirstAndSecondTime() throws Exception {
try {
foo();
fail("foo did not throw an exception");
} catch (Exception ex) { }
try{
foo();
fail("foo did not throw an exception");
} catch (Exception ex) { }
foo();
}
The key here is that the try block is crucial if you want to resume execution after an exception. You can factor it out into a method or library, but it has to be called within your test method.
Things that work:
The tried-and-true fail() idiom that you and nrainier cite, which I prefer:
try {
foo();
fail("foo did not throw an exception");
} catch (Exception ex) { }
catch-exception is a library that, like Mockito, wraps the passed object and puts a try block around each method. Mockito's caveats about final methods and classes apply here too, so this won't always work.
List myList = new ArrayList();
catchException(myList).get(1); // myList is wrapped here
assert caughtException() instanceof IndexOutOfBoundsException;
Note that catch-exception is in "maintenance mode" because the Java 8 solution (below) is much more solid.
Any solution like assertThrows(() -> methodThatThrows()) (Java 8) or:
assertThrows(new Runnable() {
#Override public void run() { methodThatThrows(); }
});
...in Java 6/7. Importantly, assertThrows is called before methodThatThrows, so it can invoke methodThatThrows. Thanks Stefan for pointing out Fishbowl, but you could easily write an equivalent yourself:
public void assertThrows(Runnable block) {
try {
block.run();
fail("Block didn't throw.");
} catch (Exception ex) { }
}
Things that don't work:
#Test(expected=YourException.class) will go up the stack to the try block that JUnit wraps your test method in. Control never returns to the test method after that.
JUnit4's ExpectedException #Rule looks tempting, but because it wraps the entire test method, you have to set expectations before calling the method that throws the exception.
Anything that looks like assertThrows(methodCallThatThrows()). Java will try to get the return value out of methodCallThatThrows before assertThrows is ever invoked, so any try block there can't help.
With Java 8 you can use the Fishbowl library.
#Test
public void testFooThrowsAtFirstAndSecondTime(){
Throwable firstException = exceptionThrownBy(() -> foo());
assertEquals(Exception.class, firstException.getClass());
Throwable secondException = exceptionThrownBy(() -> foo());
assertEquals(Exception.class, secondException.getClass());
foo()
}
It is possible to use this library with Java 6 and 7, too. But then you have to use anonymous classes.
#Test
public void testFooThrowsAtFirstAndSecondTime(){
Throwable firstException = exceptionThrownBy(new Statement() {
public void evaluate() throws Throwable {
foo();
}
});
assertEquals(Exception.class, firstException.getClass());
Throwable secondException = exceptionThrownBy(new Statement() {
public void evaluate() throws Throwable {
foo();
}
});
assertEquals(Exception.class, secondException.getClass());
foo()
}
If you are unlucky enough to have to code for some version of java prior to 8, then you cannot do it with one line per exception.
But if you are using java 8, then you can do it as Stefan Birkner suggested.
Now, if you are unwilling to include an entire library for just one method, then here is a method that will work for you, copied from my blog
public final <T extends Throwable> T expectException( Class<T> exceptionClass, Runnable runnable )
{
try
{
runnable.run();
}
catch( Throwable throwable )
{
if( throwable instanceof AssertionError && throwable.getCause() != null )
throwable = throwable.getCause();
assert exceptionClass.isInstance( throwable ) : throwable; //exception of the wrong kind was thrown.
assert throwable.getClass() == exceptionClass : throwable; //exception thrown was a subclass, but not the exact class, expected.
#SuppressWarnings( "unchecked" )
T result = (T)throwable;
return result;
}
assert false; //expected exception was not thrown.
return null; //to keep the compiler happy.
}
So, your test code becomes something like this:
#Test
public void testFooThrowsAtFirstAndSecondTime()
{
expectException( Exception.class, this::foo );
expectException( Exception.class, this::foo );
foo();
}
#Test(expected=Exception.class)