Java 8中使用Consumer函数进行异常处理

3

这段代码在processBatch(batch, this::backupMetacard);这一行上给我编译错误。process batch方法将consumer包装在try/catch块中,但Java无法编译此调用。

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 {...}

1
那么try-catch部分在哪里? - Tunaki
@Tunaki try{}将operation.accept调用包装在processBatch方法中。 - ahoffer
可能的问题是函数签名没有声明它会抛出错误。也许可以替换为void processBatch(List<Metacard> metacards, Consumer<Metacard> operation) throws IOException() - Debosmit Ray
5个回答

4

Consumer.accept()方法没有声明异常,而您的backupMetacard方法却有,因此您无法将this::backupMetacard作为Consumer参数传递。


4
问题在于以下代码片段中,方法backupMetacard声明要抛出受检查的IOException异常。
getExecutor().submit(() -> {
    processBatch(batch, this::backupMetacard);
                        ^^^^^^^^^^^^^^^^^^^^ // <-- this throws a checked exception
});

因此,它不再符合功能方法的合同 Consumer,即apply并且不声明抛出已检查异常。
将其包装在try-catch中,在那里您可以抛出未经检查的异常而不是UncheckedIOException
getExecutor().submit(() -> {
    processBatch(batch, metacard -> {
        try {
            backupMetacard(metacard);
        } catch (IOException e) {
            throw new UncheckedIOException(e);
        }
    });
});

它可以工作。我希望将错误处理保留在processBatch方法中,因为这样我就可以使用backupMetacard()、updateMetacard()、deleteMetacard()等多态方式。但是这并不容易实现。 - ahoffer

2
你可以拥有一个适配器功能接口。
interface ConsumerX<T>
{
    void consumeX(T) throws Exception;

    void default consume(T t)
    {
        try{ consumeX(t); }
        catch.... // handle exception
    }
}

并像这样使用它

processBatch( batch, (ConsumerX<Metacard>)this::backupMetacard )

类型参数<Metacard>似乎是多余的,但不幸的是在当前的Java中是必需的。然而,我们可以使用一个辅助方法来代替。

    static <T> ConsumerX<T> of(ConsumerX<T> c){ return c; }

processBatch( batch, ConsumerX.of(this::backupMetacard) )

还有更多需要考虑的事情。目前,ConsumerX 抛出了一个固定且过于普遍的 Exception。我们希望它能够抛出与 lambda 体相同的异常,即异常透明。这可以通过 consumeX() 抛出类型变量来实现。

另一件事是提供自定义异常处理,例如:

    ConsumerX.of( lambda, ex->{ ... } )

或者按照我喜欢的语法 -
    ConsumerX.of(...).catch_(FooException.class, fe->{ ... });

1
以下是基本上包含 try-catch 块并使用异常对象的片段代码。
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 - 这是一个函数式接口,执行带异常的操作。

@FunctionalInterface
public interface ExceptionBearingAction<T> {

   T doAction() throws Exception; 
}

如何使用它。
unchecked(() -> Files.copy(srcPath, Paths.get(distFileUrl), StandardCopyOption.REPLACE_EXISTING), (ex) -> LOGGER.warn("Oops!! copy failed due to {}", ex));

1
你可以使用apache commons-lang3库来完成这个操作。 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>

更改方法: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));
    }
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接