web-dev-qa-db-ja.com

KotlinのコルーチンをJavaコードで使用して利用できますか?

私の目標は何ですか?

私の目標は、JavaからKotlinのコルーチンシステムを使用できるようにすることです。実行の途中で一定時間一時停止し、一定時間経過した後、その場所で再開できるようにしたい。 Javaから、次のような非同期の方法で実行の途中で一時停止できるタスクを実行できるようにしたいと思います。

//example 1
someLogic();
pause(3000L); //3 seconds
someMoreLogic();

//example 2
while(true) {
    someContinuedLogic();
    pause(10000L); //10 seconds
}

私の問題は何ですか?

予想どおり、Kotlinからコルーチンを完全に実行できますが、Javaに関しては、コードのJava部分が一時停止せずにブロック全体を一度に実行するため、注意が必要です。一方、Kotlinブロックは正しく1秒、次に4秒一時停止します。

私の質問は何ですか?

JavaのコルーチンのバックボーンとしてKotlinを使用することも可能ですか?もしそうなら、私は何を間違っていますか? 以下に、JavaでKotlinのコルーチンをどのように使用しようとしているのかを示すソースコードを示します。

KtScriptクラス

abstract class KtScript {

    abstract fun execute()

    fun <T> async(block: suspend () -> T): CompletableFuture<T> {
        val future = CompletableFuture<T>()
        block.startCoroutine(completion = object : Continuation<T> {
            override fun resume(value: T) {
                future.complete(value)
            }
            override fun resumeWithException(exception: Throwable) {
                future.completeExceptionally(exception)
            }
        })
        return future
    }

    suspend fun <T> await(f: CompletableFuture<T>): T =
            suspendCoroutine { c: Continuation<T> ->
                f.whenComplete { result, exception ->
                    if (exception == null)
                        c.resume(result)
                    else
                        c.resumeWithException(exception)
                }
            }

    fun pause(ms: Long): CompletableFuture<*> {
        //todo - a better pausing system (this is just temporary!)
        return CompletableFuture.runAsync {
            val currentMs = System.currentTimeMillis()
            while (System.currentTimeMillis() - currentMs < ms) {
                /* do nothing */
            }
        }
    }

}

Kotlin実行コード

fun main(args: Array<String>) {
    ScriptTestKotlin().execute()
}

class ScriptTestKotlin : KtScript() {
    override fun execute() {
        println("Executing Kotlin script from Kotlin...")
        val future = async {
            await(pause(1000L))
            println("   1 second passed...")
            await(pause(4000L))
            println("   5 seconds passed...")
        }
        future.get() //wait for asynchronous task to finish
        println("Finished!")
    }
}

Kotlinの実行結果

Executing Kotlin script from Kotlin...
   1 second passed...
   5 seconds passed...
Finished!

Java実行コード

public class ScriptTestJava extends KtScript {

    public static void main(String[] args) {
        new ScriptTestJava().execute();
    }

    @Override
    public void execute() {
        System.out.println("Executing Kotlin script from Java...");
        CompletableFuture<?> future = async(continuation -> {
            await(pause(1000L), continuation);
            System.out.println("    1 second passed...");
            await(pause(4000L), continuation);
            System.out.println("    5 seconds passed...");
            return continuation;
        });
        try {
            future.get(); //wait for asynchronous task to finish
        } catch(Exception e) {
            e.printStackTrace();
        }
        System.out.println("Finished!");
    }
}

Java実行結果

Executing Kotlin script from Java...
    1 second passed...
    5 seconds passed...
Finished!

^^^残念ながら、Javaでは一時停止はスキップされます。 ^^^

12
Wonderlus

Kotlinコルーチンは、コードへのコンパイラ変換を使用して実装されます。これは、明らかにkotlincによってのみ実行できます。

したがって、いいえ、Javaはコンパイル時の機能であるため、Kotlinのコルーチンメカニズムを使用できません。

18
voddan