Se non ti fidi di FindBug, potrebbe essere un'opzione per usare un'asserzione. In questo modo si evitano i problemi menzionati da User MSalter ma si ha ancora un controllo. Naturalmente, questo approccio potrebbe non essere applicabile se non è possibile adottare un approccio così rapido, vale a dire che è necessario cogliere qualsiasi eccezione.
E per rispondere ulteriormente alla domanda se si tratta di una cattiva pratica. Bene, questo è discutibile ma non lo penserei. Considero questa annotazione FindBug come una specifica leggera che segue il principio di progettazione per contratto.
Nella progettazione per contratto si stabilisce un contratto tra un metodo e il suo chiamante. Il contratto consiste in precondizioni che il chiamante accetta di soddisfare quando chiama il metodo e una postcondizione che a sua volta viene soddisfatta dal metodo dopo l'esecuzione se la sua condizione preliminare è soddisfatta.
Uno dei vantaggi di questo metodo di sviluppo è che puoi evitare un cosiddetto stile di programmazione difensiva (in cui controlli esplicitamente tutti i valori dei parametri non validi ecc.). Puoi invece fare affidamento sul contratto ed evitare controlli ridondanti per aumentare le prestazioni e la leggibilità.
I contratti possono essere utilizzati per il controllo delle asserzioni di runtime che segue il principio fail-first sopra menzionato in base al quale si desidera che il programma fallisca in caso di violazione di un contratto, fornendo un indizio per identificare l'origine dell'errore. (Una precondizione non riuscita significa che il chiamante ha fatto qualcosa di sbagliato, una postcondizione 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 effettivamente.
L'annotazione @nonnull può essere vista come una condizione preliminare utilizzata per l'analisi statica dallo strumento FindBugs. Se si preferisce un approccio come il controllo delle asserzioni di runtime, ovvero la prima strategia di insuccesso, è necessario considerare l'utilizzo delle istruzioni di asserzione come Java integrato. O forse per adattarsi a una strategia di specifica più sofisticata utilizzando un linguaggio di specifica dell'interfaccia comportamentale come Java Modeling Language (JML).
JML è un'estensione di Java in cui le specifiche sono incorporate in speciali commenti Java. Un vantaggio di questo approccio è che puoi utilizzare specifiche sofisticate, anche utilizzando un approccio di sviluppo in cui ti affidi solo alle specifiche anziché ai dettagli di implementazione e usi diversi strumenti che fanno uso delle specifiche, come gli strumenti di controllo delle asserzioni di runtime menzionati, generazione automatizzata di unit test o documentazione.
Se condividi il mio punto di vista sul fatto che @nonnull sia un contratto (leggero), sarebbe pratica comune non aggiungere ulteriori controlli perché l'idea originale alla base di questo principio è quella di evitare la programmazione difensiva.
@Nonnull
: come una specifica del contratto. Ho rimosso i controlli difensivi dietro il contratto e finora non ho avuto problemi.