kotlinintermediate

Kotlin Result API Functional Error Handling

Use Kotlin's built-in Result type for functional error handling: runCatching, map, recover, and fold.

kotlin
fun main() {
    // runCatching wraps exceptions in Result
    val result1 = runCatching { "42".toInt() }
    val result2 = runCatching { "abc".toInt() }

    println("Success: ${result1.isSuccess}") // true
    println("Failure: ${result2.isFailure}") // true

    // getOrNull / getOrDefault / getOrElse
    println(result1.getOrNull())       // 42
    println(result2.getOrNull())       // null
    println(result2.getOrDefault(0))   // 0
    println(result2.getOrElse { -1 })  // -1

    // map: transform success value
    val doubled = result1.map { it * 2 }
    println("Doubled: ${doubled.getOrNull()}") // 84

    // mapCatching: transform with possible failure
    val parsed = runCatching { "10" }
        .mapCatching { it.toInt() }
        .mapCatching { 100 / it }
    println("Parsed: ${parsed.getOrNull()}") // 10

    // recover: handle error
    val recovered = result2.recover { 0 }
    println("Recovered: ${recovered.getOrNull()}") // 0

    // fold: handle both cases
    val message = result1.fold(
        onSuccess = { "Value is $it" },
        onFailure = { "Error: ${it.message}" }
    )
    println(message)

    // onSuccess / onFailure: side effects
    result1
        .onSuccess { println("Got: $it") }
        .onFailure { println("Failed: ${it.message}") }

    // Chaining Results
    fun parseAge(input: String): Result<Int> = runCatching {
        val age = input.trim().toInt()
        require(age in 0..150) { "Age out of range" }
        age
    }

    fun categorize(age: Int): String = when {
        age < 13 -> "child"
        age < 20 -> "teenager"
        age < 65 -> "adult"
        else -> "senior"
    }

    listOf("25", "abc", "200", "8").forEach { input ->
        val category = parseAge(input)
            .map { categorize(it) }
            .getOrElse { "invalid (${it.message})" }
        println("$input -> $category")
    }

    // Collecting results from list
    val inputs = listOf("1", "abc", "3", "xyz", "5")
    val results = inputs.map { runCatching { it.toInt() } }
    val successes = results.filter { it.isSuccess }.map { it.getOrThrow() }
    val failures = results.filter { it.isFailure }.map { it.exceptionOrNull()?.message }
    println("Successes: $successes")
    println("Failures: $failures")
}

Use Cases

  • Functional error handling without try-catch
  • Input validation and parsing pipelines
  • Batch processing with error collection

Tags

Related Snippets

Similar patterns you can reuse in the same workflow.