Every program should grapple with failure. A happy path is only a part of the story. There are many ways to handle errors. The essential toolkit showcases throwing and catching exceptions, passing results, leveraging optionals, aborting, and asserting.
Abort
Sometimes you need to stop your program forcefully on a fatal error.
Abort
When you really need to stop unconditionally:
var theMeaningOfApp: Any = 42
if (theMeaningOfApp !is String) {
kotlin.system.exitProcess(666)
}
Otherwise, rely on exceptions.
Not implemented code can be substituted by TODO() function that will raise a NotImplementedError if invoked.
fun logCrash(e: Throwable) {
TODO()
}
fun showMessage(message: String) {
TODO()
}
Depending on the seriousness, you can raise an Error, Exception, or a RuntimeException, as described in Throwing exceptions.
fun whatsTheMeaningOfApp(mode: String): String {
val meaning = theMeaningOfApp as? String
if (meaning != null) return meaning
when (mode) {
"curious" -> error("Can't understand it")
"pondering" -> throw Exception("Don't know, but you can deal without it")
else -> throw Error("Full breakdown")
}
}
whatsTheMeaningOfApp("any") // Crash
Errors would indicate a fatal error and should abort your program, Exceptions are usually recoverable, so you can display a nice message to the user. But it’s all up to installed handlers ultimately. Both Error and Exception can be caught and silenced.
try {
whatsTheMeaningOfApp("existential")
} catch (e: Throwable) {
// Errors are not usually handled by convention, but can be caught.
// To log the issue, for example.
logCrash(e)
throw e
}
try {
whatsTheMeaningOfApp("pondering")
} catch (e: Exception) {
// Exceptions are more likely to be handled and suggest the possibility.
showMessage("The app is fundamentally broken, sorry")
}