'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.

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));
    }
}

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