Ho un metodo che dovrebbe restituire un oggetto se viene trovato.
Se non viene trovato, dovrei:
- restituisce null
- generare un'eccezione
- altro
Ho un metodo che dovrebbe restituire un oggetto se viene trovato.
Se non viene trovato, dovrei:
Risposte:
Se ti aspetti sempre di trovare un valore, lancia l'eccezione se manca. L'eccezione significherebbe che c'era un problema.
Se il valore può essere mancante o presente ed entrambi sono validi per la logica dell'applicazione, restituisce un valore null.
Ancora più importante: cosa fai in altri punti del codice? La coerenza è importante.
GetPersonById(25)
verrebbe lanciato se quella persona è stata eliminata, ma GetPeopleByHairColor("red")
restituirebbe un risultato vuoto. Quindi, penso che i parametri diano qualcosa sulle aspettative.
Generare un'eccezione solo se è veramente un errore. Se si prevede che il comportamento dell'oggetto non esista, restituire il valore null.
Altrimenti è una questione di preferenza.
Come regola generale, se il metodo deve sempre restituire un oggetto, seguire l'eccezione. Se anticipi il null occasionale e vuoi gestirlo in un certo modo, vai con il null.
Qualunque cosa tu faccia, sconsiglio vivamente la terza opzione: restituire una stringa che dice "WTF".
Se null non indica mai un errore, restituisce null.
Se null è sempre un errore, genera un'eccezione.
Se null è talvolta un'eccezione, allora codifica due routine. Una routine genera un'eccezione e l'altra è una routine di test booleana che restituisce l'oggetto in un parametro di output e la routine restituisce un falso se l'oggetto non è stato trovato.
È difficile abusare di una routine Try. È davvero facile dimenticare di verificare la presenza di null.
Quindi, quando null è un errore, basta scrivere
object o = FindObject();
Quando il null non è un errore puoi scrivere qualcosa di simile
if (TryFindObject(out object o)
// Do something with o
else
// o was not found
find
e findOrFail
da Laravel Eloquent
TryFindObject
metodo? Le tuple sembrano più un paradigma pigro per i programmatori che non vogliono prendersi il tempo di definire un oggetto che incapsula più valori. Questo è essenzialmente tutte le tuple sono comunque al centro.
Volevo solo ricapitolare le opzioni menzionate prima, gettandone alcune nuove:
Oppure potresti combinare queste opzioni:
Fornisci diverse versioni sovraccariche del tuo getter, in modo che il chiamante possa decidere da che parte andare. Nella maggior parte dei casi, solo il primo ha un'implementazione dell'algoritmo di ricerca e gli altri avvolgono semplicemente il primo:
Object findObjectOrNull(String key);
Object findObjectOrThrow(String key) throws SomeException;
Object findObjectOrCreate(String key, SomeClass dataNeededToCreateNewObject);
Object findObjectOrDefault(String key, Object defaultReturnValue);
Anche se scegli di fornire una sola implementazione, potresti voler utilizzare una convenzione di denominazione come quella per chiarire il tuo contratto e ti aiuta a decidere se aggiungere altre implementazioni.
Non dovresti usarlo eccessivamente, ma può essere utile, specialmente quando scrivi una classe di supporto che userai in centinaia di applicazioni diverse con molte convenzioni sulla gestione degli errori.
Expected<T> findObject(String)
cui Expected<T>
ha le funzioni orNull()
, orThrow()
, orSupplied(Supplier<T> supplier)
, orDefault(T default)
. Ciò
Utilizzare il modello di oggetti null o generare un'eccezione.
Person somePerson = personRepository.find("does-not-exist");
supponiamo che questo metodo restituisca un oggetto null per ID does-not-exist
. Quale sarebbe quindi il comportamento corretto per somePerson.getAge()
? Al momento, non sono ancora convinto che il modello di oggetti null sia la soluzione giusta per le ricerche di entità.
Vantaggi del lancio di un'eccezione:
Per ulteriori spiegazioni con esempi, consultare: http://metatations.com/2011/11/17/returning-null-vs-throwing-an-exception/
dipende se la tua lingua e il tuo codice promuovono: LBYL (guarda prima di saltare) o EAFP (più facile chiedere perdono che permesso)
LBYL dice che dovresti controllare i valori (quindi restituisci un valore nullo)
EAFP dice di provare l'operazione e vedere se fallisce (genera un'eccezione)
anche se sono d'accordo con quanto sopra .. le eccezioni dovrebbero essere usate per condizioni eccezionali / di errore, e la restituzione di un valore null è la cosa migliore quando si usano i controlli.
EAFP vs. LBYL in Python:
http://mail.python.org/pipermail/python-list/2003-May/205182.html
( Web Archive )
Chiediti: "è un caso eccezionale che l'oggetto non venga trovato"? Se si prevede che accada nel normale corso del programma, probabilmente non dovresti sollevare un'eccezione (poiché non si tratta di un comportamento eccezionale).
Versione breve: utilizzare le eccezioni per gestire comportamenti eccezionali, non per gestire il normale flusso di controllo nel programma.
-Alan.
Le eccezioni sono correlate alla progettazione per contratto.
L'interfaccia di un oggetto è in realtà un contratto tra due oggetti, il chiamante deve soddisfare il contratto oppure il ricevitore potrebbe semplicemente fallire con un'eccezione. Vi sono due possibili contratti
1) tutti gli input il metodo è valido, nel qual caso è necessario restituire null quando l'oggetto non viene trovato.
2) è valido solo un input, ovvero ciò che risulta in un oggetto trovato. Nel qual caso DEVI offrire un secondo metodo che consenta al chiamante di determinare se il suo input sarà corretto. Per esempio
is_present(key)
find(key) throws Exception
SE e SOLO SE fornisci entrambi i metodi del 2o contratto, ti è consentito lanciare un'eccezione se non viene trovato nulla!
Preferisco solo restituire un valore null e fare affidamento sul chiamante per gestirlo in modo appropriato. L'eccezione (per mancanza di una parola migliore) è se sono assolutamente "certo" che questo metodo restituirà un oggetto. In tal caso un fallimento è un eccezionale che dovrebbe e dovrebbe essere lanciato.
Dipende da cosa significa che l'oggetto non è stato trovato.
Se si tratta di una situazione normale, restituire null. Questo è solo qualcosa che potrebbe accadere di tanto in tanto e i chiamanti dovrebbero verificarlo.
Se si tratta di un errore, quindi genera un'eccezione, i chiamanti dovrebbero decidere cosa fare con la condizione di errore dell'oggetto mancante.
Alla fine entrambi funzionerebbero, sebbene la maggior parte delle persone generalmente consideri una buona pratica usare le Eccezioni solo quando è successo qualcosa di Eccezionale.
Ecco un altro paio di suggerimenti.
Se si restituisce una raccolta, evitare di restituire null, restituire una raccolta vuota che semplifica la gestione dell'enumerazione senza prima un controllo null.
Diverse API .NET utilizzano il modello di un parametro thrownOnError che offre al chiamante la scelta se si tratta davvero di una situazione eccezionale o meno se l'oggetto non viene trovato. Type.GetType è un esempio di questo. Un altro modello comune con BCL è il modello TryGet in cui viene restituito un valore booleano e il valore viene passato tramite un parametro di output.
Si potrebbe anche considerare il modello Null Object in alcune circostanze, che può essere una versione predefinita o una versione senza comportamento. La chiave è evitare controlli null in tutta la base di codice. Vedi qui per maggiori informazioni http://geekswithblogs.net/dsellers/archive/2006/09/08/90656.aspx
In alcune funzioni aggiungo un parametro:
..., bool verify = true)
Vero significa lancio, falso significa restituire un valore di ritorno dell'errore. In questo modo, chiunque utilizzi questa funzione ha entrambe le opzioni. L'impostazione predefinita dovrebbe essere vera, a vantaggio di coloro che dimenticano la gestione degli errori.
Restituisce un valore null anziché generare un'eccezione e documenta chiaramente la possibilità di un valore di ritorno null nella documentazione dell'API. Se il codice chiamante non rispetta l'API e controlla il caso null, molto probabilmente si tradurrà in una sorta di "eccezione puntatore null" :)
In C ++, posso pensare a 3 diversi tipi di impostazione di un metodo che trova un oggetto.
Opzione A
Object *findObject(Key &key);
Restituisce null quando non è possibile trovare un oggetto. Bello e semplice. Vorrei andare con questo. Gli approcci alternativi di seguito sono per le persone che non odiano i parametri.
Opzione B
void findObject(Key &key, Object &found);
Passare un riferimento alla variabile che riceverà l'oggetto. Il metodo ha generato un'eccezione quando non è possibile trovare un oggetto. Questa convenzione è probabilmente più adatta se non ci si aspetta davvero che un oggetto non venga trovato - quindi si lancia un'eccezione per indicare che si tratta di un caso imprevisto.
Opzione C
bool findObject(Key &key, Object &found);
Il metodo restituisce false quando non è possibile trovare un oggetto. Il vantaggio di questa opzione over A è che è possibile verificare il caso di errore in una fase chiara:
if (!findObject(myKey, myObj)) { ...
riferendomi solo al caso in cui null non sia considerato un comportamento eccezionale, sono sicuramente per il metodo try, è chiaro, non è necessario "leggere il libro" o "guardare prima di saltare", come è stato detto qui
quindi in poche parole:
bool TryFindObject(RequestParam request, out ResponseParam response)
e questo significa che anche il codice dell'utente sarà chiaro
...
if(TryFindObject(request, out response)
{
handleSuccess(response)
}
else
{
handleFailure()
}
...
Generalmente dovrebbe restituire null. Il codice che chiama il metodo dovrebbe decidere se generare un'eccezione o tentare qualcos'altro.
Oppure restituisci un'opzione
Un'opzione è fondamentalmente una classe container che forza il client a gestire i casi di stand. Scala ha questo concetto, cerca l'API.
Quindi hai metodi come T getOrElse (T valueIfNull) su questo oggetto che restituiscono l'oggetto trovato, o un oggetto alternativo che specifica il client.
Sfortunatamente JDK è incoerente, se si tenta di accedere alla chiave inesistente nel pacchetto di risorse, non si trova un'eccezione e quando si richiede valore dalla mappa si ottiene null se non esiste. Quindi cambierei la risposta del vincitore a quanto segue, se il valore trovato può essere null, quindi sollevare un'eccezione quando non viene trovato, altrimenti restituire null. Quindi segui la regola con un'eccezione, se devi sapere perché il valore non viene trovato, solleva sempre un'eccezione, oppure ...
Finché si suppone che restituisca un riferimento all'oggetto, restituire un NULL dovrebbe essere buono.
Tuttavia, se restituisce l'intera cosa insanguinata (come in C ++ se lo fai: 'return blah;' piuttosto che 'return & blah;' (o 'blah' è un puntatore), allora non puoi restituire un NULL, perché è non di tipo "oggetto". In tal caso, lanciare un'eccezione o restituire un oggetto vuoto che non ha un flag di successo impostato è come approccerei il problema.
Non pensare che qualcuno abbia menzionato l'overhead nella gestione delle eccezioni: richiede risorse aggiuntive per caricare ed elaborare l'eccezione, quindi a meno che non si tratti di un vero evento di uccisione di app o di arresto del processo (andare avanti causerebbe più danni che benefici) Opterei per restituire un valore che l'ambiente chiamante potrebbe interpretare come ritiene opportuno.
Sono d'accordo con quello che sembra essere il consenso qui (restituire null se "non trovato" è un normale risultato possibile, o gettare un'eccezione se la semantica della situazione richiede che l'oggetto sia sempre trovato).
Vi è, tuttavia, una terza possibilità che potrebbe avere senso a seconda della situazione particolare. Il metodo potrebbe restituire un oggetto predefinito di qualche tipo nella condizione "non trovato", consentendo al codice chiamante di essere sicuro che riceverà sempre un oggetto valido senza la necessità di controllo null o rilevazione delle eccezioni.
Le eccezioni dovrebbero essere eccezionali . Restituisce null se è valido per restituire un null .
Se il metodo restituisce una raccolta, restituisce una raccolta vuota (come detto sopra). Ma per favore non Collezioni.EMPTY_LIST o simili! (nel caso di Java)
Se il metodo recupera un singolo oggetto, allora hai alcune opzioni.
Fai attenzione, se decidi di restituire un valore nullo. Se non sei l'unico programmatore del progetto, otterrai NullPointerExceptions (in Java o in altre lingue) in fase di esecuzione! Quindi non restituire valori null che non vengono controllati in fase di compilazione.
null
. Vedi la risposta più votata per ulteriori informazioni.
Se stai usando una libreria o un'altra classe che genera un'eccezione, dovresti ricominciare . Ecco un esempio Esempio2.java è come libreria ed Esempio.java usa il suo oggetto. Main.java è un esempio per gestire questa eccezione. È necessario mostrare un messaggio significativo e (se necessario) impilare la traccia per l'utente nel lato chiamante.
Main.java
public class Main {
public static void main(String[] args) {
Example example = new Example();
try {
Example2 obj = example.doExample();
if(obj == null){
System.out.println("Hey object is null!");
}
} catch (Exception e) {
System.out.println("Congratulations, you caught the exception!");
System.out.println("Here is stack trace:");
e.printStackTrace();
}
}
}
Example.java
/**
* Example.java
* @author Seval
* @date 10/22/2014
*/
public class Example {
/**
* Returns Example2 object
* If there is no Example2 object, throws exception
*
* @return obj Example2
* @throws Exception
*/
public Example2 doExample() throws Exception {
try {
// Get the object
Example2 obj = new Example2();
return obj;
} catch (Exception e) {
// Log the exception and rethrow
// Log.logException(e);
throw e;
}
}
}
Example2.java
/**
* Example2.java
* @author Seval
*
*/
public class Example2 {
/**
* Constructor of Example2
* @throws Exception
*/
public Example2() throws Exception{
throw new Exception("Please set the \"obj\"");
}
}
Dipende molto se ti aspetti di trovare l'oggetto o no. Se segui la scuola di pensiero che dovrebbero essere usate eccezioni per indicare qualcosa, beh, err, si è verificato un eccezionale:
Altrimenti, restituire null.