Restituisce null o un valore vuoto / genera un'eccezione? [duplicare]

8

Diversi libri di programmazione suggeriscono che i metodi non devono restituire valori di null (ad esempio, Codice pulito). Invece di restituire null i valori predefiniti (0 o stringa vuota o oggetto vuoto) devono essere restituiti o deve essere generata un'eccezione. Questo è consigliato per evitare molti controlli di != null o per evitare NullPointerException .

Davvero non capisco come possa essere d'aiuto. Se restituisci un valore predefinito, devi fare != DEFAULT controlli; più oltre, il valore predefinito potrebbe significare qualcosa (come 0 per un importo del credito). Lanciare un'eccezione specifica non vale la pena, perché se non gestisci bene il tuo codice, viene comunque generata un'eccezione - NullPointerException .

Ci ho pensato su questo quando ho trovato un bug causato da un metodo che restituiva un oggetto vuoto (ad esempio new MyBean() ) invece di restituire null . Il codice non funzionava in modo funzionale e i registri non avvisavano nulla, quindi il rilevamento e il fissaggio non erano così facili; con null a NullPointerException sarebbe stato gettato in modo da individuare e correggere il bug sarebbe stato banale.

L'unico caso in cui ha senso per me restituire un valore predefinito invece di restituire null è quando si restituiscono matrici / raccolte; qui di solito vengono consumati for each element in collection quindi se è vuoto non accade nulla ma se è null NPE viene lanciato.

    
posta m3th0dman 09.02.2014 - 10:59
fonte

4 risposte

6

Various programming books suggest that methods should not return null values (Clean Code for example). Instead of returning null default values (0 or empty string or empty object) should be returned or an exception should be thrown. This is recommended in order to avoid many != null checks or to avoid NullPointerException.

Vale la pena ricordare e un equivoco comune, che il signor Martin non ha affermato che dovresti sempre lanciare un'eccezione e mai restituire un valore di errore. In effetti, il passaggio rilevante è molto diverso se lo leggi attentamente (non ho la versione inglese qui, quindi devo tradurlo indietro, mi dispiace):

If you are about to return a null pointer, you should consider throwing an exception instead.

Nota che " considera ", non "tu".

Un'altra buona lettura sono queste due:

PS: testo originale della mia edizione tedesca:

Wenn Sie versucht sind, einen Nullzeiger zu liefern, sollten Sie stattdessen erwägen, eine Exception zu werfen.

    
risposta data 09.02.2014 - 12:15
fonte
3

A mio parere, per i metodi di restituzione a valore singolo, null è di gran lunga superiore alla restituzione di un'istanza vuota o predefinita di un tipo. Non solo i valori predefiniti possono mascherare gli errori, ma a seconda della complessità del tipo, possono creare dipendenze tra i metodi difficili da documentare perché i produttori API e i consumatori API devono mantenere una nozione coerente di quali / quali valori rappresentano risultati errati. p>

D'altra parte, quando si tratta di collezioni, restituire una raccolta vuota è di gran lunga superiore al ritorno di null, perché l'aspettativa del chiamante del metodo è che un numero variabile di risultati può essere restituito, quindi una raccolta vuota rappresenta un risultato concettualmente valido ed è simmetrico con il concetto dell'insieme vuoto in matematica.

Tuttavia, le eccezioni hanno il loro posto specialmente quando un metodo restituisce void o unit.

    
risposta data 09.02.2014 - 14:47
fonte
1

Mi piace l'idea di lanciare un'eccezione invece di restituire null o altro valore di errore. Diciamo che sto progettando una nuova classe che analizza un XML di un certo formato. Vorrei che la mia classe avesse solo un punto di accesso, ovvero un costruttore che specifica il percorso di un file XML valido. In cambio, ottengo un oggetto con un gruppo di proprietà e metodi che contiene il contenuto del mio file XML e mi fornisce alcune informazioni a riguardo.

