java - studio - android support annotation nullable
¿Cómo usar las anotaciones @Nullable y @Nonnull de manera más efectiva? (8)
Puedo ver que las anotaciones @Nullable
y @Nonnull
pueden ser útiles para evitar NullPointerException
, pero no se propagan muy lejos.
- La eficacia de estas anotaciones cae completamente después de un nivel de indirección, por lo que si solo agregas algunas, no se propagan demasiado.
- Como estas anotaciones no se aplican correctamente, existe el peligro de suponer que un valor marcado con
@Nonnull
no es nulo y, en consecuencia, no realiza comprobaciones nulas.
El siguiente código hace que un parámetro marcado con @Nonnull
sea null
sin presentar ninguna queja. NullPointerException
una NullPointerException
cuando se ejecuta.
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
}
}
¿Hay alguna forma de hacer que estas anotaciones se apliquen y / o propaguen más estrictamente?
Además de IDE que le da sugerencias de que pasa null
donde se espera que no sea nulo, tiene otras ventajas:
- Las herramientas de análisis de código estático pueden probar lo mismo que su IDE (por ejemplo, FindBugs).
- Puedes usar AOP para verificar estas afirmaciones.
Por lo tanto, puede ayudar a crear código que sea más fácil de mantener (no necesita verificaciones null
) y menos propenso a errores.
Al compilar el ejemplo original en Eclipse en conformidad 1.8 y con el análisis nulo basado en anotaciones, obtenemos esta advertencia:
directPathToA(y);
^
Null type safety (type annotations): The expression of type ''Integer'' needs unchecked conversion to conform to ''@NonNull Integer''
Esta advertencia está redactada de forma análoga a las advertencias que recibe cuando mezcla código genérico con código heredado usando tipos sin formato ("conversión sin marcar"). Aquí tenemos exactamente la misma situación: el método indirectPathToA()
tiene una firma "heredada" en el sentido de que no especifica ningún contrato nulo. Las herramientas pueden informar fácilmente esto, por lo que te perseguirán por todos los callejones donde las anotaciones nulas necesitan ser propagadas pero aún no lo son.
Y cuando usamos un @NonNullByDefault
inteligente, ni siquiera tenemos que decir esto cada vez.
En otras palabras: si las anotaciones nulas "se propagan muy lejos" puede depender de la herramienta que utilice y de cuán rigurosamente atienda todas las advertencias emitidas por la herramienta. Con las anotaciones nulas TYPE_USE , finalmente tiene la opción de permitir que la herramienta le advierta sobre cada NPE posible en su programa, ya que la nulidad se ha convertido en una propiedad intrínseca del sistema de tipos.
Creo que esta pregunta original apunta indirectamente a una recomendación general de que todavía se necesita la verificación del puntero nulo en tiempo de ejecución, aunque se utiliza @NonNull. Consulte el siguiente enlace:
Nuevas anotaciones tipo de Java 8
En el blog anterior, se recomienda que:
Las anotaciones de tipo opcional no son un sustituto de la validación en tiempo de ejecución Antes de las anotaciones de tipo, la ubicación principal para describir cosas como la nulabilidad o rangos estaba en el javadoc. Con las anotaciones Tipo, esta comunicación entra en el bytecode de una manera para la verificación en tiempo de compilación. Su código aún debe realizar la validación en tiempo de ejecución.
En Java, usaría el tipo opcional de Guava . Al ser un tipo real, obtienes garantías del compilador sobre su uso. Es fácil omitirlo y obtener una NullPointerException
, pero al menos la firma del método comunica claramente lo que espera como argumento o lo que podría devolver.
Estoy de acuerdo en que las anotaciones "no se propagan muy lejos". Sin embargo, veo el error del lado del programador.
Entiendo la anotación Nonnull
como documentación. El siguiente método expresa que se requiere (como precondición) un argumento no nulo x
.
public void directPathToA(@Nonnull Integer x){
x.toString(); // do stuff to x
}
El siguiente fragmento de código contiene un error. El método llama a directPathToA()
sin hacer cumplir que y
no es nulo (es decir, no garantiza la condición previa del método llamado). Una posibilidad es agregar una anotación Nonnull
también a indirectPathToA()
(propagando la precondición). La posibilidad dos es verificar la nulidad de y
en indirectPathToA()
y evitar la llamada a directPathToA()
cuando y
es nulo.
public void indirectPathToA(Integer y){
directPathToA(y);
}
Lo que hago en mis proyectos es activar la siguiente opción en la inspección del código "Condiciones constantes y excepciones":
Sugiera la anotación @Nullable para los métodos que posiblemente devuelven nulo e informe valores anulables pasados a parámetros no anotados
Cuando se activa, todos los parámetros no anotados se tratarán como no nulos y, por lo tanto, también verá una advertencia en su llamada indirecta:
clazz.indirectPathToA(null);
Para verificaciones aún más fuertes, Checker Framework puede ser una buena opción (vea este bonito tutorial .
Nota : Todavía no lo he usado y puede haber problemas con el compilador de Jack: mira este informe de errores
Respuesta corta: supongo que estas anotaciones solo son útiles para su IDE para avisarle de posibles errores de puntero nulos.
Como se dice en el libro "Código limpio", debe verificar los parámetros de su método público y también evitar comprobar invariantes.
Otro buen consejo es nunca devolver valores nulos, sino usar el Patrón de Objeto Nulo en su lugar.
Si usa Kotlin, admite estas anotaciones de anulabilidad en su compilador y le impedirá pasar un valor nulo a un método de Java que requiera un argumento no nulo. Aunque esta pregunta se orientó originalmente a Java, mencioné esta característica de Kotlin porque está específicamente dirigida a estas anotaciones de Java y la pregunta era "¿Hay alguna manera de hacer que estas anotaciones se apliquen y / o propaguen más estrictamente?" y esta característica hace que estas anotaciones sean más estrictamente aplicadas .
Clase Java con la anotación @NotNull
public class MyJavaClazz {
public void foo(@NotNull String myString) {
// will result in an NPE if myString is null
myString.hashCode();
}
}
Clase Kotlin que llama a la clase Java y pasa nulo para el argumento anotado con @NotNull
class MyKotlinClazz {
fun foo() {
MyJavaClazz().foo(null)
}
}
Error del compilador de Kotlin que impone la anotación @NotNull
.
Error:(5, 27) Kotlin: Null can not be a value of a non-null type String
ver: http://kotlinlang.org/docs/reference/java-interop.html#nullability-annotations