2011-01-24 4 views
9

ho qualche codice lungo il seguente schema:È uno stile sbagliato utilizzare NullPointerException per verificare null?

return a().b().c().d().e(); 

ora, poiché ognuno di questi metodi potrebbe tornare null, si potrebbe solito verificare questa:

if((a()!=null) && (a().b() != null) && ....) { 
    return a().b().c().d().e(); 
} else { 
    return null; 
} 

(e magari utilizzare alcune variabili locali al fine di evitare le chiamate duplicati)

mi verrebbe da fare:

try { 
    return a().b().c().d().e(); 
} catch (NullPointerException e) { 
    return null; 
} 

E 'considerato un cattivo stile? inefficiente? O abbastanza bene?

+0

Penso che sia male usare le eccezioni per controllare il flusso di controllo. – Sweeper

risposta

16

Non farlo. Lanciare e catturare le eccezioni è piuttosto costoso rispetto ai controlli null di base.

Potrebbe anche essere interessante sapere che la sintassi è stata proposta per una versione futura di Java che renderebbe questo più semplice. Sarebbe andare o meno così:

a()?.b()?.c()?.d() 

Il "?". operazione sarebbe una versione opzionale del "." operatore. Se LHS è nullo, restituisce null a quel punto invece di provare a valutare RHS. Esattamente quello che stai cercando, ma temo che non abbia fatto il taglio per Java 7. Non conosco lo stato di questa funzionalità per Java 8.

+0

Ma, se lo fa con un try-catch ... Quindi, qualunque cosa, funzionerà, lo sai. Perché non dovremmo usare una caratteristica un linguaggio di programmazione? E, sì, forse sarà un po 'più veloce controllarlo con assegni nulli, ma ancora: qualunque cosa, se la velocità non è importante ... –

+1

@Martijn Courteaux: La questione non è se la cattura di NPE funzionerebbe. Lo fa chiaramente. La domanda è se prendere l'abitudine di scrivere un codice come questo è una buona idea. Non lo è. –

1

Invece di restituire null, lasciare ciascuno di essi restituire NullObject o qualcosa del genere. Maggiori informazioni su Null Object Pattern.

+1

Sebbene l'oggetto Null possa essere utile, può nascondere alcuni problemi e rendere più difficile il debug. NON usarlo se l'unico guadagno è salvare un paio di test in un unico posto. – maaartinus

2

io non lo farei soprattutto perché quello che se a() o b() o c() ecc avere un bug che li induce a gettare NullPointerException? In quel caso lo stai prendendo e procedendo quando non dovresti avere.

2

Modificare i metodi in modo che non restituiscano null o evitare i metodi di concatenamento che possono restituire null.

5

È considerato uno stile errato perché le eccezioni rappresentano condizioni eccezionali, cose che non è probabile vengano generate durante l'esecuzione normale e che indicano che qualcosa è andato storto. L'utilizzo di eccezioni per verificare se gli oggetti sono nulli utilizza questo meccanismo per verificare ulteriori errori banali. Come menzionato dal post di Konstantin, c'è anche una penalità di runtime per l'utilizzo delle eccezioni. Inoltre, il raggruppamento di tutti gli errori in un singolo NullPointerException significa che si perdono le informazioni su ciò che è andato storto in particolare. Quale funzione ha restituito null? Era dovuto a errori normali o c'è qualcosa di più serio?

Ci sono altre opzioni che non hai considerato qui. Anziché avere a(), b(),, ecc. Restituire null per segnalare un errore, considerare di fare in modo che generino eccezioni più dettagliate spiegando perché non possono restituire qualcosa. Se falliscono a causa di una caduta della connessione di rete, fateli lanciare IOException s o qualcosa del genere. Se falliscono perché hai un cattivo indice in un array, chiariscilo pure.

In breve, se si desidera utilizzare le eccezioni, utilizzarle per comunicare con maggiore precisione al resto del programma cosa è successo. In questo modo, puoi intraprendere azioni correttive più fini.

5

In genere, questa riga di codice sarebbe danneggiata da sola, ignorando il problema nullo. Vedi lo "Law of Demeter" or "Principle of Least Knowledge".

return a().b().c().d().e(); 

Se avessi avuto alcun controllo su a, b, c, d ed e, vorrei riscrivere la seguente.

if((a()!=null) && (a().b() != null) && ....) { 
    return a().b().c().d().e(); 
} else { 
    return null; 
} 

come questo, che è ancora atroce, ma molto più utile quando qualcosa scombina e ho bisogno di leggere una traccia dello stack.

B b = a.a(); 
if(b == null) 
{ 
    return null; 
} 

C c = b.b(); 
if(c == null) 
{ 
    return null; 
} 

D d = c.c(); 
if(d == null) 
{ 
    return null; 
} 

return d.d(); 

No, la cattura NullPointerException non è una cosa giusta da fare. È un po 'come avvolgere un ciclo for in un blocco try per catturare ArrayIndexOutOfBoundsException.

Se questo dovrebbe essere un fluent API dove il concatenamento è una forza e un obiettivo, allora non dovrebbe mai restituire valori nulli.

+1

Sono generalmente d'accordo, ma non sempre hai una scelta, ad es. quando si utilizzano librerie di terze parti. Un altro caso in cui ciò può accadere molto è nei mapping di Object - Relation DB, ad esempio resultSet.getFirst(). GetPerson(). GetBusinessUnit(). GetAddress(). GetPostCode(); se lo schema DB consente informazioni molto parziali, questo caso può accadere molto. – Carsten

+0

+1 per il confronto di arrayindexoutofbounds, è azzeccato. – Epaga