A mio parere, le eccezioni sono uno strumento essenziale per rilevare errori di codice in fase di esecuzione. Sia nei test che nella produzione. Rendi i loro messaggi abbastanza dettagliati così in combinazione con una traccia dello stack puoi capire cosa è successo da un log.
Le eccezioni sono principalmente uno strumento di sviluppo e un modo per ottenere rapporti di errore ragionevoli dalla produzione in casi imprevisti.
A prescindere dalla separazione delle preoccupazioni (percorso felice con solo errori attesi vs. caduta fino a raggiungere qualche gestore generico per errori imprevisti) essendo una buona cosa, rendendo il tuo codice più leggibile e mantenibile, è infatti impossibile preparare il codice per tutti i possibili casi imprevisti, anche ingigantendoli con codice di gestione degli errori per completare l'illeggibilità.
Questo è in realtà il significato di "inaspettato".
Btw., cosa è previsto e cosa no è una decisione che può essere presa solo nel sito di chiamata. Ecco perché le eccezioni controllate in Java non hanno funzionato: la decisione è presa al momento dello sviluppo di un'API, quando non è affatto chiaro cosa è previsto o inaspettato.
Semplice esempio: l'API di una mappa hash può avere due metodi:
Value get(Key)
e
Option<Value> getOption(key)
il primo lancio di un'eccezione se non trovato, quest'ultimo che ti dà un valore opzionale. In alcuni casi, quest'ultimo ha più senso, ma in altri il tuo codice deve aspettarsi che ci sia un valore per una determinata chiave, quindi se non ce n'è uno, questo è un errore che questo codice non può correggere perché un l'ipotesi è fallita. In questo caso è in realtà il comportamento desiderato a cadere fuori dal percorso del codice e verso il basso per alcuni gestori generici nel caso in cui la chiamata fallisce.
Il codice non dovrebbe mai provare a gestire ipotesi di base fallite.
Tranne controllandoli e lanciando eccezioni ben leggibili, naturalmente.
Lanciare le eccezioni non è malvagio, ma catturarle potrebbe essere. Non cercare di correggere errori imprevisti. Cattura le eccezioni in alcuni punti in cui desideri continuare un ciclo o un'operazione, registrali, magari segnala un errore sconosciuto, e il gioco è fatto.
I blocchi di cattura dappertutto sono una pessima idea.
Progetta le tue API in modo che sia facile esprimere la tua intenzione, ovvero dichiarare se ti aspetti un determinato caso, come la chiave non trovata o meno. Gli utenti della tua API possono quindi scegliere la chiamata di lancio solo per casi realmente imprevisti.
Suppongo che la ragione per cui le persone si risentono delle eccezioni e spingono troppo lontano omettendo questo strumento cruciale per l'automazione della gestione degli errori e una migliore separazione delle preoccupazioni dalle nuove lingue sono esperienze negative.
Questo e alcuni fraintendimenti su ciò per cui sono effettivamente utili.
Simularli eseguendo TUTTO attraverso il binding monadico rende il tuo codice meno leggibile e manutenibile, e finisci senza una traccia stack, il che rende questo approccio WAY peggio.
La gestione degli errori di stile funzionale è ottima per i casi di errore previsti.
Lascia che la gestione delle eccezioni si occupi automaticamente di tutto il resto, ecco a cosa serve:)