runCatching în Kotlin

Rulează un bloc și prinde orice excepție într-un Result; valoarea se scoate cu getOrNull, getOrElse sau getOrThrow.

Sintaxă
inline fun <R> runCatching(block: () -> R): Result<R>
fun getOrNull(): T?
inline fun <R, T : R> Result<T>.getOrElse(onFailure: (Throwable) -> R): R
fun <T> Result<T>.getOrThrow(): T

Ce face runCatching

runCatching { ... } rulează blocul și returnează un Result: Success(valoare) dacă totul a mers bine sau Failure(excepție) dacă blocul a aruncat o excepție. Este un try/catch sub formă de valoare, pe care o poți păstra, transmite și transforma.

Din Result scoți valoarea în trei feluri: getOrNull() dă valoarea sau null la eroare; getOrElse { e -> ... } dă valoarea sau rezultatul blocului, care primește excepția; getOrThrow() dă valoarea sau aruncă din nou excepția. Mai poți verifica isSuccess, isFailure și exceptionOrNull().

Atenție: runCatching prinde orice Throwable, inclusiv erori grave precum OutOfMemoryError. Pentru o singură excepție așteptată, un try/catch pe tipul exact este mai precis.

Parametri

Parametru Descriere
block: () -> R Codul care poate arunca o excepție.
onFailure: (Throwable) -> R La getOrElse: ce valoare se folosește la eroare; primește excepția.

Ce returnează

runCatching: un Result<R>. getOrNull: valoarea sau null. getOrElse: valoarea sau valoarea de rezervă. getOrThrow: valoarea sau aruncă excepția.

Exemple

Exemplul 1: Success și Failure

Primul text se convertește fără probleme; al doilea aruncă NumberFormatException, care ajunge în Result în loc să oprească programul.

fun main() {
    val bun = runCatching { "125".toInt() }
    val rau = runCatching { "12a".toInt() }
    println(bun)
    println(rau)
    println("${bun.isSuccess} ${rau.isFailure}")
    println(rau.exceptionOrNull()?.message)
}

Rezultat

Success(125)
Failure(java.lang.NumberFormatException: For input string: "12a")
true true
For input string: "12a"

Exemplul 2: getOrNull, getOrElse și getOrThrow

Pentru textul greșit, getOrNull dă null, getOrElse dă valoarea de rezervă 0.0, exceptionOrNull arată excepția, iar getOrThrow aruncă excepția mai departe, unde o prindem.

fun main() {
    val texte = listOf("19.99", "gratis")
    for (t in texte) {
        val pret = runCatching { t.toDouble() }
        println("getOrNull: ${pret.getOrNull()}")
        println("getOrElse: ${pret.getOrElse { 0.0 }}")
        println("excepția: ${pret.exceptionOrNull()?.let { it::class.simpleName }}")
        try {
            println("getOrThrow: ${pret.getOrThrow()}")
        } catch (e: NumberFormatException) {
            println("getOrThrow a aruncat: ${e.message}")
        }
    }
}

Rezultat

getOrNull: 19.99
getOrElse: 19.99
excepția: null
getOrThrow: 19.99
getOrNull: null
getOrElse: 0.0
excepția: NumberFormatException
getOrThrow a aruncat: For input string: "gratis"

Greșeli frecvente

  • Folosești runCatching peste tot și ignori rezultatul. Erorile dispar fără urmă; verifică sau afișează excepția.
  • Crezi că getOrElse(0) primește valoarea direct. Primește un bloc: getOrElse { 0 }. Pentru o valoare fixă există și getOrDefault(0).
  • Folosești runCatching în corutine fără grijă: prinde și CancellationException, care ar trebui să oprească corutina.

Comenzi înrudite

  • Result.onSuccess: Rulează o acțiune doar dacă Result a reușit (onSuccess) sau doar dacă a eșuat (onFailure); ambele returnează același Result.
  • Result.map: map transformă valoarea unui Result reușit și lasă eroarea neschimbată; fold dă o valoare finală din ambele cazuri.
  • require: Verifică argumentele unei funcții și aruncă IllegalArgumentException dacă nu sunt bune; requireNotNull cere o valoare diferită de null.
  • String.toInt: Transformă un text în număr întreg; toInt aruncă excepție la text invalid, toIntOrNull returnează null.