È meglio restituire valori NULL o vuoti da funzioni / metodi in cui il valore restituito non è presente?


135

Sto cercando una raccomandazione qui. Sto lottando con se sia meglio restituire NULL o un valore vuoto da un metodo quando il valore restituito non è presente o non può essere determinato.

Prendi i seguenti due metodi come esempi:

string ReverseString(string stringToReverse) // takes a string and reverses it.
Person FindPerson(int personID)    // finds a Person with a matching personID.

In ReverseString(), direi restituire una stringa vuota perché il tipo restituito è stringa, quindi il chiamante se lo aspetta. Inoltre, in questo modo, il chiamante non dovrebbe verificare se è stato restituito un NULL.

In FindPerson(), il ritorno di NULL sembra una soluzione migliore. Indipendentemente dal fatto che new Person()venga restituito NULL o un oggetto persona vuoto ( ), il chiamante dovrà verificare se l'oggetto persona è NULL o vuoto prima di eseguire qualsiasi operazione (come chiamare UpdateName()). Quindi perché non semplicemente restituire NULL qui e quindi il chiamante deve solo controllare NULL.

Qualcun altro ha difficoltà con questo? Qualsiasi aiuto o approfondimento è apprezzato.


2
Varierà. Si potrebbe anche sostenere che il metodo dovrebbe interrompere i valori errati in anticipo, ad esempio il parametro stringToReverse che viene passato come vuoto o nullo. Se hai eseguito quel controllo (ha restituito un'eccezione), restituirà sempre qualcosa di diverso da null.
Aaron McIver il

Fowler POEAA - p. 496 Pattern di base - Caso speciale (oggetto null) Bloch Effective Java, 2nd Edition Item 43: Restituisce array o raccolte vuoti, non null
Boris Treukhov,

1
@Boris Non ho visto il tuo commento. In realtà ho appena pubblicato un caso speciale come risposta.
Thomas Owens

@Thomas Non vedo alcun problema :). Per quanto riguarda la domanda è comunque una questione di buon senso.
Boris Treukhov,

Un commento interessante è che nei database Oracle NULL e la stringa vuota sono uguali
WuHoUnited,

Risposte:


77

StackOverflow ha una buona discussione su questo argomento esatto in queste domande e risposte . Nella domanda più votata, kronoz osserva:

La restituzione di null è di solito l'idea migliore se si intende indicare che non sono disponibili dati.

Un oggetto vuoto implica che i dati sono stati restituiti, mentre la restituzione di null indica chiaramente che non è stato restituito nulla.

Inoltre, la restituzione di un valore nullo comporterà un'eccezione nulla se si tenta di accedere ai membri nell'oggetto, il che può essere utile per evidenziare il codice errato - il tentativo di accedere a un membro del nulla non ha alcun senso. L'accesso ai membri di un oggetto vuoto non fallirà, il che significa che i bug possono non essere scoperti.

Personalmente, mi piace restituire stringhe vuote per funzioni che restituiscono stringhe per ridurre al minimo la quantità di gestione degli errori che deve essere messa in atto. Tuttavia, dovrai assicurarti che il gruppo con cui lavori segua la stessa convenzione, altrimenti i benefici di questa decisione non saranno raggiunti.

Tuttavia, come notato dal poster nella risposta SO, è probabile che vengano restituiti valori null se si prevede un oggetto in modo che non vi siano dubbi sul fatto che i dati vengano restituiti.

Alla fine, non esiste un modo migliore per fare le cose. Costruire un consenso di gruppo alla fine guiderà le migliori pratiche del tuo team.


8
Personalmente, mi piace restituire stringhe vuote per funzioni che restituiscono stringhe per ridurre al minimo la quantità di gestione degli errori che deve essere messa in atto. Non ho mai capito questo argomento. Il controllo null è cosa, al massimo <10 caratteri? Perché ci comportiamo come se questo fosse un ritorno alla flessione del lavoro?
Aaron McIver il

19
Nessuno ha detto che era tornato a piegare il lavoro. Ma è lavoro. Aggiunge un caso speciale al codice che significa un altro ramo da testare. Inoltre, interrompe il flusso del codice. for x in list_of_things() {...}è probabilmente più veloce a brontolare alloral = list_of_things(); if l != null {...}
Bryan Oakley,

