Eu posso ver que @Nullable
e @Nonnull
anotações pode ser útil na prevenção NullPointerException
s, mas eles não se propagam muito longe.
- A eficácia dessas anotações diminui completamente após um nível de indireção, portanto, se você adicionar apenas algumas, elas não se propagam muito longe.
- Como essas anotações não são bem aplicadas, existe o risco de assumir que um valor marcado com
@Nonnull
não é nulo e, consequentemente, não executa verificações nulas.
O código abaixo faz com que um parâmetro marcado com @Nonnull
seja null
sem apresentar nenhuma reclamação. Ele lança um NullPointerException
quando é executado.
public class Clazz {
public static void main(String[] args){
Clazz clazz = new Clazz();
// this line raises a complaint with the IDE (IntelliJ 11)
clazz.directPathToA(null);
// this line does not
clazz.indirectPathToA(null);
}
public void indirectPathToA(Integer y){
directPathToA(y);
}
public void directPathToA(@Nonnull Integer x){
x.toString(); // do stuff to x
}
}
Existe uma maneira de tornar essas anotações mais rigorosamente aplicadas e / ou propagar mais?
java
annotations
nullpointerexception
nullable
code-standards
Mike Rylander
fonte
fonte
@Nullable
ou@Nonnull
, mas se eles valem a pena é muito "provável que debate solicit"@Nonnull
chamar um@Nonnull
método com uma variável anulável. Obviamente, a conversão com uma anotação não é possível no Java 7, mas o Java 8 adicionará a capacidade de aplicar anotações ao uso de uma variável, incluindo projeções. Portanto, este pode tornar-se possível implementar em Java 8.(@NonNull Integer) y
é sintaticamente possível, mas um compilador não tem permissão para emitir nenhum código de byte específico com base na anotação. Para asserções de tempo de execução, pequenos métodos auxiliares são suficientes, conforme discutido em bugs.eclipse.org/442103 (por exemplo,directPathToA(assertNonNull(y))
) - mas lembre-se, isso só ajuda a falhar rapidamente. A única maneira segura é executar uma verificação nula real (além de, esperançosamente, uma implementação alternativa no ramo else).@Nonnull
e@Nullable
que você está falando, pois há vários annoations semelhantes (Veja esta pergunta ). Você está falando sobre as anotações no pacotejavax.annotation
?Respostas:
Resposta curta: acho que essas anotações são úteis apenas para o seu IDE avisar sobre erros de ponteiro potencialmente nulos.
Como dito no livro "Código Limpo", você deve verificar os parâmetros do seu método público e também evitar a verificação de invariantes.
Outra boa dica é nunca retornar valores nulos, mas usar Null Object Pattern .
fonte
Optional
tipo em vez de planícienull
Optional
e nulo neste caso é queOptional
comunica melhor que esse valor pode intencionalmente estar vazio. Certamente, não é uma varinha mágica e, no tempo de execução, pode falhar exatamente da mesma maneira que a variável anulável. No entanto, a recepção da API pelo programador é melhorOptional
na minha opinião.Além do seu IDE, fornecendo dicas quando você passa
null
para métodos que esperam que o argumento não seja nulo, há outras vantagens:Isso pode ajudar seu código a ser mais sustentável (já que você não precisa de
null
verificações) e menos propenso a erros.fonte
assert
. Acho@Nullable
e@Nonnull
para ser idéias úteis, mas gostaria de ter mais força por trás delas, em vez de questionarmos o que se poderia fazer com elas, o que ainda deixa em aberto a possibilidade de não fazer nada com elas.Eu acho que essa pergunta original aponta indiretamente para uma recomendação geral de que a verificação de ponteiro nulo em tempo de execução ainda é necessária, mesmo que o @NonNull seja usado. Consulte o seguinte link:
Novas anotações de tipo do Java 8
No blog acima, é recomendado que:
fonte
Compilando o exemplo original no Eclipse na conformidade 1.8 e com a análise nula baseada em anotação ativada, obtemos este aviso:
Esse aviso está redigido em analogia com os avisos que você recebe ao misturar código gerado com código herdado usando tipos brutos ("conversão não verificada"). Temos exatamente a mesma situação aqui: o método
indirectPathToA()
possui uma assinatura "herdada", pois não especifica nenhum contrato nulo. As ferramentas podem relatar isso facilmente, de modo que o perseguirão por todos os becos onde as anotações nulas precisam ser propagadas, mas ainda não são.E ao usar um inteligente
@NonNullByDefault
, nem precisamos dizer isso o tempo todo.Em outras palavras: se as anotações nulas "propagam-se muito longe" podem depender da ferramenta que você usa e de quão rigorosamente você atende a todos os avisos emitidos pela ferramenta. Com as anotações nulas TYPE_USE, você finalmente tem a opção de deixar a ferramenta avisá-lo sobre todos os NPE possíveis em seu programa, porque a nulidade se tornou uma propriedade intrínseca do sistema de tipos.
fonte
Concordo que as anotações "não se propagam muito longe". No entanto, vejo o erro do lado do programador.
Entendo a
Nonnull
anotação como documentação. O método a seguir expressa que requer (como pré-condição) um argumento não nulox
.O seguinte trecho de código contém um erro. O método chama
directPathToA()
sem impor quey
não seja nulo (ou seja, não garante a pré-condição do método chamado). Uma possibilidade é adicionar umaNonnull
anotação também aindirectPathToA()
(propagar a pré-condição). A possibilidade dois é verificar a nulidade dey
inindirectPathToA()
e evitar a chamada dedirectPathToA()
quandoy
é nulo.fonte
@Nonnull
que você temindirectPathToA(@Nonnull Integer y)
é uma prática ruim: você precisará fazer a propagação na pilha de chamadas completa (por isso, se você adicionar umnull
check-indirectPathToA()
, precisará substituir@Nonnull
por@Nullable
na pilha de chamadas completa). Isso seria um grande esforço de manutenção para grandes aplicações.O que faço em meus projetos é ativar a seguinte opção na inspeção de código "Condições e exceções constantes":
Sugira anotação @Nullable para métodos que possivelmente retornem nulos e relatem valores nulos passados para parâmetros não anotados
Quando ativado, todos os parâmetros não anotados serão tratados como não nulos e, portanto, você também verá um aviso em sua chamada indireta:
Para verificações ainda mais fortes, o Checker Framework pode ser uma boa opção (consulte este bom tutorial .
Nota : Eu ainda não o usei e pode haver problemas com o compilador Jack: consulte este relatório de erros
fonte
Em Java, eu usaria o tipo opcional do Guava . Sendo um tipo real, você obtém garantias do compilador sobre seu uso. É fácil ignorá-lo e obter um
NullPointerException
, mas pelo menos a assinatura do método comunica claramente o que ele espera como argumento ou o que ele pode retornar.fonte
java.util.Optional
vez da classe do Guava. Veja as notas / comparações da Goiaba para detalhes sobre as diferenças.Se você usar o Kotlin, ele suportará essas anotações de nulidade em seu compilador e impedirá que você passe um nulo para um método java que requer um argumento não nulo. Mesmo que essa pergunta tenha sido direcionada originalmente para Java, mencionei esse recurso do Kotlin porque ele é direcionado especificamente para essas anotações em Java e a pergunta era "Existe uma maneira de tornar essas anotações mais rigorosamente aplicadas e / ou se propagarem mais?" e esse recurso torna essas anotações mais rigorosamente aplicadas .
Classe Java usando
@NotNull
anotaçãoClasse Kotlin chamando a classe Java e passando nulo para o argumento anotado com @NotNull
Erro do compilador Kotlin ao aplicar a
@NotNull
anotação.consulte: http://kotlinlang.org/docs/reference/java-interop.html#nullability-annotations
fonte
myString.hashCode()
continuará lançando o NPE, mesmo que@NotNull
não seja adicionado ao parâmetro. Então, o que há de mais específico em adicioná-lo?Desde o novo recurso Java 8, opcional, você não deve usar @Nullable ou @Notnull em seu próprio código . Veja o exemplo abaixo:
Pode ser reescrito com:
Usar um opcional obriga a verificar o valor nulo . No código acima, você pode acessar o valor apenas chamando o
get
métodoOutra vantagem é que o código fica mais legível . Com a adição do Java 9 ifPresentOrElse , a função pode até ser escrita como:
fonte
Optional
, ainda existem muitas bibliotecas e estruturas que usam essas anotações, de forma que não é possível atualizar / substituir todas as suas dependências por versões atualizadas para usar Opcionais.Optional
no entanto, pode ajudar em situações em que você usa nulo em seu próprio código.