Kotlin, Callable and ExecutorService

I’ve recently written about using Callable in Groovy, but how does it look like in kotlin?Callable instance as separete class First, let’s create class which implements Callable interface:class MyJob : Callable<Int> { override fun call() = 42}…

I’ve recently written about using Callable in Groovy, but how does it look like in kotlin?

Callable instance as separete class

First, let’s create class which implements Callable interface:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
class MyJob : Callable {
override fun call() = 42
}
class MyJob : Callable { override fun call() = 42 }
class MyJob : Callable {
    override fun call() = 42
}

Now we could pass instance of this class to executorService:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
fun callableAsClassInstance() = executorService.submit(MyJob()).get()
fun callableAsClassInstance() = executorService.submit(MyJob()).get()
fun callableAsClassInstance() = executorService.submit(MyJob()).get()

When we run it, as we expect, it returns 42. (Tests are written in groovy, not in kotlin).

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
def 'should submit callable as class instance from kotlin'() {
expect:
callableExample.callableAsClassInstance() == 42
}
def 'should submit callable as class instance from kotlin'() { expect: callableExample.callableAsClassInstance() == 42 }
def 'should submit callable as class instance from kotlin'() {
    expect:
        callableExample.callableAsClassInstance() == 42
}

Casting to Callable

If we create map with string “call” to closure or just closure and try to cast to Callable, we always obtain CastClassException:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
fun callableAsMap() = executorService.submit(mapOf("call" to { 42 }) as Callable).get()
fun callableAsClosure() = executorService.submit({ 42 } as Callable).get()
fun callableAsMap() = executorService.submit(mapOf("call" to { 42 }) as Callable).get() fun callableAsClosure() = executorService.submit({ 42 } as Callable).get()
fun callableAsMap() = executorService.submit(mapOf("call" to { 42 }) as Callable).get()

fun callableAsClosure() = executorService.submit({ 42 } as Callable).get()
Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
def 'should submit callable as closure from kotlin'() {
when:
callableExample.callableAsClosure() == 42
then:
thrown(ClassCastException)
}
def 'should submit callable as map from kotlin'() {
when:
callableExample.callableAsMap() == 42
then:
thrown(ClassCastException)
}
def 'should submit callable as closure from kotlin'() { when: callableExample.callableAsClosure() == 42 then: thrown(ClassCastException) } def 'should submit callable as map from kotlin'() { when: callableExample.callableAsMap() == 42 then: thrown(ClassCastException) }
def 'should submit callable as closure from kotlin'() {
    when:
        callableExample.callableAsClosure() == 42
    then:
        thrown(ClassCastException)
}

def 'should submit callable as map from kotlin'() {
    when:
        callableExample.callableAsMap() == 42
    then:
        thrown(ClassCastException)
}

It does not work as in groovy…

Pass instance method

So maybe passing an instance method which produces value will work?

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
private fun callMe() = 42
fun callableAsPassedFunction(): Int? {
return executorService.submit(::callMe).get()
}
private fun callMe() = 42 fun callableAsPassedFunction(): Int? { return executorService.submit(::callMe).get() }
private fun callMe() = 42

fun callableAsPassedFunction(): Int? {
    return executorService.submit(::callMe).get()
}

It does not even compile. Why? It moans that there is no submit method which could be called with such argument…

But, what interesting, if we create a value to which we assign closure and pass it to submit method then everything is ok and get returns 42.

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
private val callMe = { 42 }
fun callableAsPassedLocalFunction(): Int? {
return executorService.submit(callMe).get()
}
private val callMe = { 42 } fun callableAsPassedLocalFunction(): Int? { return executorService.submit(callMe).get() }
private val callMe = { 42 }

fun callableAsPassedLocalFunction(): Int? {
    return executorService.submit(callMe).get()
}

Inline implementation

Of course, there is also an option to create Callable inline:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
fun callableAsInlineImplementation() = executorService.submit(Callable { 42 }).get()
fun callableAsInlineImplementation() = executorService.submit(Callable { 42 }).get()
fun callableAsInlineImplementation() = executorService.submit(Callable { 42 }).get()

And this is IHMO the best and the most comfortable way to create Callable in kotlin, because its syntax is much nicer than in java or groovy.

Source code is available here.

You May Also Like