5
@Bryan: c'è una grande differenza tra un elenco di valori vuoto e una stringa vuota. Una stringa raramente rappresenta un elenco di caratteri.
Kevin Cline il

3
@kevin cline: ovviamente. Ma nel caso di una stringa, è possibile che tale stringa appaia in un registro, che sia null o meno. Dover controllare se è null in modo da poter stampare una stringa vuota offusca il vero intento. O forse è qualcosa come il campo del database che contiene contenuti forniti dall'utente che desideri aggiungere a una pagina web. È più facile da fare emit(user.hometown)rispetto aif user.hometown == null { emit("") else {emit(user.hometown)}
Bryan Oakley,

1
Non solo è una digitazione extra (non un grosso problema), ma influisce sulla leggibilità. Personalmente trovo il codice con un sacco di controlli null che distrae.
ToddR

82

In tutto il codice che scrivo, evito di tornare nullda una funzione. L'ho letto in Clean Code .

Il problema con l'utilizzo nullè che la persona che utilizza l'interfaccia non sa se nullè un possibile risultato e se deve verificarlo, perché non esiste un not nulltipo di riferimento.

In F # è possibile restituire un optiontipo, che può essere some(Person)o none, quindi è ovvio per il chiamante che devono verificare.

Il modello C # (anti-) analogo è il Try...metodo:

public bool TryFindPerson(int personId, out Person result);

Ora so che le persone hanno detto di odiare lo Try...schema perché avere un parametro di output rompe le idee di una funzione pura, ma in realtà non è diverso da:

class FindResult<T>
{
   public FindResult(bool found, T result)
   {
       this.Found = found;
       this.Result = result;
   }

