try, catch și finally în Dart

Excepții Dart 1.0

try prinde excepțiile din bloc; on alege tipul, catch dă acces la obiect, finally rulează mereu.

Sintaxă
try {
  ...
} on TipExceptie catch (e) {
  ...
} on AltTip {
  ...
} catch (e, stiva) {
  ...
} finally {
  ...
}

Ce face try, catch și finally

Codul care poate arunca o excepție se pune în blocul try. Dacă apare o excepție, Dart sare la prima clauză care o acceptă. on Tip prinde doar excepțiile de acel tip; catch (e) îți dă obiectul excepției; le poți combina: on FormatException catch (e). Un catch (e) fără on prinde orice.

catch (e, s) primește și al doilea parametru, stiva de apeluri (StackTrace), utilă la jurnalizare. Clauzele se verifică de sus în jos, deci pune tipurile specifice înaintea celor generale.

finally rulează întotdeauna la final: când blocul try se termină normal, când s-a prins o excepție și chiar când excepția nu a fost prinsă sau ai ieșit cu return. Acolo se eliberează resursele (fișiere, conexiuni).

Exemple

Exemplul 1: on și catch pe tipuri diferite

int.parse aruncă FormatException pentru text; împărțirea întreagă la zero aruncă UnsupportedError.

int imparte(String a, String b) => int.parse(a) ~/ int.parse(b);

void main() {
  for (final (a, b) in [('100', '4'), ('zece', '2'), ('7', '0')]) {
    try {
      print('$a / $b = ${imparte(a, b)}');
    } on FormatException catch (e) {
      print('Nu este număr: ${e.source}');
    } on UnsupportedError {
      print('Nu se poate împărți la zero.');
    }
  }
}

Rezultat

100 / 4 = 25
Nu este număr: zece
Nu se poate împărți la zero.

Exemplul 2: finally rulează mereu

Mesajul din finally apare și după succes, și după eroare.

void proceseaza(String fisier) {
  print('deschid $fisier');
  try {
    if (fisier.endsWith('.exe')) throw const FormatException('tip de fișier nepermis');
    print('procesez $fisier');
  } on FormatException catch (e) {
    print('eroare: ${e.message}');
  } finally {
    print('închid $fisier');
  }
}

void main() {
  proceseaza('note.csv');
  proceseaza('virus.exe');
}

Rezultat

deschid note.csv
procesez note.csv
închid note.csv
deschid virus.exe
eroare: tip de fișier nepermis
închid virus.exe

Exemplul 3: catch general și stiva de apeluri

catch (e, s) prinde orice; afișăm tipul și primul rând din stivă.

void citesteElement(List<String> lista, int poz) {
  print(lista[poz]);
}

void main() {
  try {
    citesteElement(['Ana', 'Ion'], 5);
  } catch (e, s) {
    print('Prins: ${e.runtimeType}');
    print('Mesaj: $e');
    print('Primul rând din stivă: ${s.toString().split('\n').first}');
  }
}

Rezultat

Prins: RangeError
Mesaj: RangeError (length): Invalid value: Not in inclusive range 0..1: 5
Primul rând din stivă: #0      List.[] (dart:core-patch/growable_array.dart)

Greșeli frecvente

  • catch (e) gol, care ascunde toate erorile: problemele nu mai apar nicăieri. Tratează sau măcar afișează excepția.
  • Clauza generală înaintea celei specifice: catch (e) pus primul prinde tot, iar on FormatException de sub el nu mai rulează niciodată.
  • return în finally: înlocuiește valoarea returnată din try și înghite excepția.

Comenzi înrudite

  • throw: Aruncă o excepție sau o eroare care oprește execuția normală până o prinde un catch.
  • rethrow: Aruncă mai departe excepția prinsă în catch, păstrând stiva de apeluri originală.
  • async și await: async marchează o funcție asincronă (întoarce Future), iar await așteaptă rezultatul unui Future fără să blocheze programul.