Eu estou procurando tornar meu código mais legível e usar ferramentas como inspeção de código IDE e / ou análise de código estática (FindBugs e Sonar) para evitar NullPointerExceptions. Muitas das ferramentas parecem incompatíveis com a anotação / @NotNull
/ da outra e listar todas elas no meu código seria terrível de ler. Alguma sugestão de qual é o 'melhor'? Aqui está a lista de anotações equivalentes que encontrei:@NonNull
@Nonnull
javax.validation.constraints.NotNull
Criado para validação de tempo de execução, não para análise estática.
documentaçãoedu.umd.cs.findbugs.annotations.NonNull
Usado pela análise estática do Findbugs e, portanto, pela documentação do Sonar (agora Sonarqube )
javax.annotation.Nonnull
Isso também pode funcionar com o Findbugs, mas o JSR-305 está inativo. (Veja também: Qual é o status de JSR 305? ) Fonteorg.jetbrains.annotations.NotNull
Usado pelo IntelliJ IDEA IDE para análise estática.
documentaçãolombok.NonNull
Usado para controlar a geração de código no Project Lombok .
Anotação de espaço reservado, pois não há padrão.
fonte , documentaçãoandroid.support.annotation.NonNull
Anotação de marcador disponível no Android, fornecida pela documentação do pacote de anotações de suporte
org.eclipse.jdt.annotation.NonNull
Usado pelo Eclipse para documentação de análise de código estático
fonte
com.sun.istack.internal.NotNull
. OMG ... #Respostas:
Como o JSR 305 (cujo objetivo era padronizar
@NonNull
e@Nullable
) permanece inativo por vários anos, receio que não haja uma boa resposta. Tudo o que podemos fazer é encontrar uma solução pragmática e a minha é a seguinte:Sintaxe
Do ponto de vista puramente estilístico, eu gostaria de evitar qualquer referência ao IDE, framework ou qualquer kit de ferramentas, exceto o próprio Java.
Isso exclui:
android.support.annotation
edu.umd.cs.findbugs.annotations
org.eclipse.jdt.annotation
org.jetbrains.annotations
org.checkerframework.checker.nullness.qual
lombok.NonNull
O que nos deixa com
javax.validation.constraints
oujavax.annotation
. O primeiro vem com o JEE. Se isso é melhor do quejavax.annotation
, o que pode vir eventualmente com o JSE ou nunca, é uma questão de debate. Pessoalmente, prefirojavax.annotation
porque não gostaria da dependência do JEE.Isso nos deixa com
javax.annotation
que também é o mais curto.
Há apenas uma sintaxe que seria ainda melhor:
java.annotation.Nullable
. Como outros pacotes passaramjavax
parajava
o passado, a anotação javax.an seria um passo na direção certa.Implementação
Eu esperava que todos eles tivessem basicamente a mesma implementação trivial, mas uma análise detalhada mostrou que isso não é verdade.
Primeiro pelas semelhanças:
Todas as
@NonNull
anotações têm a linhaexceto por
org.jetbrains.annotations
que chama@NotNull
e tem uma implementação trivialjavax.annotation
que tem uma implementação mais longajavax.validation.constraints
que também chama@NotNull
e tem uma implementaçãoTodas as
@Nullable
anotações têm a linhaexceto (novamente) o
org.jetbrains.annotations
com sua implementação trivial.Para as diferenças:
Um impressionante é que
javax.annotation
javax.validation.constraints
org.checkerframework.checker.nullness.qual
todos têm anotações em tempo de execução (
@Retention(RUNTIME)
), enquantoandroid.support.annotation
edu.umd.cs.findbugs.annotations
org.eclipse.jdt.annotation
org.jetbrains.annotations
são apenas tempo de compilação (
@Retention(CLASS)
).Conforme descrito nesta resposta do SO, o impacto das anotações em tempo de execução é menor do que se imagina, mas elas têm o benefício de permitir que as ferramentas realizem verificações em tempo de execução, além das de tempo de compilação.
Outra diferença importante é onde no código as anotações podem ser usadas. Existem duas abordagens diferentes. Alguns pacotes usam contextos de estilo JLS 9.6.4.1. A tabela a seguir fornece uma visão geral:
org.eclipse.jdt.annotation
,javax.annotation
Eorg.checkerframework.checker.nullness.qual
usar os contextos definidos no JLS 4,11, o que na minha opinião é o caminho certo para fazê-lo.Isso nos deixa com
javax.annotation
org.checkerframework.checker.nullness.qual
nesta rodada.
Código
Para ajudá-lo a comparar mais detalhes, listo o código de todas as anotações abaixo. Para facilitar a comparação, removi comentários, importações e
@Documented
anotações. (todos eles tinham,@Documented
exceto as classes do pacote Android). Reordenei as linhas e os@Target
campos e normalizei as qualificações.Para completar, aqui estão as
@Nullable
implementações:Os dois pacotes a seguir não têm
@Nullable
, então eu os listo separadamente; Lombok é muito chato@NonNull
. Emjavax.validation.constraints
o@NonNull
é na verdade um@NotNull
e tem uma implementação comprido.Apoio, suporte
Pela minha experiência,
javax.annotation
é pelo menos suportado pelo Eclipse e pelo Checker Framework pronto para uso.Sumário
Minha anotação ideal seria a
java.annotation
sintaxe com a implementação do Checker Framework.Se você não pretende usar o Checker Framework, o
javax.annotation
( JSR-305 ) ainda é sua melhor aposta no momento.Se você deseja comprar o Checker Framework, basta usá-lo
org.checkerframework.checker.nullness.qual
.Fontes
android.support.annotation
deandroid-5.1.1_r1.jar
edu.umd.cs.findbugs.annotations
defindbugs-annotations-1.0.0.jar
org.eclipse.jdt.annotation
deorg.eclipse.jdt.annotation_2.1.0.v20160418-1457.jar
org.jetbrains.annotations
dejetbrains-annotations-13.0.jar
javax.annotation
degwt-dev-2.5.1-sources.jar
org.checkerframework.checker.nullness.qual
dechecker-framework-2.1.9.zip
lombok
delombok
confirmarf6da35e4c4f3305ecd1b415e2ab1b9ef8a9120b4
javax.validation.constraints
devalidation-api-1.0.0.GA-sources.jar
fonte
javax.annotation
é que é a) baseado em um JSR morto, b) difícil encontrar um artefato que apenas forneça as anotações e seja mantido. O de findbugs não é: search.maven.org/…javax.annotation
é que ele causa problemas com o Java 9 porque outros módulos também fornecem classes nesse pacote (jax-ws).javax.annotation.NonNull
, nunca foi concluído porque seu lead de especificação ficou em falta. Não teve nada a ver com nenhuma decisão da Oracle.Eu gosto muito do Checker Framework , que é uma implementação de anotações de tipo ( JSR-308 ), que é usada para implementar verificadores de defeitos como um verificador de nulidade. Eu realmente não tentei outros para oferecer nenhuma comparação, mas fiquei feliz com essa implementação.
Não sou afiliado ao grupo que oferece o software, mas sou fã.
Quatro coisas que eu gosto neste sistema:
Possui um verificador de defeitos para nulidade (@Nullable), mas também possui um para imutabilidade e internação (e outros). Eu uso o primeiro (nulidade) e estou tentando entrar no segundo (imutabilidade / IGJ). Estou testando o terceiro, mas ainda não tenho certeza sobre o uso a longo prazo. Ainda não estou convencido da utilidade geral dos outros verificadores, mas é bom saber que a estrutura em si é um sistema para implementar uma variedade de anotações e verificadores adicionais.
A configuração padrão para verificação de nulidade funciona bem: Não nulo, exceto locais (NNEL). Basicamente, isso significa que, por padrão, o verificador trata tudo (variáveis de instância, parâmetros de método, tipos genéricos, etc.), exceto variáveis locais, como se tivessem um tipo @NonNull por padrão. De acordo com a documentação:
Você pode definir um padrão diferente para uma classe ou método, se o NNEL não funcionar para você.
Essa estrutura permite que você use sem criar uma dependência da estrutura , colocando suas anotações em um comentário: por exemplo
/*@Nullable*/
. Isso é bom porque você pode anotar e verificar uma biblioteca ou código compartilhado, mas ainda pode usar essa biblioteca / código compartilhado em outro projeto que não usa a estrutura. Este é um bom recurso. Eu me acostumei a usá-lo, mesmo tendo a habilitar o Checker Framework em todos os meus projetos agora.A estrutura possui uma maneira de anotar APIs usadas que ainda não foram anotadas para nulidade usando arquivos stub.
fonte
Eu uso o IntelliJ, porque estou mais preocupado com o sinalizador do IntelliJ que pode produzir um NPE. Concordo que é frustrante não ter uma anotação padrão no JDK. Fala-se em adicioná-lo, ele pode chegar ao Java 7. Nesse caso, haverá mais um para escolher!
fonte
javax.annotation.Nonnull
é mais amplamente aceito, não é?De acordo com a lista de recursos do Java 7, as anotações do tipo JSR-308 são adiadas para o Java 8. As anotações do JSR-305 nem são mencionadas.
Há algumas informações sobre o estado do JSR-305 em um apêndice do rascunho mais recente do JSR-308. Isso inclui a observação de que as anotações do JSR-305 parecem abandonadas. A página JSR-305 também mostra como "inativa".
Nesse meio tempo, a resposta pragmática é usar os tipos de anotação suportados pelas ferramentas mais usadas ... e estar preparado para alterá-los se a situação mudar.
De fato, o JSR-308 não define nenhum tipo / classe de anotação e parece que eles acham que está fora do escopo. (E eles estão certos, dada a existência do JSR-305).
No entanto, se o JSR-308 realmente parecer entrar no Java 8, não me surpreenderia se o interesse no JSR-305 revivesse. AFAIK, a equipe JSR-305 não abandonou formalmente seu trabalho. Eles ficaram quietos por mais de 2 anos.
É interessante que Bill Pugh (o líder técnico do JSR-305) seja um dos responsáveis por FindBugs.
fonte
Para projetos Android, você deve usar
android.support.annotation.NonNull
eandroid.support.annotation.Nullable
. Essas e outras anotações úteis específicas do Android estão disponíveis na Biblioteca de suporte .Em http://tools.android.com/tech-docs/support-annotations :
fonte
javax.annotation.*
anotações tambémSe alguém estiver apenas procurando pelas classes IntelliJ: você pode obtê-las no repositório maven com
fonte
JSR305 e FindBugs são de autoria da mesma pessoa. Ambos são mal mantidos, mas são tão padrão quanto possível e são suportados por todos os principais IDEs. A boa notícia é que eles funcionam bem como estão.
Aqui está como aplicar o @Nonnull a todas as classes, métodos e campos por padrão. Consulte https://stackoverflow.com/a/13319541/14731 e https://stackoverflow.com/a/9256595/14731
@NotNullByDefault
2. Adicione a anotação a cada pacote:
package-info.java
ATUALIZAÇÃO : em 12 de dezembro de 2012, o JSR 305 está listado como "Inativo". De acordo com a documentação:
Parece que o JSR 308 está entrando no JDK 8 e, embora o JSR não defina @NotNull, o acompanhamento o
Checkers Framework
faz. No momento da redação deste artigo, o plug-in Maven não pode ser usado devido a este bug: https://github.com/typetools/checker-framework/issues/183fonte
Distinguir entre análise estática e análise de tempo de execução. Use análise estática para coisas internas e análise de tempo de execução para os limites públicos do seu código.
Para coisas que não devem ser nulas:
Verificação de tempo de execução: use "if (x == null) ..." (dependência zero) ou @ javax.validation.NotNull (com validação de bean) ou @ lombok.NonNull (puro e simples) ou goiabas Preconditions.checkNotNull (.. .)
Verificação estática: use uma anotação @NonNull
Isso deve fornecer o melhor resultado: avisos no IDE, erros de Findbugs e checkerframework, exceções significativas de tempo de execução.
Não espere que as verificações estáticas sejam maduras, sua nomeação não é padronizada e as bibliotecas e IDEs diferentes as tratam de maneira diferente, ignorando-as. As classes javax.annotations. * Do JSR305 parecem padrão, mas não são, e causam pacotes divididos com o Java9 +.
Algumas notas explicativas:
Antes do Java9, esta é minha recomendação:
Observe que não há como fazer com que os Spotbugs gerem um aviso quando um parâmetro de método anulável é desreferenciado (no momento da redação, versão 3.1 do Spotbugs). Talvez o checkerframework possa fazer isso.
Infelizmente, essas anotações não fazem distinção entre os casos de um método público de uma biblioteca com chamadas arbitrárias e métodos não públicos nos quais cada site de chamada pode ser conhecido. Portanto, o duplo significado de: "Indique que nulo é indesejável, mas prepare-se para que nulo seja passado" não é possível em uma única declaração; portanto, o exemplo acima tem anotações diferentes para a interface e a implementação.
Nos casos em que a abordagem de interface dividida não é prática, a seguinte abordagem é um compromisso:
Isso ajuda os clientes a não passarem nulos (escrevendo o código correto), enquanto retornam erros úteis, se o fizerem.
fonte
O Eclipse também possui suas próprias anotações.
Veja em http://wiki.eclipse.org/JDT_Core/Null_Analysis para obter detalhes.
fonte
Apenas salientando que a Java Validation API (
javax.validation.constraints.*
) não vem com uma@Nullable
anotação, que é muito valiosa em um contexto de análise estática. Faz sentido para validação de bean de tempo de execução, pois esse é o padrão para qualquer campo não primitivo em Java (ou seja, nada para validar / impor). Para os fins declarados, isso deve pesar em relação às alternativas.fonte
Infelizmente,
JSR 308
não adicionamos mais valores que a sugestão local Não Nula do projeto aquiJava 8
não virá com uma única anotação padrão ou sua própriaChecker
estrutura. Semelhante ao Find-bugs ouJSR 305
, esse JSR é mal mantido por um pequeno grupo de equipes principalmente acadêmicas.Nenhum poder comercial por trás dele, portanto, é
JSR 308
lançadoEDR 3
(Early Draft Review àsJCP
) NOW, enquantoJava 8
é esperado que ele seja entregue em menos de 6 meses: -O Similar ao310
btw. mas, ao contrário308 Oracle
, se encarregou disso agora de seus fundadores para minimizar os danos causados à plataforma Java.Todo projeto, fornecedor e classe acadêmica, como os que estão por trás
Checker Framework
eJSR 308
criarão sua própria anotação de verificador proprietário.Tornar o código fonte incompatível nos próximos anos, até que alguns compromissos populares possam ser encontrados e talvez adicionados a
Java 9
ou10
, ou através de estruturas comoApache Commons
ouGoogle Guava
;-)fonte
Android
Esta resposta é específica para Android. O Android possui um pacote de suporte chamado
support-annotations
. Isto fornece dezenas de específicas Android anotações e também fornece mais comuns comoNonNull
,Nullable
etc.Para adicionar um pacote de anotações de suporte , adicione a seguinte dependência em seu build.gradle:
e então use:
fonte
Enquanto espera que isso seja resolvido a montante (Java 8?), Você também pode definir seu próprio projeto-local
@NotNull
e@Nullable
anotações. Isso pode ser útil também no caso de você estar trabalhando com o Java SE, ondejavax.validation.constraints
não está disponível por padrão.É certo que isso seria em grande parte para fins decorativos ou à prova de futuro, uma vez que o exposto acima obviamente não adiciona nenhum suporte à análise estática dessas anotações.
fonte
Se você está desenvolvendo para o Android, está um pouco vinculado ao Eclipse (editar: no momento da redação, não mais), que possui suas próprias anotações. Está incluído no Eclipse 3.8+ (Juno), mas desativado por padrão.
Você pode habilitá-lo em Preferências> Java> Compilador> Erros / Avisos> Análise nula (seção recolhível na parte inferior).
Marque "Ativar análise nula baseada em anotação"
http://wiki.eclipse.org/JDT_Core/Null_Analysis#Usage possui recomendações sobre configurações. No entanto, se você tiver projetos externos em sua área de trabalho (como o SDK do facebook), eles podem não atender a essas recomendações e você provavelmente não deseja corrigi-los a cada atualização do SDK ;-)
Eu uso:
fonte
@chaqke
.Se você estiver trabalhando em um grande projeto, talvez seja melhor criar suas próprias
@Nullable
e / ou@NotNull
anotações.Por exemplo:
Se você usar a política de retenção correta , as anotações não estarão disponíveis no tempo de execução . Desse ponto de vista, é apenas uma coisa interna .
Mesmo que essa não seja uma ciência estrita, acho que faz mais sentido usar uma classe interna para ela.
@Nullable
/ personalizadas@NotNull
.Perguntas adicionais (ver comentários):
Como configurar isso no IntelliJ?
fonte
idea
não conte nada sobrevoid test(@NonNull String s) {}
chamado portest(null);
Já existem muitas respostas aqui, mas (a) é 2019 e ainda não há "padrão"
Nullable
e (b) nenhuma outra resposta faz referência ao Kotlin.A referência ao Kotlin é importante, porque o Kotlin é 100% interoperável com Java e possui um recurso básico de Segurança Nula. Ao chamar as bibliotecas Java, é possível aproveitar essas anotações para informar às ferramentas do Kotlin se uma API Java pode aceitar ou retornar
null
.Até onde eu sei, os únicos
Nullable
pacotes compatíveis com o Kotlin sãoorg.jetbrains.annotations
eandroid.support.annotation
(agoraandroidx.annotation
). O último é compatível apenas com o Android, portanto não pode ser usado em projetos JVM / Java / Kotlin que não sejam do Android. No entanto, o pacote JetBrains funciona em qualquer lugar.Portanto, se você desenvolver pacotes Java que também funcionem no Android e Kotlin (e sejam suportados pelo Android Studio e IntelliJ), sua melhor opção provavelmente será o pacote JetBrains.
Maven:
Gradle:
fonte
Há outra maneira de fazer isso no Java 8. Estou fazendo duas coisas para realizar o que precisava:
java.util.Optional
java.util.Objects.requireNonNull
Exemplo:
Então, minha pergunta é: precisamos fazer anotações ao usar o java 8?
Edit: Descobri mais tarde que alguns consideram uma prática ruim usar
Optional
em argumentos, há uma boa discussão com prós e contras aqui. Por que o Java 8's Optional não deve ser usado em argumentosOpção alternativa, considerando que não é recomendado usar Opcional nos argumentos, precisamos de 2 construtores:
fonte
new Role(null,null,null,null);
. Com as anotações, meu IDE e análise estática alertam que nulo não pode ser passado para esses parâmetros. Sem ele, não descubro até executar o código. Esse é o valor das anotações.description
nulo e o código do cliente pode passar uma String vazia, mas em muitos casos pode ser útil distinguir entre String vazia e não ter valor. Obrigado por seu comentário. Vou atualizar a resposta.O sol não tem o seu agora? O que é isso:
http://www.java2s.com/Open-Source/Java-Document/6.0-JDK-Modules-com.sun/istack/com.sun.istack.internal.htm
Isso parece estar incluído em todas as versões do Java que usei nos últimos anos.
Editar: Como mencionado nos comentários abaixo, você provavelmente não deseja usá-los. Nesse caso, meu voto é para as anotações do IntelliJ jetbrains!
fonte
Uma das coisas boas do IntelliJ é que você não precisa usar as anotações. Você pode escrever o seu próprio ou pode usar os de qualquer outra ferramenta que desejar. Você nem está limitado a um único tipo. Se você estiver usando duas bibliotecas que usam anotações @NotNull diferentes, poderá dizer ao IntelliJ para usar as duas. Para fazer isso, vá para "Configurar inspeções", clique na inspeção "Constantes condições e exceções" e clique no botão "Configurar inspeções". Eu uso o Verificador de Nulidade sempre que posso, então configurei o IntelliJ para usar essas anotações, mas você pode fazê-lo funcionar com qualquer outra ferramenta que você desejar. (Não tenho opinião sobre as outras ferramentas porque uso as inspeções do IntelliJ há anos e as amo.)
fonte
Outra opção são as anotações fornecidas com o ANTLR 4. Após a solicitação de recebimento nº 434 , o artefato que contém as anotações
@NotNull
e@Nullable
inclui um processador de anotações que produz erros e / ou avisos em tempo de compilação no caso de um desses atributos ser mal utilizado (por exemplo, se ambos são aplicados ao mesmo item ou se@Nullable
forem aplicados ao item com um tipo primitivo). O processador de anotação fornece garantia adicional durante o processo de desenvolvimento de software de que as informações transmitidas pela aplicação dessas anotações são precisas, inclusive nos casos de herança de método.fonte
Se você estiver construindo seu aplicativo usando o Spring Framework, sugiro o uso
javax.validation.constraints.NotNull
da validação do Beans empacotada na seguinte dependência:A principal vantagem desta anotação é que o Spring fornece suporte para parâmetros de método e campos de classe anotados
javax.validation.constraints.NotNull
. Tudo o que você precisa fazer para ativar o suporte é:forneça o jar api para validação de beans e jar com a implementação do validador das anotações jsr-303 / jsr-349 (que vem com a dependência do Hibernate Validator 5.x):
forneça MethodValidationPostProcessor ao contexto de spring
finalmente, você anota suas aulas com o Spring
org.springframework.validation.annotation.Validated
e a validação será automaticamente tratada pelo Spring.Exemplo:
Quando você tenta chamar o método doSomething e passa null como o valor do parâmetro, a mola (por meio do HibernateValidator) será lançada
ConstraintViolationException
. Não há necessidade de trabalho manual aqui.Você também pode validar valores de retorno.
Outro benefício importante de
javax.validation.constraints.NotNull
vir para o Beans Validation Framework é que, no momento, ele ainda está desenvolvido e novos recursos estão planejados para a nova versão 2.0.Que tal
@Nullable
? Não há nada parecido na Validação de Beans 1.1. Bem, eu poderia argumentar que, se você decidir usar,@NotNull
tudo o que NÃO é anotado@NonNull
é efetivamente "anulável", portanto a@Nullable
anotação é inútil.fonte
A primavera 5 tem @NonNullApi no nível do pacote. Parece uma escolha conveniente para um projeto que já possui dependências do Spring. Todos os campos, parâmetros e valores de retorno padrão para @NonNull e @Nullable podem ser aplicados nos poucos locais que diferem.
Arquivo package-info.java:
https://docs.spring.io/spring-data/commons/docs/current/reference/html/#repositories.nullability.annotations
fonte