In Java, a cosa servono le eccezioni controllate? [chiuso]

14

Le eccezioni controllate di Java hanno avuto una brutta stampa nel corso degli anni. Un segno rivelatore è che è letteralmente l'unica lingua al mondo ad averli (nemmeno altre lingue JVM come Groovy e Scala). Anche le librerie Java prominenti come Spring e Hibernate non le usano.

Personalmente ho trovato un uso per loro ( in business logic tra livelli), ma per il resto sono carina eccezioni anti-controllo.

Ci sono altri usi che non realizzo?

    
posta Brad Cupit 16.11.2010 - 02:42
fonte

8 risposte

22

Prima di tutto, come ogni altro paradigma di programmazione, devi farlo correttamente perché funzioni bene.

Per me il vantaggio delle eccezioni controllate è che gli autori della libreria di runtime Java GIÀ hanno deciso per me quali problemi comuni potrei ragionevolmente aspettarci di essere in grado di gestire alla chiamata (in contrasto con un blocco catch-print-die di livello superiore) e considera il prima possibile come gestire questi problemi.

Mi piacciono le eccezioni controllate perché rendono il mio codice più solido costringendomi a pensare al ripristino degli errori il prima possibile.

Per essere più precisi, per me questo rende il mio codice più robusto in quanto mi costringe a considerare strani casi d'angolo molto presto nel processo invece di dire "Oops, il mio codice non gestisce se il file non esiste ancora "in base a un errore di produzione, che quindi devi rielaborare il codice da gestire. Aggiungendo la gestione degli errori al codice esistente può essere un compito non banale - e quindi costoso - quando si raggiunge la manutenzione anziché farlo semplicemente dall'inizio.

Potrebbe essere che il file mancante è una cosa fatale e dovrebbe causare il crash del programma in fiamme, ma poi tu prendere questa decisione con

} catch (FileNotFoundException e) {
  throw new RuntimeException("Important file not present", e);
}

Questo mostra anche un effetto collaterale molto importante. Se avvolgi un'eccezione, puoi aggiungere una spiegazione che va nello stack-trace ! Questo è estremamente potente perché puoi aggiungere informazioni su ad es. il nome del file che mancava, oi parametri passati a questo metodo o altre informazioni diagnostiche e quell'informazione è presente proprio nello stack trace che spesso è la singola cosa che si ottiene quando un programma ha si è schiantato.

Le persone potrebbero dire "possiamo solo eseguirlo nel debugger per riprodurlo", ma ho riscontrato che molto frequentemente errori di produzione non possono essere riprodotti più tardi, e non possiamo eseguire i debugger in produzione ad eccezione di molto casi difficili in cui essenzialmente è in gioco il tuo lavoro.

Più informazioni nella traccia dello stack, meglio è. Le eccezioni controllate mi aiutano a ottenere le informazioni lì dentro e in anticipo.

EDIT: questo vale anche per i progettisti di librerie. Una libreria che uso ogni giorno contiene molte, molte eccezioni controllate che potrebbero essere state progettate molto meglio rendendole meno noiose da usare.

    
risposta data 16.11.2010 - 06:13
fonte
11

Hai due buone risposte che spiegano quali eccezioni controllate sono diventate nella pratica. (+1 a entrambi). Ma sarebbe anche utile esaminare in teoria il motivo per cui erano stati concepiti, perché l'intenzione è effettivamente utile.

Le eccezioni controllate sono in realtà destinate a rendere la lingua più sicura. Considera un metodo semplice come la moltiplicazione dei numeri interi. Si potrebbe pensare che il tipo di risultato di questo metodo sarebbe un intero, ma, in senso stretto, il risultato è un numero intero o un'eccezione di overflow. Considerando il risultato intero di per sé come il tipo di ritorno del metodo non esprime l'intero intervallo della funzione.

