2010-08-18 8 views
17

Sono uno studente di informatica quindi non lo so molto.Diversi stili di flusso del programma?

Recentemente stavo parlando con un amico che ha appena ottenuto un lavoro come sviluppatore di software (Java). Mi ha detto che nel suo lavoro c'è un ragazzo che ha davvero esperienza in C++, ma sfortunatamente ogni volta che scrive codice in java, sta usando il try-catch per controllare il flusso del programma. Secondo il mio amico questo è uno stile sbagliato in Java. È vero? Quali sono le differenze (se ce ne sono) nell'usare try-catch (-finalmente in java) tra C++ e Java?

+1

+1 alla risposta di John Weldon. Si noti che uno degli aspetti veramente sgradevoli di una parte dell'ecosistema Java (e che è una specificità Java) è l'uso eccessivo di ** check ** delle eccezioni da parte di alcune API/framework. Fondamentalmente costringendo gli utenti API a controllare il flusso del loro programma catturando l'eccezione senza checkless per cose che non sono affatto eccezionali. Alcune strutture, come Spring, sono progettate correttamente e veramente disapprovano quella terribile pratica. Joshua Bloch nel suo * Java efficace * raccomanda di preferire un "metodo di test dello stato" per lanciare inutilmente (un) le eccezioni controllate in giro. – NoozNooz42

+0

Ciao Grazie per la risposta. "In pratica costringiamo gli utenti API a controllare il flusso del loro programma rilevando un'eccezione senza checkless per cose che non sono affatto eccezionali". Quindi questa è la differenza nel try-catch tra C++/Java? Inoltre, cosa intendi per eccezioni "controllate"? Cheers – Muggen

+1

Vedi http://www.javapractices.com/topic/TopicAction.do?Id=129. Le eccezioni controllate sono essenzialmente un abuso di eccezioni per il controllo del flusso non eccezionale. Sono anche un incubo di manutenzione. –

risposta

28

L'uso di try-catch per controllare il flusso del programma è sbagliato ovunque ... La gestione delle eccezioni è quello che dice: Gestione delle circostanze eccezionali.

Ovviamente per ogni regola ci sono una dozzina di contro-esempi di deviazioni necessarie, ma in generale: non controllare il flusso del programma con eccezioni.

L'utilizzo di eccezioni per il controllo del flusso di un programma si verifica quando si anticipano determinate eccezioni generate in un normale ambiente operativo e si prendono decisioni logiche in base a tali eccezioni.

Ad esempio controllare il flusso del programma in pseudo-codice:

try { 
    write update to file 
} catch (IOException) { 
    write update to alternate file 
} 

In questo caso sarebbe meglio provare effettivamente per il percorso esistenza prima di eseguire ciecamente la scrittura.

ho tolto il permesso di controllare le note perché è un cattivo esempio

Un buon utilizzo di gestione delle eccezioni: (pseudo codice di nuovo)

try { 
    do stuff 
} catch(OutOfMemoryException) { 
    fail gracefully (don't try and do something else to achieve the same result) 
} 
+1

Ciao. Grazie per la risposta. Sarebbe possibile mostrare qualche codice in cui un try-catch controlla il flusso e un caso simile in cui non lo fa? Grazie – Muggen

+2

Questa è una domanda davvero buona @Muggen; Farò un tentativo di aggiornare la mia risposta, ma penso che valga la pena di parlarne. –

+3

@Muggen se hai un file aperto dovresti essere in grado di leggere, ma se questo non è un caso eccezionale. Se un utente prova ad accedere ma inserisce una password non valida questa è una normale condizione di flusso e dovrebbe essere trattata in questo modo, non con try-catch –

-2

La tua domanda è troppo vaga senza codice di esempio. Non c'è finally in C++.

EDIT In generale, non si desidera utilizzare exceptions come mezzo per controllare il flusso. Exceptions devono essere utilizzati solo per casi eccezionali (situazioni impreviste).

+1

In realtà questa risposta inizia ad affrontare l'altra domanda dell'OP: Quali sono le differenze nella gestione delle eccezioni tra java e C++ –

+0

Questa è una buona risposta, +1. – fastcodejava

8

Direi che dal punto di vista dell'architettura del programma lo scopo delle eccezioni è lo stesso in Java e C++. Dovrebbero essere usati per gestire casi eccezionali, non il diretto flusso normale del programma.

L'argomento più comune contro l'utilizzo di eccezioni è che sono lenti. Come la maggior parte degli argomenti basati sulla velocità del codice, oggigiorno è quasi sempre irrilevante, specialmente quando le eccezioni vengono utilizzate correttamente.

+0

Ciao. "... specialmente quando le eccezioni sono usate correttamente.". Come può essere utilizzata un'eccezione in modo improprio? – Muggen

+2

Ogni volta che viene utilizzato per controllare il flusso del programma, piuttosto che gestire casi eccezionali. Ad esempio, se è possibile controllare la lunghezza di una matrice, non utilizzare un'eccezione di indice fuori limite per sapere che si è passati la lunghezza dell'array per l'indice, ma invece è sufficiente che il ciclo for termini nel punto appropriato. – aperkins

+3

In questo caso "they are slow" è una sorta di argomento proxy per "non è quello per cui sono". Alcune persone non si lamentano molto bene del ragionamento simbolico di livello superiore, quindi devi dare loro degli esempi. Quando usi le cose al di fuori della loro gamma di usi previsti, si ottengono problemi (essendo lento per quell'uso che ne è un esempio). Se qualcuno capita di aggiustare la lentezza, tutto non è ancora giusto con il mondo. –

4

mi aspetterei il mondo Java C++ e ad essere in gran parte simili nei loro punti di vista:

  1. controllo del flusso con blocchi try/catch non è immediatamente evidente
  2. è costoso prestazioni-saggio. In pratica, questo potrebbe non essere un problema, ma in molti scenari (ad esempio i loop stretti) ti avrà sicuramente un impatto.
6

Penso che quello che sta dicendo è che sta usando le eccezioni per condizioni non eccezionali come le normali terminazioni del ciclo.Questo è considerato un no-no dai programmatori nella maggior parte delle lingue che forniscono eccezioni, incluso C++.

Il motivo è che le eccezioni tendono a trascinare con sé un bel po 'di informazioni. Su alcune piattaforme, portano l'intero callstack al punto dell'eccezione, allo scopo di visualizzarlo in un messaggio di debug bello. È molto costoso, se tutto quello che vuoi veramente è un salto di controllo incondizionato.

Invece, si dovrebbero usare istruzioni come break, return o anche (in un vero pizzico) goto.

+2

D'altra parte, questo è un "sì-sì" in Python dove ** ogni ciclo for ** viene terminato gestendo un'eccezione StopIteration. ;) – UncleBens

+2

@UncleBens - Grazie mille per aver convalidato la mia sdolcinata. Ho pensato che doveva esserci almeno uno là fuori. :-) –

