'Exception handling with Consumer functions in Java 8
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 {...}
Solution 1:[1]
Consumer.accept() does not declare an exception whereas your backupMetacard method does, so you can't pass this::backupMetacard as Consumer parameter.
Solution 2:[2]
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->{ ... });
Solution 3:[3]
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));
Solution 4:[4]
You can do it with apache commons-lang3 library.
<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));
}
}
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 | wero |
| Solution 2 | ZhongYu |
| Solution 3 | Ajay Kumar |
| Solution 4 | Eltan Hajiyev |
