He notado que muchos métodos Java 8 en Oracle JDK usan Objects.requireNonNull()
, que arroja internamente NullPointerException
si el objeto (argumento) es null
.
public static <T> T requireNonNull(T obj) {
if (obj == null)
throw new NullPointerException();
return obj;
}
Pero NullPointerException
será arrojado de todos modos si null
se desreferencia un objeto. Entonces, ¿por qué debería uno hacer esta comprobación nula adicional y lanzar
NullPointerException
?
Una respuesta obvia (o beneficio) es que hace que el código sea más legible y estoy de acuerdo. Estoy interesado en conocer otras razones para usar
Objects.requireNonNull()
al comienzo del método.
java
java-8
nullpointerexception
usuario4686046
fuente
fuente
Objects.requireNonNull
, su código no tiene ramificación, por lo que una sola pasada de una prueba unitaria obtendrá una cobertura del 100% :-)Respuestas:
Porque puedes hacer las cosas explícitas al hacerlo. Me gusta:
O más corto:
Ahora ya sabes :
new()
Compare eso con: usted crea un objeto Foo hoy, y mañana invoca un método que usa ese campo y lanza. ¡Lo más probable es que mañana no sepas por qué esa referencia fue nula ayer cuando se pasó al constructor!
En otras palabras: al usar explícitamente este método para verificar las referencias entrantes , puede controlar el punto en el tiempo en que se lanzará la excepción. Y la mayoría de las veces, ¡quieres fallar lo más rápido posible !
Las principales ventajas son:
bar
no es nulo, ¡y por lo tanto no necesita ningúnif (bar == null)
control en otros lugares!fuente
this.bar = Objects.requireNonNull(bar, "bar must not be null");
Objects.requireNonNull(bar, "bar must not be null");
. Gracias por estethis.bar = Objects.requireNonNull(bar, "bar must not be null");
es aceptable en los constructores, pero potencialmente peligroso en otros métodos, si dos o más variables se establecen en el mismo método. Ejemplo: talkwards.com/2018/11/03/…Fallar rapido
El código debería bloquearse lo antes posible. No debe hacer la mitad del trabajo y luego desreferenciar el valor nulo y bloquearse, solo dejando la mitad del trabajo realizado, haciendo que el sistema esté en un estado no válido.
Esto se conoce comúnmente como "falla temprana" o "falla rápida" .
fuente
Significa que detecta el problema de forma inmediata y confiable .
Considerar:
.NET mejora esto separando
NullReferenceException
("desreferenciado un valor nulo") deArgumentNullException
("no debería haber pasado nulo como argumento, y fue por este parámetro). Desearía que Java hiciera lo mismo, pero incluso con soloNullPointerException
que, aún es mucho más fácil corregir el código si el error se produce lo antes posible en el que se puede detectar.fuente
El uso de las
requireNonNull()
primeras declaraciones en un método permite identificar ahora / rápidamente la causa de la excepción.El seguimiento de la pila indica claramente que la excepción se produjo tan pronto como se introdujo el método porque la persona que llamó no respetó los requisitos / contrato. Pasar un
null
objeto a otro método puede provocar una excepción a la vez, pero la causa del problema puede ser más complicada de entender ya que la excepción se lanzará en una invocación específica sobre elnull
objeto que puede estar mucho más lejos.Aquí hay un ejemplo concreto y real que muestra por qué tenemos que favorecer el fracaso rápido en general y más particularmente el uso
Object.requireNonNull()
o cualquier forma de realizar una verificación no nula en los parámetros diseñados para no serlonull
.Supongamos que una
Dictionary
clase que compone unaLookupService
y unaList
deString
representación de palabras contenidas en. Estos campos están diseñados para ser nonull
y uno de ellos se pasa en elDictionary
constructor.Ahora suponga una implementación "incorrecta"
Dictionary
sinnull
verificación en la entrada del método (aquí está el constructor):Ahora, invoquemos al
Dictionary
constructor con unanull
referencia para elwords
parámetro:La JVM arroja el NPE a esta declaración:
La excepción se desencadena en la
LookupService
clase mientras que su origen es bastante anterior (elDictionary
constructor). Hace que el análisis general del problema sea mucho menos obvio.Es
words
null
? Eswords.get(0) null
? Ambos ? ¿Por qué el uno, el otro o tal vez ambos sonnull
? ¿Es un error de codificación enDictionary
(constructor? Método invocado?)? ¿Es un error de codificaciónLookupService
? (¿constructor? ¿método invocado?)?Finalmente, tendremos que inspeccionar más código para encontrar el origen del error y, en una clase más compleja, tal vez incluso usar un depurador para comprender más fácilmente lo que sucedió.
Pero, ¿por qué una cosa simple (la falta de verificación nula) se convierte en un problema complejo?
Debido a que permitimos el error / falta inicial identificable en una fuga de componente específico en componentes inferiores.
Imagine que
LookupService
no se trata de un servicio local, sino de un servicio remoto o de una biblioteca de terceros con poca información de depuración o imagine que no tenía 2 capas, sino 4 o 5 capas de invocaciones de objetos antes de quenull
se detectara. El problema sería aún más complejo de analizar.Entonces la forma de favorecer es:
De esta manera, no hay dolor de cabeza: recibimos la excepción tan pronto como se recibe:
Tenga en cuenta que aquí ilustré el problema con un constructor, pero una invocación de método podría tener la misma restricción de comprobación no nula.
fuente
Como nota al margen, este fallo rápido antes
Object#requireNotNull
se implementó ligeramente diferente antes de java-9 dentro de algunas de las clases jre. Supongamos el caso:En java-8 esto se compila como (solo las partes relevantes)
Básicamente una operación como:
yourReference.getClass
- que fallaría si yourRefercence esnull
.Las cosas han cambiado en jdk-9, donde se compila el mismo código que
O básicamente
Objects.requireNotNull (yourReference)
fuente
El uso básico es comprobar y lanzar de
NullPointerException
inmediato.Una mejor alternativa (acceso directo) para satisfacer el mismo requisito es la anotación @NonNull de lombok.
fuente
Se genera una excepción de puntero nulo cuando accede a un miembro de un objeto que se encuentra
null
en un punto posterior.Objects.requireNonNull()
comprueba inmediatamente el valor y lanza una excepción al instante sin avanzar.fuente
Creo que debería usarse en constructores de copias y algunos otros casos como DI cuyo parámetro de entrada es un objeto, debe verificar si el parámetro es nulo. En tales circunstancias, puede usar este método estático convenientemente.
fuente
En el contexto de las extensiones del compilador que implementan la comprobación de Nullability (por ejemplo: uber / NullAway ),
Objects.requireNonNull
debe usarse con moderación para ocasiones en las que tiene un campo anulable que sabe que no es nulo en un determinado punto de su código.De esta manera, hay dos usos principales:
Validación
Marcado de nulabilidad (cambio de @Nullable a @Nonnull)
Ejemplo de uso de marcado de nulabilidad:
fuente
Además de todas las respuestas correctas:
Lo usamos en flujos reactivos. Por lo general, los
NullpointerException
s resultantes se envuelven en otras Excepciones dependiendo de su ocurrencia en la secuencia. Por lo tanto, luego podemos decidir fácilmente cómo manejar el error.Solo un ejemplo: imagina que tienes
donde
parseAndValidate
envuelve elNullPointerException
derequireNonNull
aParsingException
.Ahora puede decidir, por ejemplo, cuándo reintentar o no:
Sin la comprobación, la excepción NullPointerException se producirá en el
save
método, lo que dará como resultado un sinfín de reintentos. Incluso vale la pena, imagine una suscripción de larga duración, agregandoAhora
RetryExhaustException
matará tu suscripción.fuente