When your objective is to start a coroutine that doesn't return a result, you should use launch(). It's designed for fire-and-forget scenarios where you only want to be notified if the computation fails, and it still provides you with a function to cancel it if needed. Consider this example:
fun main(args: Array<String>) = runBlocking {
val task = launch {
doSomething()
}
task.join()
println("completed")
}
Here, doSomething() throws an exception:
fun doSomething() {
throw UnsupportedOperationException("Can't do")
}
The exception will be printed to the stack as expected, but notice that the execution was not interrupted and the application finished the execution of main():
As we will see in chapter 3, Life Cycle and Error Handling, the default behavior for uncaught exceptions is defined per platform, but can be overwritten.