Se você não confia no FindBug, pode ser uma opção para usar uma asserção. Dessa forma, você evita os problemas mencionados pelo User MSalters, mas ainda tem uma verificação. Obviamente, essa abordagem pode não ser aplicável se tal abordagem à prova de falhas não for viável, ou seja, você precisará capturar qualquer exceção.
E para responder ainda mais à pergunta se é uma má prática. Bem, isso é discutível, mas eu não pensaria assim. Considero essa anotação do FindBug como uma especificação leve, seguindo o princípio do design por contrato.
No design por contrato, você estabelece um contrato entre um método e seu chamador. O contrato consiste em pré-condições que o chamador concorda em cumprir ao chamar o método e em uma pós-condição que, por sua vez, é cumprida pelo método após a execução, se sua pré-condição for atendida.
Um dos benefícios desse método de desenvolvimento é que você pode evitar o chamado estilo de programação defensiva (no qual você verifica explicitamente todos os valores de parâmetros inválidos etc.). Em vez disso, você pode confiar no contrato e evitar verificações redundantes para aumentar o desempenho e a legibilidade.
Os contratos podem ser usados para a verificação da asserção de tempo de execução, que segue o princípio de falha-primeiro mencionado acima, no qual você deseja que seu programa falhe se um contrato for quebrado, fornecendo uma pista para identificar a origem do erro. (Uma pré-condição com falha significa que o chamador fez algo errado, uma pós-condição com falha indica um erro de implementação do método fornecido)
Além disso, os contratos podem ser usados para análise estática, que tenta tirar conclusões sobre o código fonte sem realmente executá-lo.
A anotação @nonnull pode ser vista como uma pré-condição usada para análise estática pela ferramenta FindBugs. Se você preferir uma abordagem como a verificação de asserção de tempo de execução, ou seja, a estratégia de falha em primeiro lugar, considere o uso de instruções de asserção como Java interno. Ou talvez para se adaptar a uma estratégia de especificação mais sofisticada usando uma linguagem de especificação de interface comportamental, como a Java Modeling Language (JML).
JML é uma extensão do Java na qual a especificação é incorporada em Comentários Java especiais. Uma vantagem dessa abordagem é que você pode usar especificações sofisticadas, mesmo usando uma abordagem de desenvolvimento na qual confia apenas nas especificações, e não nos detalhes da implementação, e utiliza diferentes ferramentas que fazem uso da especificação, como as mencionadas ferramentas de verificação de asserção de tempo de execução, geração automatizada de testes de unidade ou documentação.
Se você compartilhar meu ponto de vista de @nonnull como um contrato (leve), seria uma prática comum não adicionar verificações adicionais, porque a idéia original por trás desse princípio é evitar a programação defensiva.
@Nonnull
: como uma especificação de contrato. Venho removendo os cheques defensivos por trás do contrato e até agora não tive problemas.