Visto in questa luce, non è proprio vero che le eccezioni controllate non hanno trovato la loro strada in altre lingue. Non hanno appena preso la forma usata da Java. Nelle applicazioni Haskell, è comune utilizzare tipi di dati algebrici per distinguere tra completamento riuscito e non riuscito della funzione. Sebbene questa non sia un'eccezione, di per sé, l'intenzione è molto simile a un'eccezione controllata; si tratta di un'API progettata per forzare l'utente dell'API a gestire sia l'esito positivo nel caso non riuscito, ad esempio:

data Foo a =
     Success a
   | DidNotWorkBecauseOfA
   | DidNotWorkBecauseOfB

Questo dice al programmatore che la funzione ha altri due risultati possibili oltre al successo.

    
risposta data 16.11.2010 - 03:34
fonte
11

IMO, le eccezioni controllate sono un'implementazione imperfetta di ciò che potrebbe essere stato un'idea decente (in circostanze completamente diverse - ma in realtà non è nemmeno una buona idea nella circostanza attuale).

La buona idea è che sarebbe bello fare in modo che il compilatore verifichi che tutte le eccezioni che un programma ha un potenziale di lancio saranno catturate. L'implementazione imperfetta è che, per fare ciò, Java ti obbliga a gestire l'eccezione direttamente in qualsiasi classe invochi qualsiasi cosa dichiarata per generare un'eccezione controllata. Una delle idee più basilari (e vantaggi) della gestione delle eccezioni è che, in caso di errore, consente strati intermedi di codice che non hanno nulla a che fare con un particolare errore, per ignorare completamente la sua stessa esistenza. Le eccezioni controllate (come implementate in Java) non lo consentono, distruggendo quindi un vantaggio maggiore (il principale?) Della gestione delle eccezioni con cui iniziare.

In teoria, avrebbero potuto rendere utili le eccezioni controllate applicandole solo su una base di programma - cioè, mentre "costruivano" il programma, costruisci un albero di tutti i percorsi di controllo nel programma. Vari nodi nell'albero verranno annotati con 1) eccezioni che possono generare e 2) eccezioni che possono catturare. Per assicurare che il programma fosse corretto, dovresti quindi camminare sull'albero, verificando che tutte le eccezioni lanciate a qualsiasi livello nell'albero siano state rilevate a un livello più alto nell'albero.

Il motivo per cui non l'ho fatto (suppongo, comunque) è che farlo sarebbe terribilmente difficile - anzi, dubito che qualcuno abbia scritto un sistema di compilazione in grado di farlo per tutto tranne i linguaggi / sistemi estremamente semplici (confinanti con il "giocattolo"). Per Java, cose come il caricamento dinamico delle classi lo rendono ancora più difficile rispetto a molti altri casi. Peggio ancora, (a differenza di qualcosa come C) Java non è (almeno normalmente) compilato staticamente / collegato a un eseguibile. Ciò significa che nulla nel sistema ha realmente la consapevolezza globale di provare a fare questo tipo di applicazione finché l'utente non inizia effettivamente a caricare il programma per eseguirlo.

L'attuazione a quel punto non è pratica per un paio di motivi. Prima di tutto, anche nel migliore dei casi si potrebbero estendere i tempi di avvio, che sono già una delle lamentele più grandi e comuni su Java. In secondo luogo, per fare molto bene, è davvero necessario rilevare il problema abbastanza presto da consentire a un programmatore di risolverlo. Quando l'utente sta caricando il programma, è troppo tardi per fare molto bene - le tue uniche scelte a quel punto sono di ignorare il problema, o rifiutare di caricare / eseguire il programma a tutti, nella remota possibilità che lì potrebbe essere un'eccezione che non è stata rilevata.

