Perché molti programmatori sono passati a utilizzare la gestione delle eccezioni per l'input o l'output? [chiuso]

5

Perché molti programmatori sono passati a utilizzare la gestione delle eccezioni per l'input o l'output? Per questi programmatori, qual è la motivazione alla base di questa decisione?

    
posta Damon Walker 23.04.2015 - 03:41
fonte

7 risposte

18

Poiché input e output non sono affidabili.

Le eccezioni sono, in parte, un riconoscimento che ci saranno condizioni che il software non può ragionevolmente recuperare da.

  1. Fine prematura della fine della riga, errore di sintassi o qualsiasi numero di condizioni di errore di convalida,
  2. Gli input sono troppo lunghi o grandi per essere ragionevolmente accomodanti,
  3. La tastiera viene scollegata,
  4. Il disco rigido esaurisce lo spazio, ecc.

Le eccezioni sono il modo in cui il programmatore dice "Non posso continuare nelle condizioni attuali". In sostanza, quando si lancia un'eccezione, si arrende e si chiede un ripensamento.

Puoi farlo senza uscire con garbo dalla subroutine di input / output o anche preoccuparti della gestione della memoria, perché l'eliminazione ordinata degli oggetti rilevanti è già incorporata nel meccanismo di gestione delle eccezioni.

Puoi controllare dove nel codice viene gestita l'eccezione senza elaborate strutture if , meccanismi di stato complessi o tracciamento della struttura delle chiamate.

    
risposta data 23.04.2015 - 03:58
fonte
10

Perché le eccezioni (al contrario dei valori di ritorno del codice di errore) non possono essere ignorate.

Il codice tipico per le chiamate i / o prima delle eccezioni, di solito è stato scritto in termini di printf / scanf / gets / puts.

Queste funzioni restituiscono valori che consentono allo sviluppatore di verificare la presenza di errori, ma ciò non è banale.

La maggior parte degli sviluppatori, sapendo che la gestione degli errori non è banale, è semplicemente omessa; Tendono a pensare che una tipica chiamata fscanf dovrebbe apparire come questa:

int a;
FILE *f = /* ... */;
fscanf(f, "%d", &a);

quando dovrebbe probabilmente assomigliare a questo:

switch(fscanf(f, "%d", &a))
{
case EOF:
    // todo: handle EOF case
    break;
case 0:
    puts("could not read 'a'");
    break;
case 1:
    // handle success case
    break;
}

Questo codice può (a un punto) essere estratto in una funzione, parametrizzata e (probabilmente) nascosta all'interno di un wrapper su scanf, o una macro (entrambe con i lati negativi).

Se non lo scrivi, la tua applicazione semplicemente non gestisce gli errori. D'altra parte, le eccezioni ti danno più utili informazioni di errore, propagano naturalmente lo stack delle chiamate e non possono essere ignorate (se lo fai, loro fermeranno la tua applicazione).

    
risposta data 23.04.2015 - 10:04
fonte
1

Perché è un codice più leggibile.

Ad esempio (adoro gli esempi):

function myFunc(someInput:String) : OutputType
  if firstErrorCondition(someInput)
    throw new FirstConditionException
  if secondErrorCondition(someInput)
    throw new SecondConditionException
  if thirdErrorCondition(someInput)
    throw new ThirdConditionException
  // do some other fancy stuff and return value eventually

Cosa succede se qui restituiremo un valore invece di generare eccezioni? Fammi vedere:

function myFunc(someInput:String) : OutputType
  if firstErrorCondition(someInput)
    return -1
  if secondErrorCondition(someInput)
    return -2
  if thirdErrorCondition(someInput)
    return -3
  // do some other fancy stuff and return value eventually

Va bene, va ancora bene. Ma come apparirà il codice dei clienti?

OutputType result = myFunc(someInput)

Questa è una parte comune di questo. Eccezioni:

try {
  OutputType result = myFunc(someInput)
  //other operations
} catch (FirstErrorCondition e) {
  //do some exception handling
} catch (SecondErrorCondition e) {
  //do some magic
} catch (ThirdErrorCondition e) {
  //or just inform user that is a problem
} finally {
  //close everything and clean up after some doing
}

