I have Kotlin interface

interface FileSystem {
    suspend fun getName(path: Path): List<String>
}

How I can call it from Java? What is

Continuation <? super List<String>>

enter image description here

推荐答案

Kotlin implements coroutines using a mix of the regular stack-based calling convention and the continuation-passing style (CPS). To achieve that, it performs a CPS transformation on all suspend funs by adding an implicit parameter, an object you can use to continue the program from the place where the function was called. That's how Kotlin manages to pull off the trick to suspend the execution within your function's body: it extracts the continuation object, saves it somewhere, and then makes your function return (without yet having produced its value). Later on it can achieve the effect of jumping into the middle of your function body by invoking the continuation object.

延续基本上是一个回调对象,就像异步JavaAPI中熟悉的对象一样.可挂起函数将其结果传递给Continue,而不是返回其结果.要从java调用suspend fun,您必须创建这样的回调.下面是一个示例:

Continuation<List<String>> myCont = new Continuation<List<String>>() {
    @Override public void resume(List<String> result) {
        System.out.println("Result of getName is " + result);
    }
    @Override public void resumeWithException(Throwable throwable) {
        throwable.printStackTrace();
    }
    @NotNull @Override public CoroutineContext getContext() {
        return Unconfined.INSTANCE;
    }
};

NOTE: The above works only with experimental coroutines. In the final API there's just one resumption method: resumeWith(result: Result<T>) where Result is a discriminated union of the result type and the internal class Failure, which makes it inaccessible from Java.

我们还将创建FileSystem接口的模拟实现:

class MockFs : FileSystem {
    override suspend fun getName(path: Path): List<String> {
        suspendCoroutine<Unit> {
            println("getName suspended")
        }
        println("getName resumed")
        return listOf("usr", "opt")
    }
}

Now we're ready to call it from Java:

Object result = new MockFs().getName(Paths.get(""), myCont);
System.out.println("getName returned " + result);

它会打印

getName suspended
getName returned
kotlin.coroutines.experimental.intrinsics.CoroutineSuspendedMarker@6ce253f1

getName()返回一个特殊的标记对象,表示函数已挂起.一旦函数恢复,它将把它的实际结果传递给我们的回调.

Let us now improve MockFs so we can get access to the continuation:

class MockFs : FileSystem {
    var continuation : Continuation<Unit>? = null

    override suspend fun getName(path: Path): List<String> {
        suspendCoroutine<Unit> {
            continuation = it
            println("getName suspended")
        }
        println("getName resumed")
        return listOf("usr", "opt")
    }
}

Now we'll be able to manually resume the continuation. We can use this code:

MockFs mockFs = new MockFs();
mockFs.getName(Paths.get(""), myCont);
mockFs.getContinuation().resume(Unit.INSTANCE);

这将打印出来

getName suspended
getName resumed
Result of getName is [usr, opt]

In real life a suspendable function will use some mechanism to get itself resumed when the result becomes available. For example, if it's a wrapper around some async API call, it will register a callback. When the async API invokes the callback, it will in turn invoke our continuation. You shouldn't need to manually resume it like we did in our mock code.

Asuspend fun还可以 Select 直接返回其结果.例如,使用这个MockFs代码

class MockFs : FileSystem {
    override suspend fun getName(path: Path) = listOf("usr", "opt") 
}

在Java中,我们只能说

System.out.println(new MockFs().getName(Paths.get(""), myCont));

and it will print [usr, opt]. We could even have passed in an empty implementation of Continuation.

The most demanding case happens when you don't know in advance whether the function will suspend itself or not. In such a case a good approach is to write the following at the call site:

Object retVal = mockFs.getName(Paths.get(""), myCont);
if (retVal != IntrinsicsKt.getCOROUTINE_SUSPENDED()) {
    myCont.resume((List<String>) retVal);
}

否则,必须复制处理函数结果的代码.

Kotlin相关问答推荐

如何在Kotlin中反射多个对象以查找特定类型的属性

用Quarkus和Reactor重写异步过滤器中的数据流

修改器的属性是什么,我需要更改以使角变圆且宽度更小?喷气背包组合

如何使用 Mockk 模拟返回值类的 Kotlin 函数类型?

mutableStateOf 在 Jetpack Compose 中不记住 API 的情况下保持重组后的值

如果不为空,则为 builder 设置一个值 - Kotlin

.indices 在 kotlin 中的含义是什么?

如何使用 Kotlin Coroutines 使 setOnClickListener debounce 1 秒?

如何在 Spring WebFlux 的响应正文中流式传输二进制数据

androidx.core:core-ktx:1.0.0 小部件包丢失

将协同路由调用放在存储库或ViewModel中哪个更好?

Kotlin get字段注释始终为空

Kotlin 的类型具体化使哪些在 Java 或 Scala 中无法实现的成为可能?

Android 与 Kotlin - 如何使用 HttpUrlConnection

添加抽象的私有getter和公共setter的正确方法是什么?

如何使用mockk库模拟android上下文

如何将vararg作为数组传递给Kotlin中的函数?

递归方法调用在 kotlin 中导致 StackOverFlowError 但在 java 中没有

项目不会使用 Kotlin 1.1.3 构建

如何在 spring-boot Web 客户端中发送请求正文?