it-swarm.it

È mai ok avere una dichiarazione di cattura vuota?

Ci ho pensato e non ho potuto fare un esempio. Perché qualcuno dovrebbe voler prendere un'eccezione e non fare nulla al riguardo? Puoi fare un esempio? Forse è solo qualcosa che non dovrebbe mai essere fatto.

61
ysolik

Lo faccio sempre con cose come errori di conversione in D:

import std.conv, std.stdio, std.exception;

void main(string[] args) {  
    enforce(args.length > 1, "Usage:  foo.exe filename");

    double[] nums;

    // Process a text file with one number per line into an array of doubles,
    // ignoring any malformed lines.
    foreach(line; File(args[1]).byLine()) {
        try {
            nums ~= to!double(line);
        } catch(ConvError) {
            // Ignore malformed lines.
        }
    }

    // Do stuff with nums.
}

Detto questo, penso che tutti i blocchi di cattura dovrebbero avere qualcosa in essi, anche se quel qualcosa è solo un commento che spiega perché stai ignorando l'eccezione.

Modifica: voglio anche sottolineare che, se hai intenzione di fare qualcosa del genere, dovresti fare attenzione a cogliere solo l'eccezione specifica che vuoi ignorare. Fare un semplice vecchio catch {} è quasi sempre una brutta cosa.

78
dsimcha

Un esempio in cui penso sia giusto ingoiare l'eccezione senza fare nulla, anche registrando l'eccezione, è all'interno del codice di registrazione stesso.

Se hai provato a registrare qualcosa e hai ottenuto un'eccezione, non c'è molto che puoi fare al riguardo:

  • non è possibile registrarlo ovviamente;
  • potresti essere in grado di ricorrere a un meccanismo di registrazione delle riserve, ma la maggior parte delle applicazioni non è così sofisticata e per quelle che sono abbastanza sofisticate lo stesso problema di progettazione sorgerà con il meccanismo di registrazione delle riserve;
  • fallimento rapido: sarà una soluzione troppo radicale per la maggior parte delle applicazioni;
  • vomitare un'eccezione farà poco bene in quanto finirà in una dichiarazione catch nello stack che quasi sicuramente proverà a registrarlo ...

Ciò ti lascia con l'opzione "meno del male" di ingoiarlo in silenzio, consentendo all'applicazione di continuare a svolgere il suo lavoro principale, ma compromettendo la capacità di risolverlo.

50
kdubinets

Se viene generata un'eccezione da un'operazione facoltativa, potrebbe non esserci nulla da fare. Potrebbe non essere utile registrarlo. In tal caso, potresti semplicemente voler prenderlo e non fare nulla.