2

Il blocco try-catch è destinato a fare la stessa cosa in tutte le lingue - le eccezioni sono uno dei molti modi di recupero quando qualcosa va storto. In Java, le seguenti due istruzioni sono identiche:

if(x != null){ 
    //do the normal thing 
} 
else{ 
    //recover from the error 
} 

e

try{ 
    //do the normal thing 
} 
catch(NullPointerException ex){ 
    //recover 
} 

Tuttavia, utilizzando eccezioni è mai buona idea per una serie di motivi:

  • i costi associati con lancio l'eccezione (ovvero la generazione di Throwable in Java)
  • il flusso di controllo non è immediatamente evidente, ad esempio, se una NullPointerException può essere lanciata da più istruzioni nel blocco try, come si può dire che uno gettò nel blocco catch
  • ecc, ecc
+0

Ciao. Grazie per la risposta. "come puoi dire quale ha gettato nel blocco di cattura" è un'altra domanda che ho avuto. Quindi suggerisci che il try-catch dovrebbe essere usato solo in casi particolari o ho capito male? Cheers – Muggen

+0

Fai attenzione quando dici che i costrutti sono identici o equivalenti. Se "// fa la cosa normale" prima fa qualcosa che non usa impropriamente il riferimento 'null', allora il secondo esempio farà del lavoro (possibilmente con effetti collaterali visibili) che non si verificherà nel primo esempio. –

+0

Aspetta, non è "mai" una buona idea ?! Le eccezioni sono ideali per ciò per cui sono state progettate: eccezioni. A differenza dei codici di risultato, non possono essere ignorati e si gonfiano automaticamente fino a quando non trovano il codice che è disposto a gestirli. Mai dire mai, soprattutto per le cose con un uso ben definito. –

3

Il unica scopo di try/catch è il controllo di flusso. Ha lo scopo di permetterci di uscire da qualsiasi loop e persino di superare il chiamante e fino a una funzione di livello superiore.

Tuttavia, è progettato per condizioni eccezionali, come i riferimenti null in uso, il sovraccarico di divisione o l'errore di I/O di file. Si tratta di errori che impediscono al programma di continuare e deve essere gestito da. Generalmente, sono difficili da prevedere o sono molto rari.

Quando si verifica una condizione eccezionale, la cosa migliore da fare è modificare il flusso di controllo in modo che l'eccezione sia lanciata fino in fondo come deve essere al fine di trovare un blocco catch disposto a gestirlo. Qualsiasi metodo nel mezzo viene interrotto e svolto, anche se non ha codice per verificare i risultati.

Quando le persone si lamentano utilizzando try/catch per il controllo del flusso, quello che dovrebbe dire è che non è per il controllo del flusso in condizioni non eccezionali. Se tutto ciò che vuoi fare è uscire da un loop, usa break o return; non lanciare un'eccezione e poi prenderla. Questo non è ciò che le eccezioni sono per, né è ciò per cui sono buoni.

+0

Buona spiegazione @Steven.Non sono sicuro che valesse la mia risposta, ma comunque buono :) –

+0

@John: Hai ottenuto 20 upvotes. le persone a fermarsi e guardare le alternative. –

1

Quello che può mancare è più modi per non eseguire un po 'di codice ... Quindi, piuttosto che (in java)

if (cond1) { 
    some_code(); 
    if (cond2) { 
    some_more_code(); 
    if (condN) { 
     ad_infinitum 
    } 
    } 
} 

Questo può essere 'appiattito' di gettare un po' di spazzatura ...

try { 
    if (!cond1) throw new Throwable(); 
    some_code(); 
    if (!cond2) throw new Throwable(); 
    some_more_code(); 
    if (!condN) throw new Throwable(); 
    ad_infinitum(); 
} catch (Throwable ignore) { } 

Il problema è se una qualche eccezione reale è stata lanciata?Penso che ciò che il vostro collega dovrebbe scrivere se vuole appiattire il rientro è qualcosa di simile:

do { 
    if (!cond1) break; 
    some_code(); 
    if (!cond2) break; 
    some_more_code(); 
    if (!condN) break; 
    ad_infinitum(); 
} while (false); 

Dal do/while esegue sempre siamo in grado di utilizzare la pausa per approssimare un goto (a patto che tutto va per il stesso punto).

Problemi correlati