Due blocchi diversi per due scopi diversi
Delphi offre due varianti del blocco di gestione eccezioni, spesso confuse da chi inizia: try...except intercetta un'eccezione e permette di reagire (mostrare un messaggio, registrare un log, tentare un recupero), mentre try...finally garantisce che un blocco di codice venga eseguito comunque, che si sia verificata un'eccezione o meno — tipicamente per rilasciare risorse come file aperti, connessioni al database o oggetti creati dinamicamente. I due blocchi rispondono a domande diverse: "cosa faccio se qualcosa va storto?" per except, "cosa devo comunque eseguire alla fine, in ogni caso?" per finally.
Il pattern più comune: create/try/finally/free
Per qualsiasi oggetto creato dinamicamente con Create, il pattern raccomandato in Delphi è creare l'oggetto prima del blocco try, e liberarlo in un blocco finally subito dopo: Obj := TMyClass.Create; try ... finally Obj.Free; end;. In questo modo, anche se il codice all'interno del try solleva un'eccezione, l'oggetto viene comunque liberato correttamente, evitando memory leak. Creare l'oggetto dentro il blocco try, prima della clausola finally, è un errore diffuso: se il costruttore stesso solleva un'eccezione, il finally tenterebbe comunque di liberare un riferimento non ancora assegnato.
Catturare l'eccezione giusta, non tutte
Un except generico che intercetta Exception (la classe base di tutte le eccezioni) nasconde qualsiasi errore, incluso quelli inattesi che invece dovrebbero interrompere l'esecuzione e segnalare un bug. È preferibile intercettare tipi di eccezione specifici — on E: EConvertError do, on E: EDatabaseError do — gestendo solo i casi che ci si aspetta davvero possano verificarsi, e lasciando propagare (o rilanciando con raise) tutto il resto.
Creare eccezioni personalizzate
Per errori specifici della propria applicazione, è buona pratica derivare una nuova classe da Exception (ad esempio ESaldoInsufficiente = class(Exception)), da sollevare con raise ESaldoInsufficiente.Create('Saldo insufficiente per completare l'operazione'). Questo permette al codice chiamante di distinguere tra un errore di business specifico e un errore generico di sistema, gestendoli in modo diverso quando serve.
L'errore da evitare: except senza except
Un blocco try...except end; vuoto, che intercetta silenziosamente qualsiasi eccezione senza fare nulla, è probabilmente l'errore più pericoloso in assoluto: nasconde ogni problema, rendendo il debug quasi impossibile quando qualcosa smette di funzionare senza un motivo apparente. Se davvero un'eccezione va ignorata (un caso raro), è preferibile farlo esplicitamente e con un commento che ne spieghi il motivo, non per abitudine.