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/ @Nonnullanotació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
@NonNully@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.annotationedu.umd.cs.findbugs.annotationsorg.eclipse.jdt.annotationorg.jetbrains.annotationsorg.checkerframework.checker.nullness.quallombok.NonNullLo que nos deja con
javax.validation.constraintsojavax.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.annotationporque no me gustaría la dependencia JEE.Esto nos deja con
javax.annotationque 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 dejavaxajavaen 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
@NonNullanotaciones todos tienen la líneaexcepto por
org.jetbrains.annotationsque lo llama@NotNully tiene una implementación trivialjavax.annotationque tiene una implementación más largajavax.validation.constraintsque también lo llama@NotNully tiene una implementaciónLas
@Nullableanotaciones todos tienen la líneaa excepción de (nuevamente)
org.jetbrains.annotationscon su implementación trivial.Por las diferencias:
Una sorprendente es que
javax.annotationjavax.validation.constraintsorg.checkerframework.checker.nullness.qualtodos tienen anotaciones de tiempo de ejecución (
@Retention(RUNTIME)), mientras queandroid.support.annotationedu.umd.cs.findbugs.annotationsorg.eclipse.jdt.annotationorg.jetbrains.annotationsson 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:
MÉTODO DE CAMPO PARÁMETRO VARIABLE LOCAL android.support.annotation XXX edu.umd.cs.findbugs.annotations XXXX org.jetbrains.annotation XXXX lombok XXXX javax.validation.constraints XXXorg.eclipse.jdt.annotation,javax.annotationyorg.checkerframework.checker.nullness.qualuse los contextos definidos en JLS 4.11, que en mi opinión es la forma correcta de hacerlo.Esto nos deja con
javax.annotationorg.checkerframework.checker.nullness.qualen 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
@Documentedanotación. (todos tenían a@Documentedexcepción de las clases del paquete de Android). Reordené las líneas y los@Targetcampos y normalicé las calificaciones.Para completar, aquí están las
@Nullableimplementaciones:Los siguientes dos paquetes no tienen
@Nullable, así que los enumero por separado; Lombok tiene una muy aburrida@NonNull. Enjavax.validation.constraintsla@NonNullrealidad es una@NotNully tiene una aplicación bastante largo.Apoyo
Desde mi experiencia,
javax.annotational menos es compatible con Eclipse y el Checker Framework listo para usar.Resumen
Mi anotación ideal sería la
java.annotationsintaxis 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.annotationdesdeandroid-5.1.1_r1.jaredu.umd.cs.findbugs.annotationsdesdefindbugs-annotations-1.0.0.jarorg.eclipse.jdt.annotationdesdeorg.eclipse.jdt.annotation_2.1.0.v20160418-1457.jarorg.jetbrains.annotationsdesdejetbrains-annotations-13.0.jarjavax.annotationdesdegwt-dev-2.5.1-sources.jarorg.checkerframework.checker.nullness.qualdesdechecker-framework-2.1.9.ziplombokdelombokcommitf6da35e4c4f3305ecd1b415e2ab1b9ef8a9120b4javax.validation.constraintsdesdevalidation-api-1.0.0.GA-sources.jarfuente
javax.annotationes 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.annotationes 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.Nonnulles 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.NonNullyandroid.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
@NotNullByDefault2. Agregue la anotación a cada paquete:
package-info.javaACTUALIZACIÓ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@Nullableanotació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 308no agregaré más valores que la sugerencia local No nula de este proyecto aquíJava 8no vendrá con una sola anotación predeterminada o su propioCheckermarco. 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 308lanzaEDR 3(Early Draft Review enJCP) AHORA, mientrasJava 8se supone que se enviará en menos de 6 meses: -O Similar a por310cierto. pero a diferencia308 Oraclede 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 FrameworkyJSR 308creará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 CommonsoGoogle 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,Nullableetc.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
@NotNully@Nullableanotaciones. Esto puede ser útil también en caso de que esté trabajando con Java SE, dondejavax.validation.constraintsno 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
@Nullabley / o@NotNullanotaciones.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
ideano 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"
Nullabley (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
Nullablepaquetes compatibles con Kotlin sonorg.jetbrains.annotationsyandroid.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.Optionaljava.util.Objects.requireNonNullEjemplo:
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
Optionalen 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.descriptionno 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
@NotNully@Nullableincluye 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@Nullablese 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.NotNullComming 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.Validatedy 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.NotNullvenir 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,@NotNulltodo lo que NO esté anotado@NonNulles efectivamente "anulable", entonces la@Nullableanotació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