如何声明一个函数参数来接受抛出的函数?

Mic*_*son 7 java lambda throws java-8 kotlin

我在Kotlin中定义了一个函数:

fun convertExceptionToEmpty(requestFunc: () -> List<Widget>): Stream<Widget> {
    try {
        return requestFunc().stream()
    } catch (th: Throwable) {
        // Log the exception...
        return Stream.empty()
    }
}
Run Code Online (Sandbox Code Playgroud)

我已经使用此签名定义了一个Java方法:

List<Widget> getStaticWidgets() throws IOException;
Run Code Online (Sandbox Code Playgroud)

我试图像这样组成它们:

Stream<Widget> widgets = convertExceptionToEmpty(() ->  getStaticWidgets())
Run Code Online (Sandbox Code Playgroud)

当我编译时,我收到此错误:

错误:(ln,col)java:未报告的异常java.io.IOException; 必须被抓住或宣布被抛出

如何定义我的函数参数以接受抛出的函数?

hol*_*ava 4

问题是 Java 具有检查异常,但 Kotlin 没有。requestFunc 参数类型() -> List<Widget>将映射到函数接口Function0<List<Widget>>,但运算符调用不会在 Kotlin 代码中引发已检查异常。

所以你不能调用getStaticWidgets()in lambda 表达式,因为它会抛出一个IOExceptionJava 中的检查异常。

由于您同时控制 Kotlin 和 Java 代码,因此最简单的解决方案是将参数类型更改() -> List<Widget>Callable<List<Widget>>,例如:

// change the parameter type to `Callable` ---v
fun convertExceptionToEmpty(requestFunc: Callable<List<Widget>>): Stream<Widget> {
    try {
        //                 v--- get the `List<Widget>` from `Callable`
        return requestFunc.call().stream()
    } catch (th: Throwable) {
        return Stream.empty()
    }
}
Run Code Online (Sandbox Code Playgroud)

然后你可以进一步使用Java8中的方法引用表达式,例如:

Stream<Widget> widgets = convertExceptionToEmpty(this::getStaticWidgets);

//OR if `getStaticWidgets` is static `T` is the class belong to
//                                               v
Stream<Widget> widgets = convertExceptionToEmpty(T::getStaticWidgets);
Run Code Online (Sandbox Code Playgroud)