try, catch și finally în Kotlin

Excepții Kotlin 1.0

try execută cod care poate eșua, catch prinde excepția și o tratează, finally rulează întotdeauna la final.

Sintaxă
try {
    // cod care poate arunca excepții
} catch (e: NumberFormatException) {
    // tratare
} catch (e: Exception) {
    // orice altă excepție
} finally {
    // se execută mereu
}

val x = try { s.toInt() } catch (e: NumberFormatException) { 0 }

Ce face try, catch și finally

Când o operație eșuează (un text care nu e număr, un fișier care lipsește, o împărțire la zero), programul aruncă o excepție. Dacă nimeni nu o prinde, programul se oprește. Codul care poate eșua se pune în try { }, iar după el, unul sau mai multe blocuri catch (e: TipExceptie) { } care tratează eroarea. Se alege primul catch al cărui tip se potrivește, deci tipurile specifice se scriu înaintea celor generale (Exception).

finally { } se execută întotdeauna: după try reușit, după un catch și chiar dacă se iese cu return. Acolo se pun operațiile de curățenie, de exemplu închiderea unei conexiuni. Pentru fișiere, use { } face acest lucru automat.

În Kotlin try este o expresie: val n = try { text.toInt() } catch (e: NumberFormatException) { 0 }. Kotlin nu are excepții verificate („checked”): nu ești obligat să prinzi sau să declari excepțiile, ca în Java.

Ce returnează

Folosit ca expresie: ultima valoare din try sau din catch-ul executat (nu din finally).

Exemple

Exemplul 1: Text care nu este număr

toInt() aruncă NumberFormatException pentru „doi”. Excepția este prinsă și programul continuă.

fun main() {
    for (text in listOf("3", "doi", "5")) {
        try {
            val bucati = text.toInt()
            println("Comand $bucati pizza, total ${bucati * 35} lei")
        } catch (e: NumberFormatException) {
            println("'$text' nu este număr: ${e.message}")
        }
    }
    println("Programul a continuat")
}

Rezultat

Comand 3 pizza, total 105 lei
'doi' nu este număr: For input string: "doi"
Comand 5 pizza, total 175 lei
Programul a continuat

Exemplul 2: try ca expresie și mai multe catch

Primul catch potrivit este ales. Valoarea lui try este pusă direct în variabilă.

fun pretPePersoana(total: String, persoane: Int): String =
    try {
        val suma = total.toInt()
        "${suma / persoane} lei de persoană"
    } catch (e: NumberFormatException) {
        "total invalid"
    } catch (e: ArithmeticException) {
        "împărțire la zero: ${e.message}"
    }

fun main() {
    println(pretPePersoana("240", 4))
    println(pretPePersoana("2x0", 4))
    println(pretPePersoana("240", 0))
}

Rezultat

60 lei de persoană
total invalid
împărțire la zero: / by zero

Exemplul 3: finally se execută mereu

Mesajul din finally apare în toate cele trei cazuri: reușită, eroare prinsă și return din try.

fun proceseaza(comanda: String): String {
    println("Deschid conexiunea pentru '$comanda'")
    try {
        if (comanda.isEmpty()) return "comandă goală"
        val cod = comanda.toInt()
        return "comanda $cod salvată"
    } catch (e: NumberFormatException) {
        return "cod invalid"
    } finally {
        println("Închid conexiunea")
    }
}

fun main() {
    println(proceseaza("1024"))
    println(proceseaza("abc"))
    println(proceseaza(""))
}

Rezultat

Deschid conexiunea pentru '1024'
Închid conexiunea
comanda 1024 salvată
Deschid conexiunea pentru 'abc'
Închid conexiunea
cod invalid
Deschid conexiunea pentru ''
Închid conexiunea
comandă goală

Greșeli frecvente

  • catch (e: Exception) pus primul: prinde tot, iar catch-urile specifice de după nu mai ajung să ruleze niciodată.
  • Un catch gol, care ascunde eroarea: programul continuă cu date greșite și problema e greu de găsit. Măcar afișează sau înregistrează mesajul.
  • Folosirea excepțiilor pentru cazuri normale: pentru texte care pot să nu fie numere, toIntOrNull() este mai simplu decât try/catch.

Comenzi înrudite

  • throw: Aruncă o excepție: oprește execuția normală și transmite eroarea până la primul catch potrivit.
  • null și null safety (?. ?: !!): null înseamnă „nicio valoare”. Kotlin separă tipurile care acceptă null (String?) și oferă ?., ?: și !! pentru ele.
  • return: Încheie funcția curentă și întoarce o valoare apelantului; cu etichetă (return@forEach) iese doar din lambda.