   public bool Found { get; private set; }
   // Only valid if Found is true
   public T Result { get; private set;
}

public FindResult<Person> FindPerson(int personId);

... e ad essere onesti, puoi presumere che ogni programmatore .NET sia a conoscenza del Try...modello perché è utilizzato internamente dal framework .NET. Ciò significa che non devono leggere la documentazione per capire cosa fa, il che è più importante per me che attenersi alla visione delle funzioni di un purista (capire che resultè un outparametro, non un refparametro).

Quindi vorrei andare TryFindPersonperché sembra che indichi che è perfettamente normale non riuscire a trovarlo.

Se, d'altra parte, non vi fosse alcuna ragione logica per cui il chiamante avrebbe mai fornito un personIdche non esisteva, probabilmente lo farei:

public Person GetPerson(int personId);

... e poi lancerei un'eccezione se non fosse valida. Il Get...prefisso implica che il chiamante sa che dovrebbe avere successo.


28
+1, risponderei a questa domanda con un riferimento a Clean Code se non lo avessi già fatto. Mi piace il mantra: "SE LA TUA CANTINA FUNZIONALE FA COSA DICE IL NOME, POI GLI ECCEZIONI." Muuuch è meglio che cercare null ogni decine di righe ...
Graham,

13
Ho rinunciato ad assumere qualcosa sulla conoscenza delle persone.
CaffGeek,

5
"Il problema con l'utilizzo di null è che la persona che utilizza l'interfaccia non sa se null è un possibile risultato e se deve verificarlo, perché non esiste un tipo di riferimento null." Poiché i tipi di riferimento possono essere nulli, non puoi sempre supporre che null sia un possibile risultato?
Tommy Carlier,

4
Se una funzione restituisce un puntatore (C / C ++) o un riferimento a un oggetto (Java), presumo sempre che possa restituire null.
Giorgio,

7
"Il problema con l'utilizzo di null è che la persona che utilizza l'interfaccia non sa se null è un possibile risultato e se deve verificarlo, [...]" Se un metodo potrebbe restituire null, dovrebbe essere esplicitamente menzionato come parte del contratto API.
Zsolt Török,

28

Potresti provare il modello Special Case di Martin Fowler , da Paterns of Enterprise Application Architecture :

I nullità sono cose imbarazzanti nei programmi orientati agli oggetti perché sconfiggono il polimorfismo. Di solito puoi invocare foo liberamente su un riferimento variabile di un determinato tipo senza preoccuparti se l'articolo è il tipo esatto o una sottoclasse. Con un linguaggio fortemente tipizzato puoi persino far controllare al compilatore che la chiamata sia corretta. Tuttavia, poiché una variabile può contenere null, è possibile che si verifichi un errore di runtime invocando un messaggio su null, che fornirà una traccia dello stack piacevole e intuitiva.

Se è possibile che una variabile sia nulla, devi ricordarti di circondarla con un codice di test null in modo da fare la cosa giusta se è presente un null. Spesso la cosa giusta è la stessa in molti contesti, quindi finisci per scrivere codice simile in molti punti - commettendo il peccato della duplicazione del codice.

I null sono un esempio comune di tali problemi e altri spuntano regolarmente. Nei sistemi numerici devi affrontare l'infinito, che ha regole speciali per cose come l'addizione che spezza i soliti invarianti di numeri reali. Una delle mie prime esperienze nel software aziendale è stata con un cliente di utilità che non era completamente noto, indicato come "occupante". Tutto ciò implica l'alterazione del normale comportamento del tipo.

Invece di restituire un valore nullo o un valore dispari, restituisce un caso speciale che ha la stessa interfaccia di quello che si aspetta il chiamante.


Mi sono imbattuto in questo scenario, ma solo dopo il rilascio del software. I miei dati di test non l'hanno mai attivato, quindi è stato un po 'fuori dal comune e il debug è stato un dolore. Anche se non l'ho risolto con il modello Special Case, è bene esserne consapevoli.
Samis,

14

Penso ReverseString()che restituirebbe la stringa invertita e genererebbe un IllegalArgumentExceptionif se passato in a Null.

Penso che FindPerson()dovrebbe seguire il NullObject Pattern o sollevare un'eccezione non selezionata sul non trovare qualcosa se dovresti sempre essere in grado di trovare qualcosa.

Dover affrontare Nullè qualcosa che dovrebbe essere evitato. Avere Nullin lingue è stato chiamato un errore di miliardi di dollari dal suo inventore!

Lo chiamo il mio errore da miliardi di dollari. Fu l'invenzione del riferimento nullo nel 1965. A quel tempo, stavo progettando il primo sistema di tipi completo per riferimenti in un linguaggio orientato agli oggetti (ALGOL W).

Il mio obiettivo era quello di garantire che ogni uso dei riferimenti fosse assolutamente sicuro, con il controllo eseguito automaticamente dal compilatore. Ma non ho resistito alla tentazione di inserire un riferimento null, semplicemente perché era così facile da implementare.

Ciò ha portato a innumerevoli errori, vulnerabilità e arresti anomali del sistema, che probabilmente hanno causato un miliardo di dollari di dolore e danni negli ultimi quarant'anni.

Negli ultimi anni, numerosi analizzatori di programmi come PREfix e PREfast in Microsoft sono stati utilizzati per controllare i riferimenti e fornire avvisi in caso di rischio che possano essere non nulli. Linguaggi di programmazione più recenti come Spec # hanno introdotto dichiarazioni per riferimenti non nulli. Questa è la soluzione, che ho respinto nel 1965.

Tony Hoare


11

Restituisce un'opzione . Tutti i vantaggi della restituzione di un diverso valore non valido (come la possibilità di avere valori vuoti nelle raccolte) senza alcun rischio di NullPointerException.


1
Interessante. Come implementare un'opzione in Java? E in C ++?
Giorgio,

1
@Giorgio, Per Java, le librerie Guava, di Google, hanno una classe chiamata Opzionale .
Otavio Macedo,

1
Per C ++, c'èboost::optional<T>
MSalters,

8

Vedo entrambi i lati di questo argomento e mi rendo conto che alcune voci piuttosto influenti (ad esempio Fowler) sostengono di non restituire valori null per mantenere pulito il codice, evitare blocchi aggiuntivi di gestione degli errori, ecc.

Tuttavia, tendo a schierarmi con i fautori del ritorno a null. Trovo che vi sia un'importante distinzione nell'invocare un metodo e rispondere con non ho dati e rispondere con ho questa stringa vuota .

Dal momento che ho visto alcune delle discussioni che fanno riferimento a una classe Person, considera lo scenario in cui tenti di cercare un'istanza della classe. Se passi un attributo finder (ad es. Un ID), un client può immediatamente verificare la presenza di null per vedere se non è stato trovato alcun valore. Questo non è necessariamente eccezionale (quindi non necessita di eccezioni), ma dovrebbe anche essere documentato chiaramente. Sì, questo richiede un certo rigore da parte del cliente, e no, non penso che sia affatto una cosa negativa.

Ora considera l'alternativa in cui restituisci un oggetto Person valido ... che non contiene nulla. Metti i null in tutti i suoi valori (nome, indirizzo, favoriteDrink) o vai a popolare quelli con oggetti validi ma vuoti? In che modo il cliente può ora determinare che non è stata trovata alcuna persona reale? Devono verificare se il nome è una stringa vuota anziché nulla? Questo genere di cose non porterebbe davvero a un numero maggiore o maggiore di ingombri di codice e istruzioni condizionali rispetto a se avessimo appena verificato la presenza di null e avessimo proseguito?

Ancora una volta, ci sono punti su entrambi i lati di questo argomento con cui potrei essere d'accordo, ma trovo che questo abbia più senso per la maggior parte delle persone (rendendo il codice più gestibile).


La differenza è, "non FindPersono GetPersonrestituire un nullo o un'eccezione se la chiave non esiste?" Come utente dell'API non lo so e devo controllare la documentazione. D'altra parte, bool TryGetPerson(Guid key, out Person person)non mi impone di controllare la documentazione e so che non viene generata un'eccezione in una circostanza piuttosto non eccezionale. Questo è il punto che sto cercando di chiarire nella mia risposta.
Scott Whitlock,

4
Penso che le persone siano troppo attaccate alle eccezioni. Le eccezioni sono dannose e richiedono risorse. Per non parlare delle persone che cercano di catturare dichiarazioni senza risolvere nulla. Le eccezioni sono un chiaro segno che qualcosa è andato sostanzialmente storto. Ad esempio, i riferimenti null generano un'eccezione, poiché è chiaramente errato fare riferimento a oggetti null. È sbagliato usarlo per verificare se la persona è stata trovata o meno.
Vladimir Kocjancic,

1
@VladimirKocjancic: Sono pienamente d'accordo: eccezioni dovrebbero essere utilizzate per situazioni eccezionali, come bug del software, guasti hardware, configurazione errata del sistema. Se stai calcolando una funzione parziale (comefindPerson ) è assolutamente normale non ottenere alcun risultato. Ciò non dovrebbe comportare un'eccezione.
Giorgio,

6

Restituisce null se è necessario sapere se l'articolo esiste o meno. In caso contrario, restituisce il tipo di dati previsto. Ciò è particolarmente vero se stai restituendo un elenco di articoli. Di solito è sicuro supporre che se il chiamante desidera un elenco, vorrà scorrere l'elenco. Molte (la maggior parte? Tutte?) Lingue falliscono se provi a scorrere su null ma non su iterate su un elenco vuoto.

Trovo frustrante provare a usare codice come questo, solo per fallire:

for thing in get_list_of_things() {
    do_something_clever(thing)
}

Non dovrei aggiungere un caso speciale per il caso quando non ci sono cose .


7
Nei casi in cui è previsto un elenco o un altro gruppo di valori, scelgo sempre di restituire un elenco vuoto, proprio per questo motivo. L'azione predefinita (che scorre su un elenco vuoto) è quasi sempre corretta e, in caso contrario, il chiamante può verificare esplicitamente se l'elenco è vuoto.
TMN,

5

Dipende dalla semantica del metodo. È possibile specificare, il metodo accetta solo "Non null". In Java puoi dichiarare che usando alcune annotazioni sui metadati:

string ReverseString(@NotNull String stringToReverse)

Dovresti in qualche modo specificare il valore di ritorno. Se dichiari di accettare solo valori NotNull, sei obbligato a restituire una stringa vuota (se anche l'input era una stringa vuota).

Il secondo caso è un po 'complicato nella sua semantica. Se questo metodo consiste nel restituire una persona con la sua chiave primaria (e la persona dovrebbe esistere), il modo migliore è gettare un'eccezione.

Person FindPerson(int personID)

Se cerchi una persona con qualche id indovinato (che mi sembra strano), è meglio dichiarare quel metodo come @Nullable.


3

Consiglierei di usare il modello Null Object quando possibile. Semplifica il codice quando chiami i tuoi metodi e non riesci a leggere brutti codici come

if (someObject != null && someObject.someMethod () != whateverValue)

Ad esempio, se un metodo restituisce una raccolta di oggetti che si adattano a un modello, restituire una raccolta vuota ha più senso che restituire nulle iterare su questa raccolta vuota non avrà praticamente alcuna penalità di prestazione. Un altro caso sarebbe un metodo che restituisce l'istanza della classe utilizzata per registrare i dati, restituendo un oggetto Null piuttosto che nullè preferibile a mio avviso, in quanto non obbliga gli utenti a verificare sempre se il riferimento restituito ènull .

Nei casi in cui il ritorno nullha senso (chiamando il findPerson ()metodo per esempio), proverei almeno a fornire un metodo che ritorni se l'oggetto è presente ( personExists (int personId)per esempio), un altro esempio sarebbe il containsKey ()metodo su un Mapin Java). Rende il codice del chiamante più pulito, poiché puoi facilmente vedere che esiste la possibilità che l'oggetto desiderato non sia disponibile (la persona non esiste, la chiave non è presente nella mappa). A nullmio parere, verificare costantemente se un riferimento è offuscato dal codice.


3

null è la cosa migliore da restituire se e solo se si applicano le seguenti condizioni:

  • il risultato null è previsto nel normale funzionamento . Ci si potrebbe aspettare che potresti non essere in grado di trovare una persona in alcune circostanze ragionevoli, quindi findPerson () che restituisce null va bene. Tuttavia, se si tratta di un errore veramente imprevisto (ad es. In una funzione chiamata saveMyImportantData ()), dovresti generare un'eccezione. C'è un suggerimento nel nome: le eccezioni sono per circostanze eccezionali!
  • null è usato per significare "non trovato / nessun valore" . Se vuoi dire qualcos'altro, allora restituisci qualcos'altro! Buoni esempi potrebbero essere le operazioni in virgola mobile che restituiscono Infinity o NaN: si tratta di valori con significati specifici, quindi sarebbe molto confuso se si restituisse null qui.
  • La funzione ha lo scopo di restituire un singolo valore , come findPerson (). Se è stato progettato per restituire una raccolta, ad esempio findAllOldPeople (), è preferibile una raccolta vuota. Un corollario di ciò è che una funzione che restituisce una raccolta non dovrebbe mai restituire null .

Inoltre, assicurarsi di documentare il fatto che la funzione può restituire null.

Se segui queste regole, i null sono per lo più innocui. Si noti che se si dimentica di verificare la presenza di null, si otterrà normalmente una NullPointerException immediatamente dopo, che di solito è un bug abbastanza facile da correggere. Questo approccio fail-fast è molto meglio che avere un valore di ritorno falso (ad esempio una stringa vuota) che viene propagato silenziosamente attorno al sistema, possibilmente corrompendo i dati, senza generare un'eccezione.

Infine, se applichi queste regole alle due funzioni elencate nella domanda:

  • FindPerson : sarebbe opportuno che questa funzione restituisse null se la persona non veniva trovata
  • ReverseString : sembra che non riuscirebbe mai a trovare un risultato se si passasse una stringa (poiché tutte le stringhe possono essere invertite, inclusa la stringa vuota). Quindi non dovrebbe mai restituire null. Se qualcosa va storto (memoria insufficiente?), Dovrebbe generare un'eccezione.

1

A mio avviso, c'è una differenza tra la restituzione di NULL, la restituzione di un risultato vuoto (ad esempio la stringa vuota o un elenco vuoto) e il lancio di un'eccezione.

Normalmente prendo il seguente approccio. Considero una funzione o un metodo f (v1, ..., vn) come l'applicazione di una funzione

f : S x T1 x ... x Tn -> T

dove S è lo "stato del mondo" T1, ..., Tn sono i tipi di parametri di input e T è il tipo di ritorno.

Per prima cosa provo a definire questa funzione. Se la funzione è parziale (ovvero ci sono alcuni valori di input per i quali non è definita) restituisco NULL per segnalarlo. Questo perché voglio che il calcolo termini normalmente e mi dica che la funzione che ho richiesto non è definita sugli input dati. L'uso, ad esempio, di una stringa vuota come valore di ritorno è ambiguo perché potrebbe essere che la funzione è definita sugli input e la stringa vuota è il risultato corretto.

Penso che il controllo extra per un puntatore NULL nel codice chiamante sia necessario perché stai applicando una funzione parziale ed è compito del metodo chiamato dirti se la funzione se non definita per l'input dato.

Preferisco utilizzare eccezioni per errori che non consentono di eseguire il calcolo (ovvero non è stato possibile trovare alcuna risposta).

Ad esempio, supponiamo di avere un cliente di classe e di voler implementare un metodo

Customer findCustomer(String customerCode)

per cercare un cliente nel database dell'applicazione tramite il suo codice. Con questo metodo, lo farei

  • Restituisce un oggetto di classe Cliente se la query ha esito positivo,
  • Restituisce null se la query non trova alcun cliente.
  • Generare un'eccezione se non è possibile connettersi al database.

I controlli extra per null, ad es

Customer customer = findCustomer("...");
if (customer != null && customer.getOrders() > 0)
{
    ...
}

fanno parte della semantica di ciò che sto facendo e non vorrei semplicemente "saltarli" per migliorare la lettura del codice. Non credo sia una buona pratica semplificare la semantica del problema a portata di mano solo per semplificare il codice.

Naturalmente, poiché il controllo per null si verifica molto spesso, è utile che la lingua supporti una sintassi speciale per esso.

Vorrei anche prendere in considerazione l'uso del modello Null Object (come suggerito da Laf) fintanto che posso distinguere l'oggetto null di una classe da tutti gli altri oggetti.


0

I metodi che restituiscono le raccolte dovrebbero restituire vuoti, ma altri potrebbero restituire null, perché per le raccolte potrebbe accadere che tu abbia un oggetto ma non ci sono elementi in esso, quindi il chiamante eseguirà la validazione solo per le dimensioni piuttosto che per entrambe.


0

Per me ci sono due casi qui. Se stai restituendo una sorta di elenco, dovresti sempre restituire l'elenco in ogni caso, vuoto se non hai nulla da inserire.

L'unico caso in cui vedo un dibattito è quando stai restituendo un singolo oggetto. Mi trovo a preferire restituire null in caso di fallimento in una situazione del genere sulla base del fallimento rapido delle cose.

Se si restituisce un oggetto null e il chiamante aveva bisogno di un oggetto reale, potrebbero andare avanti e provare a utilizzare l'oggetto null producendo comportamenti imprevisti. Penso che sia meglio che la routine diventi boom se dimenticano di affrontare la situazione. Se qualcosa non va, voglio un'eccezione APPENA POSSIBILE. È meno probabile che spedisca un bug in questo modo.


0

Aggiungendo a ciò che la gente ha già detto sul Maybecostruttore del tipo:

Un altro grande guadagno, a parte il fatto di non rischiare NPE, è quello semantico. Nel mondo funzionale, dove ci occupiamo di funzioni pure, ci piace provare a creare funzioni che, quando applicate, sono esattamente equivalenti al loro valore di ritorno . Si consideri il caso di String.reverse(): Questa è una funzione che data una determinata stringa rappresenta la versione inversa di quella stringa. Sappiamo che questa stringa esiste, perché ogni stringa può essere invertita (le stringhe sono essenzialmente insiemi di caratteri ordinati).

E adesso findCustomer(int id)? Questa funzione rappresenta il cliente che ha l'ID specificato. Questo è qualcosa che può o non può esistere. Ma ricorda, le funzioni hanno un unico valore di ritorno, quindi non puoi davvero dire "questa funzione restituisce un cliente con l'ID dato O restituisce null.

Questo è il mio problema principale sia con la restituzione che con la nullrestituzione di un oggetto null. Sono fuorvianti. nullnon è un cliente e non è nemmeno "l'assenza di un cliente". È l'assenza di NIENTE. È solo un puntatore senza nome a NIENTE. Livello molto basso, molto brutto e soggetto a errori. Un oggetto nullo è anche piuttosto fuorviante qui penso. Un cliente null È un cliente. Non è l'assenza di uno, non è il cliente con l'ID richiesto, quindi restituirlo è semplicemente SBAGLIATO. Questo NON è il cliente che ho richiesto, ma comunque pretendi di aver restituito un cliente. Ha un ID sbagliato, chiaramente questo è un bug. Rompe il contratto suggerito dal nome e dalla firma del metodo. Richiede che il codice client assuma elementi sulla progettazione o legga la documentazione.

Entrambi questi problemi sono risolti da a Maybe Customer. Improvvisamente, non stiamo dicendo "questa funzione rappresenta il cliente con l'ID specificato". Stiamo dicendo "questa funzione rappresenta il cliente con l'ID specificato se esiste . Ora è molto chiaro ed esplicito su ciò che fa. Se chiedi il cliente con un ID inesistente, riceverai Nothing. Come va meglio di null? Non solo per il rischio di NPE. Ma anche perché il tipo di Nothingnon è solo Maybe. È Maybe Customer. Ha un significato semantico. Significa specificamente "l'assenza di un cliente", indicando che tale cliente non esiste.

Un altro problema con null è ovviamente che è ambiguo. È che non hai trovato il cliente o c'è stato un errore di connessione db o non posso vedere quel cliente?

Se hai diversi casi di errore come questo da gestire, potresti generare eccezioni per quelle versioni o (e preferisco in questo modo) potresti restituire un Either CustomerLoadError Customer, che rappresenta qualcosa che è andato storto o il cliente restituito. Ha tutti i vantaggi di Maybe Customerconsentire anche di specificare cosa può andare storto.

La cosa principale che sto cercando è catturare il contratto della funzione nella sua firma. Non dare per scontato nulla, non fare affidamento su convenzioni fugaci, sii esplicito.


0

1) Se la funzione semantica è che non può restituire nulla, il chiamante DEVE testarlo, altrimenti es. prendi i tuoi soldi e non darli a nessuno.

2) È utile creare funzioni che semanticamente restituiscono sempre qualcosa (o lancio).