Se lo stai facendo, includi un commento. Commenta sempre tutto ciò che sembra un bug (descrizione dettagliata di un'istruzione switch, blocco catch vuoto, assegnazione in una condizione).

Potresti sostenere che questo non è un uso corretto delle eccezioni, ma è per un'altra domanda.

8
David Thornley

In alcuni casi, Java richiede di gestire un'eccezione che, in nessun caso, può mai accadere. Considera questo codice:

try {
   bytes[] hw = "Hello World".getBytes("UTF-8");
}
catch(UnsupportedCodingException e) {
}

Ogni implementazione della Java è richiesta per supportare i seguenti set di caratteri standard.

...

UTF-8

Senza rompere la tua Java, semplicemente non c'è modo di causare questa eccezione. Quindi perché preoccuparsi di gestirla? Ma non puoi semplicemente ommettere la clausola try-catch-.

6
user281377

Come regola generale, no. O vuoi gettare l'eccezione nello stack o registrare ciò che è successo.

Tuttavia, lo faccio spesso quando analizzo le stringhe e la conversione in numeri (specialmente nella mappatura di progetti che sono di uso una volta e butto via la varietà).

boolean isNonZeroNumber = false;

try {
   if(StringUtils.isNotBlank(s) && new BigDecimal(s).compareTo(BigDecimal.ZERO) != 0) {
     b = true;
   }
} catch(NumberFormatException e) {
//swallow this exception; b stays false.
}

return b;
6
Fil

I blocchi catch vuoti sono odori di codice nella maggior parte delle lingue. L'idea principale è usare le eccezioni per situazioni eccezionali e non usarle per il controllo logico. Tutte le eccezioni devono essere gestite da qualche parte.

Come conseguenza di questo approccio, quando si programma un particolare livello di applicazione, sono disponibili diverse opzioni:

  • non fare nulla per l'eccezione. Sarà catturato e gestito da un livello diverso
  • catturarlo ed eseguire l'azione correttiva.
  • prenderlo, fare qualcosa, ma ri-lanciarlo per un altro livello da gestire

Questo in realtà non lascia spazio a nulla-vuoti, blocchi vuoti catch.

EDITED TO ADD: supponi di programmare in un linguaggio in cui generare eccezioni è il modo normale di controllare la logica del programma (una delle alternative a goto). Quindi un blocco catch vuoto in un programma scritto in questa lingua è molto simile a un blocco else vuoto in una lingua tradizionale (o nessun blocco else). Tuttavia, credo che questo non sia lo stile di programmazione raccomandato da C #, Java o comunità di sviluppo C++.

6
azheglov

In alcuni casi, l'eccezione non è affatto eccezionale; in effetti, è previsto. Considera questo esempio:

    /* Check if the process is still alive; exitValue() throws an exception if it is */
    try {
        p.exitValue();
        processPool.remove(p);
    }
    catch (IllegalThreadStateException e) { /* expected behaviour */ }

Poiché non esiste un metodo isAlive () in Java.lang.Process (), l'unico modo per verificare se è ancora attivo è chiamare exitValue (), che genera un oggetto IllegalThreadStateException se il processo è ancora in esecuzione.

3
user281377

Nella mia umile esperienza, raramente è una cosa positiva. Il chilometraggio può variare però.

Quasi ogni volta che l'ho visto nella nostra base di codice, è stato perché ho rintracciato un bug che l'eccezione mangiata ha nascosto. Per dirla in altro modo, non fornendo alcun codice, l'applicazione non ha modo di indicare un errore o eseguire un'altra azione.

A volte, ad esempio a livello di API, potresti non voler o essere in grado di far passare le eccezioni, quindi in quel caso, tendo a cercare di catturare il più generico, quindi registrarle. Ancora una volta, per dare almeno una possibilità a una sessione di debug/diagnosi.

In genere, se deve essere vuoto, il minimo che faccio è mettere un'asserzione di qualche tipo, quindi almeno qualcosa accade durante una sessione di debug. Detto questo, se non riesco a gestirlo, tendo a ometterli completamente.

2
DevSolo

IMO c'è un posto dove le dichiarazioni di cattura vuote sono OK. Nei casi di test in cui ti aspetti un'eccezione:

try
{
   DoSomething(); //This should throw exception if everything works well
   Assert.Fail('Expected exception was not thrown');
}
catch(<whatever exception>)
{
    //Expected to get here
}
2

Credo che ci siano alcuni casi in cui è giustificato avere una clausola catch vuota - questi sono casi in cui si desidera che il codice continui a funzionare se una determinata operazione fallisce. Tuttavia, penso che questo modello possa essere facilmente abusato, quindi ogni utilizzo dovrebbe essere attentamente esaminato per assicurarsi che non ci sia un modo migliore per gestirlo. In particolare, ciò non dovrebbe mai essere fatto se lascia il programma in uno stato incoerente o se potrebbe portare a qualche altra parte del codice che fallisce in seguito.

2
o. nate

Il controllo dell'esistenza è un buon caso d'uso:

// If an exception happens, it doesn't matter. Log the initial value or the new value

function logId(person) {
    let id = 'No ID';
    try {
        id = person.data.id;
    } catch {}
    console.log(id);
}

Un altro caso è quando viene utilizzata una clausola finally:

 function getter(obj){}

 function objChecker()
   {
   try
     {
     /* Check argument length and constructor type */
     if (getter.length === 1 && getter.constructor === Function)
       {
       console.log("Correct implementation");
       return true;
       }
     else
       {
       console.log("Wrong implementation");
       return false;
       }
     }
   catch(e)
     {
     }
   finally
     {
     console.log(JSON.stringify(getter))
     }
   }

 // Test the override of the getter method 
 getter = getter;
 objChecker();
 getter = [];
 objChecker();
 getter = {};
 objChecker();
 getter = RegExp;
 objChecker();
 getter = Function;
 objChecker();

Esiste una proposta per consentire omissione del vincolo di cattura in ECMAScript relativo a questo e ad altri casi d'uso simili.

Riferimenti

1
Paul Sweatte

Non credo di non avere un certo livello di allerta quando si verifica un'eccezione - uno degli obiettivi della programmazione non dovrebbe essere quello di migliorare il codice? Se un'eccezione si verifica il 10% delle volte e non si è mai a conoscenza di essa, allora l'eccezione sarà sempre così grave o peggiore.

Tuttavia, vedo l'altro lato, che se l'eccezione non fa alcun danno reale nell'elaborazione del codice, perché esporre l'utente ad esso. La soluzione che in genere implemento è averlo registrato dalla mia classe logger (che è in ogni singola classe che scrivo mai al lavoro).

Se è un'eccezione benigna, allora faccio una chiamata al metodo .Debug () del mio Logger; in caso contrario, Logger.Error () (e (forse) lancio).

try
{
   doWork();
}
catch(BenignException x)
{
  _log.Debug("Error doing work: " + x.Message);
}

A proposito, nella mia implementazione del mio logger, effettuare una chiamata al metodo .Debug () lo registrerà solo se il mio file App.Config specifica che il livello del registro di esecuzione del programma è in modalità Debug.

1
Tim Claason

Va bene in una situazione in cui è necessario eseguire una sequenza, indipendentemente dal pezzo più critico posto alla fine.

Per esempio. Comunicazione motion control dell'host al controller. In situazioni di emergenza vi sono una serie di passaggi di preparazione per interrompere il movimento, arrestare la generazione della traiettoria, rallentare i motori, abilitare le interruzioni, disabilitare l'amplificatore e successivamente è necessario interrompere l'alimentazione del bus. Tutto deve avvenire in sequenza e se uno dei passaggi fallisce il resto dei passaggi deve essere eseguito comunque anche con il rischio accettato di danneggiare l'hardware. Dì anche se tutto quanto sopra fallisce, la potenza del bus di uccisione deve avvenire comunque.

0
user7071

L'unica volta in cui ho davvero avuto bisogno di fare qualcosa del genere era con una classe di registrazione per un'app console. Esisteva un gestore di cattura globale di livello superiore che emetteva l'errore su STDOUT, registrava l'errore su un file, quindi chiudeva l'app con un codice di errore> 0.

Il problema qui era che a volte la registrazione nel file non riusciva. I permessi della directory ti hanno impedito di scrivere il file, il file era bloccato esclusivamente, qualunque cosa. Se ciò accadesse, non potrei gestire l'eccezione nello stesso modo che avevo altrove (cattura, registra i dettagli rilevanti, includi un tipo di eccezione migliore, ecc.) Perché la registrazione dei dettagli dell'eccezione ha causato il logger per passare attraverso le stesse azioni (tentando di scrivere su un file) che erano già fallite. Quando hanno fallito di nuovo ... Vedi dove sto andando. Entra in un ciclo infinito.

Se elimini alcuni dei blocchi try {}, puoi finire con l'eccezione che appare in una finestra di messaggio (non quello che vuoi per un'app di configurazione silenziosa). Quindi in quel metodo che scrive nel file di registro, ho un gestore di cattura vuoto. Questo non seppellisce l'errore poiché ottieni ancora il codice di errore> 0, interrompe il ciclo infinito e consente all'app di uscire con grazia.

C'è ovviamente un commento, che spiega perché è vuoto.

(Avevo intenzione di postare questo in precedenza, avevo solo paura di farmi infiammare nell'oblio. Dato che non sono l'unico, però ...)

0
JohnL

Chiudere le risorse di sistema con garbo per recuperare da un errore

Per esempio. Se stai eseguendo un servizio in background che non fornisce feedback all'utente, potresti non voler inviare un'indicazione dell'errore all'utente ma devi fare chiudere le risorse essere usato in modo grazioso.

try
{
    // execution code here
}
catch(Exception e)
{
    // do nothing here
}
finally
{
    // close db connection
    // close file io resource
    // close memory stream
    // etc...
}

Idealmente, dovresti utilizzare la cattura in modalità debug per rilevare errori e stamparli sulla console o su un file di registro per il test. In un ambiente di produzione, i servizi in background generalmente non devono interrompere l'utente quando viene generato un errore, pertanto è necessario eliminare l'output dell'errore.

0
Evan Plaice