Estoy buscando hacer que mi código sea más legible, así como utilizar herramientas como la inspección de código IDE y / o el análisis de código estático (FindBugs y Sonar) para evitar NullPointerExceptions. Muchas de las herramientas parecen incompatibles con la @NotNull
/ @NonNull
/ @Nonnull
anotación de las demás y enumerarlas todas en mi código sería terrible de leer. ¿Alguna sugerencia de cuál es el "mejor"? Aquí está la lista de anotaciones equivalentes que he encontrado:
javax.validation.constraints.NotNull
Creado para la validación del tiempo de ejecución, no para el análisis estático.
documentaciónedu.umd.cs.findbugs.annotations.NonNull
Utilizado por Findbugs análisis estático y, por tanto, Sonar (ahora sonarqube )
la documentaciónjavax.annotation.Nonnull
Esto también podría funcionar con Findbugs, pero JSR-305 está inactivo. (Ver también: ¿Cuál es el estado de JSR 305? ) Fuenteorg.jetbrains.annotations.NotNull
Utilizado por IntelliJ IDEA IDE para el análisis estático.
documentaciónlombok.NonNull
Se usa para controlar la generación de código en el Proyecto Lombok .
Anotación de marcador de posición ya que no hay un estándar.
fuente , documentaciónandroid.support.annotation.NonNull
Anotación de marcador disponible en Android, proporcionada por la documentación del paquete de anotaciones de soporte
org.eclipse.jdt.annotation.NonNull
Utilizado por Eclipse para la documentación de análisis de código estático
fuente
com.sun.istack.internal.NotNull
. Dios mío ...Respuestas:
Dado que JSR 305 (cuyo objetivo era estandarizar
@NonNull
y@Nullable
) ha estado inactivo durante varios años, me temo que no hay una buena respuesta. Todo lo que podemos hacer es encontrar una solución pragmática y la mía es la siguiente:Sintaxis
Desde un punto de vista puramente estilístico, me gustaría evitar cualquier referencia a IDE, framework o cualquier kit de herramientas, excepto Java.
Esto descarta:
android.support.annotation
edu.umd.cs.findbugs.annotations
org.eclipse.jdt.annotation
org.jetbrains.annotations
org.checkerframework.checker.nullness.qual
lombok.NonNull
Lo que nos deja con
javax.validation.constraints
ojavax.annotation
. El primero viene con JEE. Si esto es mejor quejavax.annotation
, lo que podría ocurrir con JSE o nunca, es un tema de debate. Personalmente prefierojavax.annotation
porque no me gustaría la dependencia JEE.Esto nos deja con
javax.annotation
que es también el más corto
Sólo hay una sintaxis que incluso puede ser mejor:
java.annotation.Nullable
. A medida que otros paquetes se graduaron dejavax
ajava
en el pasado, la anotación javax sería un paso en la dirección correcta.Implementación
Esperaba que todos tuvieran básicamente la misma implementación trivial, pero un análisis detallado mostró que esto no es cierto.
Primero por las similitudes:
Las
@NonNull
anotaciones todos tienen la líneaexcepto por
org.jetbrains.annotations
que lo llama@NotNull
y tiene una implementación trivialjavax.annotation
que tiene una implementación más largajavax.validation.constraints
que también lo llama@NotNull
y tiene una implementaciónLas
@Nullable
anotaciones todos tienen la líneaa excepción de (nuevamente)
org.jetbrains.annotations
con su implementación trivial.Por las diferencias:
Una sorprendente es que
javax.annotation
javax.validation.constraints
org.checkerframework.checker.nullness.qual
todos tienen anotaciones de tiempo de ejecución (
@Retention(RUNTIME)
), mientras queandroid.support.annotation
edu.umd.cs.findbugs.annotations
org.eclipse.jdt.annotation
org.jetbrains.annotations
son solo tiempo de compilación (
@Retention(CLASS)
).Como se describe en esta respuesta SO, el impacto de las anotaciones de tiempo de ejecución es menor de lo que uno podría pensar, pero tienen el beneficio de permitir que las herramientas realicen comprobaciones de tiempo de ejecución además de las de tiempo de compilación.
Otra diferencia importante es dónde se pueden usar las anotaciones en el código. Hay dos enfoques diferentes. Algunos paquetes usan contextos de estilo JLS 9.6.4.1. La siguiente tabla ofrece una descripción general:
org.eclipse.jdt.annotation
,javax.annotation
yorg.checkerframework.checker.nullness.qual
use los contextos definidos en JLS 4.11, que en mi opinión es la forma correcta de hacerlo.Esto nos deja con
javax.annotation
org.checkerframework.checker.nullness.qual
en esta ronda
Código
Para ayudarlo a comparar más detalles usted mismo, enumero el código de cada anotación a continuación. Para facilitar la comparación, eliminé los comentarios, las importaciones y la
@Documented
anotación. (todos tenían a@Documented
excepción de las clases del paquete de Android). Reordené las líneas y los@Target
campos y normalicé las calificaciones.Para completar, aquí están las
@Nullable
implementaciones:Los siguientes dos paquetes no tienen
@Nullable
, así que los enumero por separado; Lombok tiene una muy aburrida@NonNull
. Enjavax.validation.constraints
la@NonNull
realidad es una@NotNull
y tiene una aplicación bastante largo.Apoyo
Desde mi experiencia,
javax.annotation
al menos es compatible con Eclipse y el Checker Framework listo para usar.Resumen
Mi anotación ideal sería la
java.annotation
sintaxis con la implementación de Checker Framework.Si no tiene la intención de utilizar el Checker Framework, el
javax.annotation
( JSR-305 ) sigue siendo su mejor apuesta por el momento.Si está dispuesto a comprar el Checker Framework, simplemente use su
org.checkerframework.checker.nullness.qual
.Fuentes
android.support.annotation
desdeandroid-5.1.1_r1.jar
edu.umd.cs.findbugs.annotations
desdefindbugs-annotations-1.0.0.jar
org.eclipse.jdt.annotation
desdeorg.eclipse.jdt.annotation_2.1.0.v20160418-1457.jar
org.jetbrains.annotations
desdejetbrains-annotations-13.0.jar
javax.annotation
desdegwt-dev-2.5.1-sources.jar
org.checkerframework.checker.nullness.qual
desdechecker-framework-2.1.9.zip
lombok
delombok
commitf6da35e4c4f3305ecd1b415e2ab1b9ef8a9120b4
javax.validation.constraints
desdevalidation-api-1.0.0.GA-sources.jar
fuente
javax.annotation
es que es a) basado en un JSR muerto, b) difícil de encontrar un artefacto que solo proporcione las anotaciones y se mantenga. El de findbugs no es: search.maven.org/…javax.annotation
es que causa problemas con Java 9 porque otros módulos también proporcionan clases en ese paquete (jax-ws).javax.annotation.NonNull
, nunca se completó porque su plomo de especificación quedó AWOL. No tuvo nada que ver con ninguna decisión de Oracle.Me gusta mucho el Checker Framework , que es una implementación de anotaciones de tipo ( JSR-308 ) que se usa para implementar verificadores de defectos como un verificador de nulidad. Realmente no he intentado ningún otro para ofrecer una comparación, pero me ha encantado esta implementación.
No estoy afiliado al grupo que ofrece el software, pero soy fanático.
Cuatro cosas que me gustan de este sistema:
Tiene un verificador de defectos de nulidad (@Nullable), pero también tiene unos de inmutabilidad e internamiento (y otros). Uso el primero (nulidad) y estoy tratando de usar el segundo (inmutabilidad / IGJ). Estoy probando el tercero, pero todavía no estoy seguro de usarlo a largo plazo. Todavía no estoy convencido de la utilidad general de los otros verificadores, pero es bueno saber que el marco en sí mismo es un sistema para implementar una variedad de anotaciones y verificadores adicionales.
La configuración predeterminada para la comprobación de nulidad funciona bien: no nulo excepto locales (NNEL). Básicamente, esto significa que, de forma predeterminada, el verificador trata todo (variables de instancia, parámetros de método, tipos genéricos, etc.) excepto las variables locales como si tuvieran un tipo @NonNull de forma predeterminada. Por la documentación:
Puede establecer un valor predeterminado diferente para una clase o un método si NNEL no funciona para usted.
Este marco le permite usarlo sin crear una dependencia en el marco al adjuntar sus anotaciones en un comentario: por ejemplo
/*@Nullable*/
. Esto es bueno porque puede anotar y verificar una biblioteca o código compartido, pero aún así puede usar esa biblioteca / código compartido en otro proyecto que no usa el marco. Esta es una buena característica. Me he acostumbrado a usarlo, aunque ahora tiendo a habilitar Checker Framework en todos mis proyectos.El marco tiene una forma de anotar las API que usa que aún no están anotadas por nulidad mediante el uso de archivos stub.
fuente
Yo uso el IntelliJ, porque me preocupa principalmente que IntelliJ marque cosas que podrían producir un NPE. Estoy de acuerdo en que es frustrante no tener una anotación estándar en el JDK. Se habla de agregarlo, podría llegar a Java 7. ¡En cuyo caso habrá uno más para elegir!
fuente
javax.annotation.Nonnull
es más ampliamente aceptado, ¿no es así?De acuerdo con la lista de características de Java 7, las anotaciones de tipo JSR-308 se difieren a Java 8. Las anotaciones de JSR-305 ni siquiera se mencionan.
Hay un poco de información sobre el estado de JSR-305 en un apéndice del último borrador de JSR-308. Esto incluye la observación de que las anotaciones JSR-305 parecen estar abandonadas. La página JSR-305 también lo muestra como "inactivo".
Mientras tanto, la respuesta pragmática es usar los tipos de anotación que son compatibles con las herramientas más utilizadas ... y estar preparado para cambiarlos si la situación cambia.
De hecho, JSR-308 no define ningún tipo / clase de anotación, y parece que piensan que está fuera de alcance. (Y tienen razón, dada la existencia de JSR-305).
Sin embargo, si parece que JSR-308 realmente llega a Java 8, no me sorprendería si el interés en JSR-305 reviviera. AFAIK, el equipo JSR-305 no ha abandonado formalmente su trabajo. Han estado callados por más de 2 años.
Es interesante que Bill Pugh (el líder tecnológico de JSR-305) sea uno de los tipos detrás de FindBugs.
fuente
Para proyectos de Android debes usar
android.support.annotation.NonNull
yandroid.support.annotation.Nullable
. Estas y otras anotaciones útiles específicas de Android están disponibles en la Biblioteca de soporte .Desde http://tools.android.com/tech-docs/support-annotations :
fuente
javax.annotation.*
anotaciones tambiénSi alguien solo está buscando las clases de IntelliJ: puede obtenerlas del repositorio de Maven con
fuente
JSR305 y FindBugs son creados por la misma persona. Ambos están mal mantenidos, pero son tan estándar como es posible y cuentan con el respaldo de todos los IDE principales. La buena noticia es que funcionan bien como están.
Aquí se explica cómo aplicar @Nonnull a todas las clases, métodos y campos de forma predeterminada. Ver https://stackoverflow.com/a/13319541/14731 y https://stackoverflow.com/a/9256595/14731
@NotNullByDefault
2. Agregue la anotación a cada paquete:
package-info.java
ACTUALIZACIÓN : A partir del 12 de diciembre de 2012, JSR 305 figura como "inactivo". De acuerdo con la documentación:
Parece que JSR 308 está llegando a JDK 8 y, aunque JSR no define a @NotNull, lo acompaña
Checkers Framework
. Al momento de escribir esto, el complemento Maven no se puede usar debido a este error: https://github.com/typetools/checker-framework/issues/183fuente
Distinguir entre análisis estático y análisis de tiempo de ejecución. Use análisis estático para cosas internas y análisis de tiempo de ejecución para los límites públicos de su código.
Para cosas que no deberían ser nulas:
Verificación de tiempo de ejecución: use "if (x == null) ..." (dependencia cero) o @ javax.validation.NotNull (con validación de bean) o @ lombok.NonNull (simple y simple) o Prevasditions de guayabas. .)
Comprobación estática: use una anotación @NonNull
Esto debería dar el mejor resultado: advertencias en el IDE, errores de Findbugs y checkerframework, excepciones significativas en tiempo de ejecución.
No espere que las comprobaciones estáticas sean maduras, su denominación no está estandarizada y diferentes bibliotecas e IDE los tratan de manera diferente, ignórelos. Las clases JSR305 javax.annotations. * Parecen estándar, pero no lo son, y causan paquetes divididos con Java9 +.
Algunas notas explicaciones:
Antes de Java9, esta es mi recomendación:
Tenga en cuenta que no hay forma de hacer que Spotbugs genere una advertencia cuando se desreferencia un parámetro de método anulable (en el momento de la escritura, versión 3.1 de Spotbugs). Quizás el checkerframework pueda hacer eso.
Lamentablemente, estas anotaciones no distinguen entre los casos de un método público de una biblioteca con sitios de llamadas arbitrarios y los métodos no públicos donde se puede conocer cada sitio de llamadas. Por lo tanto, el doble significado de: "Indica que nulo no es deseado, pero prepárate para que se pase nulo sin embargo" no es posible en una sola declaración, por lo tanto, el ejemplo anterior tiene diferentes anotaciones para la interfaz y la implementación.
Para los casos en que el enfoque de interfaz dividida no es práctico, el siguiente enfoque es un compromiso:
Esto ayuda a los clientes a no pasar nulo (escribir el código correcto), al tiempo que devuelve errores útiles si lo hacen.
fuente
Eclipse también tiene sus propias anotaciones.
Ver en http://wiki.eclipse.org/JDT_Core/Null_Analysis para más detalles.
fuente
Simplemente señalando que la API de Validación de Java (
javax.validation.constraints.*
) no viene con una@Nullable
anotación, lo cual es muy valioso en un contexto de análisis estático. Tiene sentido para la validación de beans de tiempo de ejecución, ya que este es el valor predeterminado para cualquier campo no primitivo en Java (es decir, nada que validar / aplicar). A los fines declarados que deberían pesar hacia las alternativas.fuente
Desafortunadamente,
JSR 308
no agregaré más valores que la sugerencia local No nula de este proyecto aquíJava 8
no vendrá con una sola anotación predeterminada o su propioChecker
marco. Similar a Find-bugs oJSR 305
, este JSR está mal mantenido por un pequeño grupo de equipos principalmente académicos.No hay poder comercial detrás de esto, por lo tanto, se
JSR 308
lanzaEDR 3
(Early Draft Review enJCP
) AHORA, mientrasJava 8
se supone que se enviará en menos de 6 meses: -O Similar a por310
cierto. pero a diferencia308 Oracle
de eso se ha hecho cargo de eso ahora lejos de sus fundadores para minimizar el daño que le hará a la Plataforma Java.Cada proyecto, proveedor y clase académica como los que están detrás de
Checker Framework
yJSR 308
crearán su propia anotación de corrector patentada.Haciendo código fuente incompatibles en los próximos años, hasta hace unos compromisos populares se podían encontrar y tal vez añaden a
Java 9
, o10
, o por medio de marcos comoApache Commons
oGoogle Guava
;-)fuente
Androide
Esta respuesta es específica de Android. Android tiene un paquete de soporte llamado
support-annotations
. Esto proporciona docenas de anotaciones específicas de Android y también proporciona comunes comoNonNull
,Nullable
etc.Para agregar el paquete de anotaciones de soporte , agregue la siguiente dependencia en su build.gradle:
y luego usa:
fuente
Mientras espera que esto se solucione en sentido ascendente (¿Java 8?), También podría definir su propio proyecto local
@NotNull
y@Nullable
anotaciones. Esto puede ser útil también en caso de que esté trabajando con Java SE, dondejavax.validation.constraints
no está disponible de forma predeterminada.Sin duda, esto sería en gran medida con fines decorativos o a prueba de futuro, ya que lo anterior obviamente no agrega en sí mismo ningún soporte para el análisis estático de estas anotaciones.
fuente
Si estás desarrollando para Android, eres algo vinculado a Eclipse (edición: al momento de escribir, ya no), que tiene sus propias anotaciones. Está incluido en Eclipse 3.8+ (Juno), pero está deshabilitado de forma predeterminada.
Puede habilitarlo en Preferencias> Java> Compilador> Errores / Advertencias> Análisis nulo (sección contraíble en la parte inferior).
Marque "Habilitar análisis nulo basado en anotaciones"
http://wiki.eclipse.org/JDT_Core/Null_Analysis#Usage tiene recomendaciones sobre la configuración. Sin embargo, si tiene proyectos externos en su espacio de trabajo (como el SDK de Facebook), es posible que no cumplan con esas recomendaciones, y probablemente no desee solucionarlos con cada actualización del SDK ;-)
Yo suelo:
fuente
@chaqke
.Si está trabajando en un proyecto grande, que puede ser mejor de crear su propio
@Nullable
y / o@NotNull
anotaciones.Por ejemplo:
Si usa la política de retención correcta , las anotaciones no estarán disponibles en tiempo de ejecución . Desde ese punto de vista, es solo una cosa interna .
Aunque esto no es una ciencia estricta, creo que tiene más sentido usar una clase interna para ello.
@Nullable
/ personalizadas@NotNull
.Preguntas adicionales (ver comentarios):
¿Cómo configurar esto en IntelliJ?
fuente
idea
no cuentes nada sobrevoid test(@NonNull String s) {}
llamado portest(null);
Ya hay demasiadas respuestas aquí, pero (a) es 2019, y todavía no hay un "estándar"
Nullable
y (b) ninguna otra respuesta hace referencia a Kotlin.La referencia a Kotlin es importante, porque Kotlin es 100% interoperable con Java y tiene una característica central de seguridad nula. Al llamar a las bibliotecas de Java, puede aprovechar esas anotaciones para informar a las herramientas de Kotlin si una API de Java puede aceptar o devolver
null
.Hasta donde yo sé, los únicos
Nullable
paquetes compatibles con Kotlin sonorg.jetbrains.annotations
yandroid.support.annotation
(ahoraandroidx.annotation
). Este último solo es compatible con Android, por lo que no se puede usar en proyectos JVM / Java / Kotlin que no sean Android. Sin embargo, el paquete JetBrains funciona en todas partes.Entonces, si desarrolla paquetes Java que también deberían funcionar en Android y Kotlin (y que sean compatibles con Android Studio e IntelliJ), su mejor opción es probablemente el paquete JetBrains.
Maven
Gradle:
fuente
Hay otra forma de hacer esto en Java 8. Estoy haciendo 2 cosas para lograr lo que necesitaba:
java.util.Optional
java.util.Objects.requireNonNull
Ejemplo:
Entonces mi pregunta es, ¿necesitamos incluso anotar cuando usamos Java 8?
Editar: descubrí más tarde que algunos consideran una mala práctica para usar
Optional
en argumentos, hay una buena discusión con pros y contras aquí ¿Por qué no debería usarse Java 8's Opcional en argumentos?Opción alternativa dado que no se recomienda usar Opcional en los argumentos, necesitamos 2 constructores:
fuente
new Role(null,null,null,null);
. Con las anotaciones, mi IDE y el análisis estático advertirán que no se puede pasar nulo a esos parámetros. Sin él, no lo descubro hasta que ejecuto el código. Ese es el valor de las anotaciones.description
no sea nulo y el código del cliente podría pasar una cadena vacía, pero en muchos casos podría ser útil distinguir entre una cadena vacía y no tener un valor. Gracias por tu comentario. Actualizaré la respuesta.¿El sol no tiene el suyo ahora? Qué es esto:
http://www.java2s.com/Open-Source/Java-Document/6.0-JDK-Modules-com.sun/istack/com.sun.istack.internal.htm
Esto parece estar empaquetado con todas las versiones de Java que he usado en los últimos años.
Editar: como se menciona en los comentarios a continuación, probablemente no quiera usarlos. En ese caso, ¡mi voto es por las anotaciones de IntelliJ jetbrains!
fuente
Una de las cosas buenas de IntelliJ es que no necesita usar sus anotaciones. Puede escribir la suya, o puede usar las de cualquier otra herramienta que desee. Ni siquiera estás limitado a un solo tipo. Si está utilizando dos bibliotecas que usan anotaciones @NotNull diferentes, puede decirle a IntelliJ que use ambas. Para hacer esto, vaya a "Configurar inspecciones", haga clic en la inspección "Condiciones constantes y excepciones" y presione el botón "Configurar inspecciones". Uso el Comprobador de nulidad siempre que puedo, así que configuré IntelliJ para usar esas anotaciones, pero puedes hacer que funcione con cualquier otra herramienta que desees. (No tengo opinión sobre las otras herramientas porque he estado usando las inspecciones de IntelliJ durante años, y me encantan).
fuente
Otra opción son las anotaciones proporcionadas con ANTLR 4. Luego de la solicitud de extracción # 434 , el artefacto que contiene las anotaciones
@NotNull
y@Nullable
incluye un procesador de anotaciones que produce errores y / o advertencias en tiempo de compilación en caso de que uno de estos atributos se use incorrectamente (por ejemplo, si ambos se aplican al mismo elemento, o si@Nullable
se aplica a un elemento con un tipo primitivo). El procesador de anotaciones proporciona una garantía adicional durante el proceso de desarrollo de software de que la información transmitida por la aplicación de estas anotaciones es precisa, incluso en casos de herencia de métodos.fuente
Si está compilando su aplicación utilizando Spring Framework, le sugiero que utilice
javax.validation.constraints.NotNull
Comming Beans Validation empaquetado en la siguiente dependencia:La principal ventaja de esta anotación es que Spring proporciona soporte tanto para los parámetros del método como para los campos de clase con anotaciones
javax.validation.constraints.NotNull
. Todo lo que necesita hacer para habilitar el soporte es:suministre el jar api para la validación de beans y jar con la implementación del validador de anotaciones jsr-303 / jsr-349 (que viene con la dependencia de Hibernate Validator 5.x):
proporcionar MethodValidationPostProcessor al contexto de spring
finalmente anota tus clases con Spring
org.springframework.validation.annotation.Validated
y Spring validará la validación automáticamente.Ejemplo:
Cuando intente llamar al método doSomething y pasar nulo como valor del parámetro, se lanzará spring (por medio de HibernateValidator)
ConstraintViolationException
. No es necesario trabajar manualmente aquí.También puede validar los valores de retorno.
Otro beneficio importante de
javax.validation.constraints.NotNull
venir para Beans Validation Framework es que, por el momento, todavía está desarrollado y se planean nuevas características para la nueva versión 2.0.¿Qué hay de
@Nullable
? No hay nada como eso en Beans Validation 1.1. Bueno, podría argumentar que si decides usarlo,@NotNull
todo lo que NO esté anotado@NonNull
es efectivamente "anulable", entonces la@Nullable
anotación es inútil.fuente
Spring 5 tiene @NonNullApi en el nivel del paquete. Esto parece una opción conveniente para un proyecto que ya tiene dependencias de Spring. Todos los campos, parámetros y valores de retorno predeterminados a @NonNull y @Nullable pueden aplicarse en los pocos lugares que difieren.
Archivo package-info.java:
https://docs.spring.io/spring-data/commons/docs/current/reference/html/#repositories.nullability.annotations
fuente