我知道如何创建一个有String参数并返回int的方法的引用,它是:

Function<String, Integer>

然而,如果函数抛出异常,比如它被定义为:

Integer myMethod(String s) throws IOException

我该如何定义这个引用呢?


当前回答

实际上,您可以使用一个处理异常的新接口来扩展Consumer(和Function等)——使用Java 8的默认方法!

考虑这个接口(扩展Consumer):

@FunctionalInterface
public interface ThrowingConsumer<T> extends Consumer<T> {

    @Override
    default void accept(final T elem) {
        try {
            acceptThrows(elem);
        } catch (final Exception e) {
            // Implement your own exception handling logic here..
            // For example:
            System.out.println("handling an exception...");
            // Or ...
            throw new RuntimeException(e);
        }
    }

    void acceptThrows(T elem) throws Exception;

}

然后,例如,如果你有一个列表:

final List<String> list = Arrays.asList("A", "B", "C");

如果你想消费它(例如。使用forEach)和一些抛出异常的代码,你通常会设置一个try/catch块:

final Consumer<String> consumer = aps -> {
    try {
        // maybe some other code here...
        throw new Exception("asdas");
    } catch (final Exception ex) {
        System.out.println("handling an exception...");
    }
};
list.forEach(consumer);

但是有了这个新接口,你可以用lambda表达式实例化它,编译器不会报错:

final ThrowingConsumer<String> throwingConsumer = aps -> {
    // maybe some other code here...
    throw new Exception("asdas");
};
list.forEach(throwingConsumer);

或者甚至只是转换它更简洁!:

list.forEach((ThrowingConsumer<String>) aps -> {
    // maybe some other code here...
    throw new Exception("asda");
});

更新

看起来榴莲有一个非常好的实用程序库,叫做Errors,可以用来解决这个问题,具有更大的灵活性。例如,在上面的实现中,我显式地定义了错误处理策略(System.out…或者抛出RuntimeException),而Durian的Errors允许您通过一套大型实用程序方法动态应用策略。感谢分享,@NedTwigg!

示例用法:

list.forEach(Errors.rethrow().wrap(c -> somethingThatThrows(c)));

其他回答

您需要执行以下操作之一。

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

你可以使用ET。ET是一个用于异常转换/转换的小型Java 8库。

对于ET,它看起来是这样的:

// Do this once
ExceptionTranslator et = ET.newConfiguration().done();

...

// if your method returns something
Function<String, Integer> f = (t) -> et.withReturningTranslation(() -> myMethod(t));

// if your method returns nothing
Consumer<String> c = (t) -> et.withTranslation(() -> myMethod(t));

ExceptionTranslator实例是线程安全的,可以由多个组件共享。如果你喜欢,你可以配置更具体的异常转换规则(例如FooCheckedException -> BarRuntimeException)。 如果没有其他可用的规则,被检查的异常将自动转换为RuntimeException。

(声明:我是ET的作者)

如果你有lombok,你可以用@SneakyThrows注释你的方法

SneakyThrow不会静默地吞咽、包装到RuntimeException中,或以其他方式修改所列出的检查异常类型的任何异常。JVM不检查被检查异常系统的一致性;Javac可以,而且这个注释允许您选择不使用它的机制。

https://projectlombok.org/features/SneakyThrows

一些提供的解决方案使用E的泛型参数来传递抛出的异常类型。

更进一步,不是传递异常的类型,而是传递异常类型的Consumer,如……

Consumer<E extends Exception>

您可以创建几个Consumer<Exception>的可重用变体,这些变体将覆盖应用程序的常见异常处理需求。

这个问题也一直困扰着我;这就是我创建这个项目的原因。

用它你可以做:

final ThrowingFunction<String, Integer> f = yourMethodReferenceHere;

JDK总共定义了39个接口,它们都有类似的抛出功能;这些都是流中使用的@ functionalinterface(基本流,还有IntStream, LongStream和DoubleStream)。

当它们中的每一个都扩展了它们的非抛出对应对象时,你也可以直接在lambdas中使用它们:

myStringStream.map(f) // <-- works

默认行为是,当您抛出lambda抛出一个检查异常时,抛出一个ThrownByLambdaException,并将检查异常作为原因。因此,您可以捕捉到它并得到原因。

其他特性也可用。