Con un logger , ha senso restituire un logger che non registra se non è stato definito alcun logger. Quando restituisce la raccolta, non ha quasi mai senso (tranne che a "livello abbastanza basso", in cui la raccolta stessa è I dati, non ciò che contiene) per non restituire nulla, perché un set vuoto è un set, non niente.

Con una persona ad esempio, vorrei andare "ibernazione" via (get vs carico, IIRC, ma è complicato da oggetti proxy per caricamento pigro) di avere due funzioni, una che restituisce null e la seconda che getta.


-1
  • NULL deve essere restituito se l'applicazione prevede che i dati siano disponibili ma i dati non sono disponibili. Ad esempio, un servizio che restituisce CITY in base al codice postale deve restituire null se la città non viene trovata. Il chiamante può quindi decidere di gestire il valore nullo o esplodere.

  • L'elenco vuoto deve essere restituito se ci sono due possibilità. Dati disponibili o NO dati disponibili. Ad esempio un servizio che restituisce le CITTA 'se la popolazione è maggiore di un certo numero. Può restituire un elenco vuoto se nessun dato soddisfa i criteri indicati.


-2

Returning NULL è un design terribile , nel mondo orientato agli oggetti. In breve, l'utilizzo di NULL porta a:

  • gestione degli errori ad hoc (anziché eccezioni)
  • semantico ambiguo
  • lento invece di fallimento veloce
  • pensiero del computer vs. pensiero dell'oggetto
  • oggetti mutabili e incompleti

Controlla questo post del blog per una spiegazione dettagliata: http://www.yegor256.com/2014/05/13/why-null-is-bad.html

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.