Controlla i parametri annotati con @Nonnull per null?

19

Abbiamo iniziato a utilizzare FindBugs e ad annotare i nostri parametri con @Nonnull in modo appropriato, e funziona ottimo per segnalare bug all'inizio del ciclo. Finora abbiamo continuato a controllare questi argomenti per null usando checkNotNull di Guava, ma preferirei controllare null solo ai bordi - luoghi in cui il valore può entrare senza essere stato controllato per null , ad esempio, una richiesta SOAP.

// service layer accessible from outside
public Person createPerson(@CheckForNull String name) {
    return new Person(Preconditions.checkNotNull(name));
}

...

// internal constructor accessed only by the service layer
public Person(@Nonnull String name) {
    this.name = Preconditions.checkNotNull(name);  // remove this check?
}

Capisco che @Nonnull non blocchi null valori stessi.

Tuttavia, dato che FindBugs indica ovunque un valore viene trasferito da un campo non marcato a uno marcato @Nonnull , non possiamo dipendere da esso per catturare questi casi (che fa) senza dover controllare questi valori per null ovunque vengano passati in giro nel sistema? Sono ingenuo per voler fidarmi dello strumento ed evitare questi controlli dettagliati?

In conclusione: Mentre sembra sicuro rimuovere il secondo controllo null di seguito, è una cattiva pratica?

Questa domanda è forse troppo simile a Si dovrebbe verificare null se non si aspetta nulla , ma sto chiedendo specificamente in relazione all'annotazione @Nonnull .

    
posta David Harkness 10.10.2012 - 23:37
fonte

2 risposte

6

Se non ti fidi di FindBug, potrebbe essere un'opzione per usare un'asserzione. In questo modo si evitano i problemi menzionati dagli User MSalters ma si ha comunque un controllo. Ovviamente, questo approccio potrebbe non essere applicabile se un approccio di tipo "fail-fast" non è fattibile, cioè devi prendere qualche eccezione.

E per rispondere ulteriormente alla domanda se sia una cattiva pratica. Bene, questo è discutibile ma non lo penserei. Considero questa annotazione FindBug come una specifica di luce seguendo il principio della progettazione per contratto.

Nella progettazione per contratto si stabilisce un contratto tra un metodo e il relativo chiamante. Il contratto è costituito da precondizioni che il chiamante accetta di adempiere quando chiama il metodo e una post-condizione che a sua volta è soddisfatta dal metodo dopo l'esecuzione se il suo presupposto è soddisfatto.

Uno dei vantaggi di questo metodo di sviluppo è la possibilità di evitare un cosiddetto stile di programmazione difensivo (in cui si controllano esplicitamente tutti i valori dei parametri non validi, ecc.). Invece puoi fare affidamento sul contratto ed evitare controlli ridondanti per aumentare le prestazioni e la leggibilità.

I contratti possono essere utilizzati per il controllo di asserzione di runtime che segue il principio di fail-first sopra menzionato in cui si desidera che il programma fallisca se un contratto viene interrotto, fornendo un indizio per identificare l'origine dell'errore. (Una precondizione fallita significa che il chiamante ha fatto qualcosa di sbagliato, una postazione non riuscita indica un errore di implementazione del metodo dato)

Inoltre, i contratti possono essere utilizzati per l'analisi statica, che tenta di trarre conclusioni sul codice sorgente senza eseguirlo.

L'annotazione @nonnull può essere vista come una precondizione che viene utilizzata per l'analisi statica dallo strumento FindBugs. Se si preferisce un approccio come il controllo di asserzione di runtime, ovvero la prima strategia fallita, si dovrebbe prendere in considerazione l'uso di istruzioni di asserzione come Java integrato. O forse per adattarsi a una strategia specifica più sofisticata utilizzando un linguaggio di specifica dell'interfaccia comportamentale come il JML (Java Modeling Language).

JML è un'estensione di Java in cui le specifiche sono incorporate in speciali commenti Java. Un vantaggio di questo approccio è che è possibile utilizzare specifiche sofisticate, anche utilizzando un approccio di sviluppo in cui si fa affidamento solo sulle specifiche piuttosto che sui dettagli dell'implementazione e si utilizzano strumenti diversi che fanno uso delle specifiche, come i menzionati strumenti di verifica dell'asserzione di runtime, generazione automatizzata di unit test o documentazione.

Se condividi il mio punto di vista sul fatto che @nonnull sia un contratto (leggero), sarebbe prassi comune non aggiungere ulteriori controlli perché l'idea originale alla base di questo principio è di evitare la programmazione difensiva.

    
risposta data 18.10.2012 - 00:44
fonte
4

Bene, considera perché non scrivi

this.name = Preconditions.checkNotNull(name);  // Might be necessary
that.name = Preconditions.checkNotNull(this.name);  // Who knows?

La programmazione non è magia nera. Le variabili non diventano improvvisamente Null. Se sai che una variabile non è Null e sai che non è stata modificata, allora not controllala.

Se lo controlli, alcuni programmatori in futuro (forse tu) impiegheranno molto tempo a scoprire perché quel controllo è lì. Il controllo deve essere lì per un motivo, dopo tutto, quindi cosa stai trascurando?

    
risposta data 11.10.2012 - 16:47
fonte

Leggi altre domande sui tag