Converting Thread/Runnable implementation from Java to Kotlin

Craig Otis :

I have an existing Java class ThreadUtils with a method every that looks like:

public class ThreadUtil {

    public static Thread every(int seconds, Runnable r) {
        Thread t = new Thread(() -> {
            while(true) {
                r.run();
                try {
                    Thread.sleep(1000 * seconds);
                } catch (InterruptedException e) {
                    return;
                }
            }
        });
        t.start();
        return t;
    }
}

And I'm trying to convert it to Kotlin. I'm a bit hung up on the Runnable closure. This fails with a bad return:

fun every(seconds: Int, r: Runnable): Thread {
    val t = Thread({
        while (true) {
            r.run()
            try {
                Thread.sleep((1000 * seconds).toLong())
            } catch (e: InterruptedException) {
                return // ERROR: This function must return a value of type Thread
            }
        }
    })
    t.start()
    return t
}

I also tried pulling the Runnable out just to help myself separate things, but this also fails the same way:

fun every(seconds: Int, r: Runnable): Thread {
    val internalRunnable = Runnable {
        while (true) {
            r.run()
            try {
                Thread.sleep((1000 * seconds).toLong())
            } catch (e: InterruptedException) {
                return // ERROR: This function must return a value of type Thread
            }
        }
    }
    val t = Thread(internalRunnable)
    t.start()
    return t
}

How can I implement a @FunctionalInterface or similar-style closure/lambda that doesn't try to return from the function in which it's being defined?

hotkey :

In Kotlin, return statements inside lambdas work differently from those in Java. If you write just return, it means return from the innermost function declared with keyword fun, and it ignores lambdas -- in your code, it means 'return from every'.

To return from a lambda, use qualified return@label-- in your case, it's return@Thread (and return@Runnable for the second example), like in this simplified snippet:

for (i in 1..4) {
    Thread { 
        if (i % 2 == 0)
            return@Thread
        println("Thread $i")
    }.run()
}

(runnable demo of this code)

Also, there is a thread { ... } function in kotlin-stdlib that you might find useful (and, similarly, the return statement for its lambda is return@thread).

You can find a more detailed explanation in the language reference and in this answer.

Guess you like

Origin http://10.200.1.11:23101/article/api/json?id=445455&siteId=1