Ora, ad esempio, come posso assicurarmi che il mio percorso per il file XML sia valido? Posso avere, ad esempio, una funzione Load(string xmlPath) nella mia classe. Quale dovrebbe essere il suo tipo di ritorno? Dovrebbe restituire un bool o int o cosa? E, cosa più interessante, come posso verificarlo? Idealmente dovrei rendere Load function private , e non mi interessa nemmeno che esista. Ma se voglio controllare il risultato di Load , allora la funzione dovrebbe essere resa public . Oppure passare una variabile bool loadSuccesful al mio costruttore e riempirla con il risultato del caricamento del file. Ma aspetta, cosa succede se voglio controllare il mio file XML rispetto a XSD ? Dovrò avere un'altra funzione, parseXmlSchema(string xmlPath) o qualcosa del genere. Cosa dovrebbe restituire in caso di fallimento? E come puoi ottenere le informazioni dalla tua classe mantenendo allo stesso tempo un'interfaccia pulita? Altre convalide potrebbero anche essere necessarie.

Mentre, se rendi privati questi tipi di metodi, e fai un'eccezione quando qualcosa va storto (non è proprio il caso di analizzare il tuo file XML se non è valido), puoi avere un'interfaccia pulita e usare la tua classe in un'istruzione try/catch . Puoi avere il costruttore della classe con un solo parametro string (o due, se conti lo schema XSD ). Se tutto va bene nella dichiarazione try , se nulla è andato storto, nessuna eccezione generata, percorsi esistenti, ecc. Il tuo programma è felice. Se al momento ti trovi nel livello intermedio della tua app e ottieni un FileNotFoundException dai livelli inferiori, puoi rethrow e passarlo all'utente (GUI) per fare qualcosa al riguardo. Il livello della GUI potrebbe prenderlo in questo momento e avvisare l'utente, ad esempio tramite un messageBox, e registrarlo come bonus. L'utente prova quindi un altro file XML e continua la storia. Se rilevi tutte le possibili eccezioni e visualizzi informazioni significative all'utente o prendi le misure appropriate in background, non c'è bisogno che la tua applicazione si blocchi (è probabile che tu l'abbia visto), se è quello che ti spaventa.

Come bonus, puoi trasmettere ogni tipo di informazione significativa nel punto in cui è stata generata la tua eccezione, come messaggi, nomi di parametri, numeri di linea, nome di funzione, ecc. Se documenti il tuo codice (come dovresti), documenta il eccezioni che una classe / metodo può lanciare.

    
risposta data 09.02.2014 - 11:31
fonte
1

È di fondamentale importanza distinguere tra i metodi che si prevede incontrino condizioni di errore e quelli che non lo sono. È altrettanto importante avere una chiara comprensione del contratto per quel metodo.

Se il metodo è uno che riscontra abitualmente un errore (come ad esempio il recupero di dati da un database), allora ha bisogno di un modo per restituire successo / fallimento, nonché un modo per restituire i dati. La mia preferenza è di solito restituire true / false per l'operazione, utilizzare una chiamata separata per recuperare i dati e / o lo stato.

Se il metodo è uno che non si prevede che incontri un errore (come restituire un elemento da una raccolta per indice), dovrebbe never restituire null. Dovrebbe restituire un articolo valido, o sollevare un'eccezione, o affermare. I chiamanti dovrebbero mai controllare il risultato di ritorno, perché sarà sempre valido.

Potrebbe essere conveniente restituire un valore predefinito piuttosto che asserire, ma questo dovrebbe riflettersi nel contratto del metodo e potrebbero esserci due metodi (GetXxx e GetXxxOrDefault).

Il controllo diffuso dei valori di ritorno rispetto a null è spesso sintomatico di problemi più profondi nel codice. I consigli trovati nei libri di programmazione più recenti sono validi.

    
risposta data 09.02.2014 - 15:08
fonte

Leggi altre domande sui tag