Così come sono, le eccezioni controllate sono peggio che inutili, ma i progetti alternativi per le eccezioni controllate sono anche peggio. Mentre l'idea di base per le eccezioni controllate sembra buona, non è molto buona, e sembra essere un particolarmente inadatto per Java. Per qualcosa come C ++, che di solito è compilato / collegato ad un eseguibile completo con niente di simile al caricamento della reflection / dynamic class, ci sarebbe un po 'più di possibilità (anche se, francamente, anche applicandoli correttamente senza lo stesso tipo di disordine loro attualmente la causa in Java sarebbe probabilmente ancora al di là dell'attuale stato dell'arte).

    
risposta data 16.11.2010 - 05:33
fonte
10

Sono davvero utili per i programmatori fastidiosi e per incoraggiare la deglutizione delle eccezioni. La metà del punto delle eccezioni è che hai un modo predefinito per gestire gli errori e non devi pensare a propagare esplicitamente le condizioni di errore che non puoi gestire. (L'impostazione predefinita è che se non si gestisce l'errore da nessuna parte nel codice, si è effettivamente affermato che non può accadere, e se si sbaglia si lascia un'uscita sana e una traccia dello stack.) Sconfitta delle eccezioni controllate Questo. Sentono molto come dover propagare esplicitamente gli errori in C.

    
risposta data 16.11.2010 - 02:47
fonte
5

Penso sia corretto affermare che le eccezioni controllate erano un po 'un esperimento fallito. Dove hanno sbagliato è che hanno rotto la stratificazione:

  • Il modulo A potrebbe essere costruito sopra il modulo B, dove
  • Il modulo B potrebbe essere costruito sopra il modulo C.
  • Il modulo C potrebbe sapere come identificare un errore e
  • Il modulo A potrebbe sapere come gestire l'errore.

La bella separazione degli interessati è rotta, perché ora la conoscenza degli errori che potevano essere limitati ad A e C devono ora essere dispersi su B.

C'è una bella discussione di eccezioni controllate su Wikipedia.

E Bruce Eckel ha anche un bel articolo . Ecco una citazione:

[T]he more random rules you pile onto the programmer, rules that have nothing to do with solving the problem at hand, the slower the programmer can produce. And this does not appear to be a linear factor, but an exponential one

Credo che per il caso del C ++, se tutti i metodi hanno la clausola di specificazione throws , allora si possono avere delle belle ottimizzazioni. Non credo che Java possa avere comunque questi vantaggi, perché RuntimeExceptions non viene controllato. Un moderno JIT dovrebbe essere in grado di ottimizzare il codice in ogni caso.

Una delle funzionalità più interessanti di AspectJ è l'eccezionalità: è possibile trasformare le eccezioni controllate in eccezioni non controllate, in particolare per migliorare il layering.

Forse è ironico che Java abbia affrontato tutti questi problemi, quando invece avrebbe potuto verificare null , che potrebbe sono stati molto più preziosi .

    
risposta data 16.11.2010 - 03:07
fonte
5

Adoro le eccezioni.

Tuttavia, sono costantemente confuso dal loro uso mancato.

  1. Non usarli per la gestione del flusso. Non vuoi il codice che cerca di fare qualcosa e usa un'eccezione come trigger per fare qualcos'altro, invece, perché le eccezioni sono oggetti che devono essere creati e usano la memoria, ecc. Ecc. Solo perché non ti si può prendere la briga di scrivere qualcosa tipo di if () controlla prima di effettuare la chiamata. È solo pigro e dà alla gloriosa eccezione un brutto nome.

  2. Non ingerirli. Mai. Sotto ogni circostanza. Come minimo, si inserisce qualcosa nel file di registro per indicare che si è verificata un'eccezione. Cercando di rintracciare il codice che ingoia le eccezioni è un incubo. Ancora una volta, maledire i tuoi sostenitori delle eccezioni per screditare la potente Exception!

  3. Tratta le eccezioni con il tuo cappello OO. Crea i tuoi oggetti Exception con gerarchie significative. Livelli mano nella mano la logica aziendale e le eccezioni. Scoprivo che se avessi iniziato su una nuova area di un sistema avrei trovato la necessità di sottoclasse Exception entro mezz'ora di codifica, quindi in questi giorni comincio a scrivere le classi Exception.

  4. Se stai scrivendo bit di codice "frameworky", assicurati che tutte le tue interfacce iniziali siano scritte per lanciare le tue nuove eccezioni dove appropriato ... e assicurati che i tuoi coder abbiano un codice di esempio intorno al luogo cosa fare quando il loro codice genera IOException ma l'interfaccia a cui stanno scrivendo vuole lanciare una 'SegnalazioneEsclusioneApplicazione'.

Una volta che hai capito come far funzionare le eccezioni per te non guarderai mai indietro.

    
risposta data 18.11.2010 - 16:58
fonte
4

Le eccezioni controllate sono anche in ADA.

(Avvertenza, questo post contiene credenze strongmente radicate che potresti trovare di fronte.)

Ai programmatori non piacciono e si lamentano, o scrivono codice di deglutizione delle eccezioni.

Esistono eccezioni controllate perché le cose non solo non riescono a funzionare, puoi fare un'analisi degli errori in modalità / effetti e determinarlo in anticipo.

Le letture dei file possono fallire. Le chiamate RPC possono fallire. L'IO di rete può fallire. I dati possono essere formattati in modo errato se analizzati.

Il "percorso felice" per il codice è facile.

Conoscevo un ragazzo all'Università che poteva scrivere un ottimo codice "percorso felice". Nessuno dei casi limite ha mai funzionato. In questi giorni fa Python per una società open source. Nuff ha detto.

Se non vuoi gestire eccezioni controllate, quello che stai dicendo è

While I'm writing this code, I don't want to consider obvious failure modes.

The User will just have to like the program crashing or doing weird things.

But that's okay with me because 

I'm so much more important than the people who will have to use the software

in the real, messy, error-prone world.

After all, I write the code once, you use it all day long.

Quindi le eccezioni controllate non saranno apprezzate dai programmatori, perché significa più lavoro.

Ovviamente, altre persone avrebbero voluto che il lavoro fosse svolto.

Potrebbero aver voluto la risposta giusta anche se il file server non funziona / la penna USB muore.

È strano credere nella comunità di programmazione che dovresti usare un linguaggio di programmazione che ti semplifica la vita, che ti diverte quando il tuo compito è scrivere software. Il tuo lavoro sta risolvendo il problema di qualcuno, non lasciandoti coinvolgere nell'improvvisazione programmatica del jazz.

Se sei un programmatore amatoriale (non programmando per soldi), sentiti libero di programmare in C # o in un'altra lingua senza eccezioni controllate. Diamine, ritaglia l'uomo medio e programma in Logo. Puoi disegnare graziosi motivi sul pavimento con la tartaruga.

    
risposta data 16.11.2010 - 03:46
fonte
4

Le eccezioni controllate dovrebbero aver incoraggiato le persone a gestire gli errori vicini alla fonte. Più lontano dalla sorgente, più funzioni sono terminate durante l'esecuzione e più è probabile che il sistema abbia inserito uno stato incoerente. Inoltre, è più probabile che tu rilevi per errore l'eccezione sbagliata.

Purtroppo, le persone hanno avuto la tendenza a ignorare le eccezioni o ad aggiungere specifiche di lancio sempre maggiori. Entrambi mancano il punto di ciò che le eccezioni controllate dovrebbero incoraggiare. Sono come trasformare il codice procedurale per utilizzare molte funzioni di Getter e Setter che lo rendono apparentemente OO.

Essenzialmente, le eccezioni controllate stanno tentando di dimostrare un certo grado di correttezza nel codice. È praticamente la stessa idea della tipizzazione statica, in quanto tenta di dimostrare che certe cose sono corrette prima che il codice venga eseguito. Il problema è che tutta questa prova extra richiede uno sforzo e lo sforzo è utile?

    
risposta data 16.11.2010 - 05:12
fonte

Leggi altre domande sui tag