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?
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()
}
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.