Come sviluppatore regolare posso vedere quale codice è responsabile per ogni parte di errore / eccezione.

OutputType result = myFunc(someInput)
switch(result) {
  case -1:
    //meh meh
  case -2:
    //meh meh
  case -3:
    //meh meh
  default:
    //and here we have a REGULAR code
}

Altro vantaggio delle eccezioni: può essere omesso nel codice client ma genererà un'eccezione alla fine quando si verifica un problema . Non sarà un codice silient, buggy e illeggibile.

    
risposta data 23.04.2015 - 14:12
fonte
1

Sono d'accordo con la risposta rimanente su un dato di fatto: quel "ritorno eccezionale" avviene e deve essere gestito.

Ma la ragione per cui esistono eccezioni non è che esistono rendimenti eccezionali. È possibile avere "valori di ritorno" per ciascuno dei possibili stati di errore, proprio come fa C. Il motivo per cui le eccezioni sono preferibili alla gestione degli errori di tipo C è che è estremamente raro che l'errore di una funzione venga gestito nel chiamante immediato. È molto più comune che lo stato di errore faccia esplodere lo stack fino a quando non viene posizionato dove può essere ragionevolmente gestito. Inoltre, un singolo codice di "gestione" gestirà chiamate di metodi differenti.

Se si utilizza la gestione degli errori di tipo C, è necessario creare una quantità estesa di codice per eseguire il bubbling e l'aggregazione degli errori fino al codice del gestore. Ciò richiede disciplina e rigore e complica drasticamente i valori di ritorno dai metodi, in cui ogni possibile rendimento eccezionale deve avere il proprio valore). Le eccezioni e le infrastrutture intorno a loro semplicemente fanno tutto questo per te. E mentre sono d'accordo, anche la gestione delle eccezioni ha bisogno di un certo livello di disciplina e rigore, ne ha bisogno molto meno.

    
risposta data 23.04.2015 - 15:03
fonte
0

Ricorda per prima cosa stai risolvendo i problemi. Immagina una soluzione semplice, aggiungendo due numeri. Dovresti fare quanto segue.

  1. Identifica prima il percorso positivo in un test. Vale a dire. dato 2, 2 restituisce 4, dato 1,2 ritorno 3 e così via.
  2. Scrivi il codice per superare il test.
  3. Scopri i modi per rompere le cose. Ie Given 1 raise exception Non abbastanza args, Given A, 3 raise exception err type arg.

Questo è l'approccio che prendo sempre. È molto TDD ma funziona per me e devo dire che lo trovo più veloce di qualsiasi altro approccio. Le eccezioni sono pulite. E in un linguaggio come Python non ci sarebbe la codifica necessaria per aumentarne la maggior parte .. 'a' + 2 solleva un'eccezione gratis: -)

    
risposta data 23.04.2015 - 11:46
fonte
-1

Trovo che le eccezioni siano più pulite per lo stile del codice dato che posso avvolgere il codice e gestire eventuali errori in una posizione specifica (il blocco catch), anziché copiare il mio codice con un sacco di istruzioni if ( if (result == -1) ), per controlla le condizioni di errore.

    
risposta data 23.04.2015 - 07:53
fonte
-4

Behavioral Economics n. 101: perché è il modo più semplice.

Le eccezioni sono, in parte, un riconoscimento che la gestione degli errori è difficile e mentre possiamo recuperare da eccezioni, è molto più facile da non .

Le eccezioni sono il modo in cui il programmatore dice "Ho questa situazione ideale che deve essere abbinata e non mi preoccuperò di spendere più linee né le situazioni di gestione del tempo che non lo sono. " In sostanza, quando si esegue un tipo di gestione delle eccezioni "catch-all", si è rinunciare :

} catch(e) {
    print("Don't even know what error it is but **there's an error**. Exit / Retry.");
}

(Oltre alle eccezioni "catch-all", c'è anche lo stile longform "one-by-one" che è l' eccezione piuttosto che la norma ma non quello che la gente dice quando dice "gestione delle eccezioni".)

Per la lettura aggiuntiva, vedi link

    
risposta data 23.04.2015 - 07:49
fonte

Leggi altre domande sui tag