¡A nadie le gusta NullPointerException! ¿Hay alguna forma de evitarlos? Tal vez. .
Este artículo discutirá las siguientes tecnologías.
1.Tipo opcional (recientemente introducido en Java 8)
2.Clase de objetos (original en Java 7)
Clase opcional en Java 8
¿qué es?
1. Nuevos tipos introducidos en Java 8
2. Se utiliza como contenedor para un objeto de un tipo específico o para escenarios donde no existe ningún objeto (nulo).
En pocas palabras, es una mejor alternativa para manejar valores nulos (advertencia: puede que no sea tan obvio a primera vista)
Uso básico
Es un tipo (una clase). Entonces, ¿cómo se crea una instancia de este tipo?
Simplemente use sus tres métodos estáticos:
Copie el código de código de la siguiente manera:
público estático Opcional<Cadena> cadenaOpcional(Entrada de cadena) {
return Opcional.de(entrada);
}
Simple y claro: cree un contenedor opcional que contenga este valor. Recuerde: si este valor es nulo, generará NPE.
Copie el código de código de la siguiente manera:
public static Opcional<String> stringNullableOptional(entrada de cadena) {
if (!new Aleatorio().nextBoolean()) {
entrada = nulo;
}
return Opcional.ofNullable(entrada);
}
Personalmente creo que es mejor. De esta manera no habrá riesgo de NPE: si la entrada es nula, se devolverá un Opcional vacío.
Copie el código de código de la siguiente manera:
público estático Opcional<Cadena> vacíoOpcional() {
return Opcional.empty();
}
Si realmente solo desea devolver un valor "nulo". Un valor "vacío" no significa nulo.
Bien, entonces, ¿cómo consumir/usar Opcional?
Copie el código de código de la siguiente manera:
público estático vacío consumiendoOptional() {
Opcional<Cadena> envuelto = Opcional.of("aString");
si (envuelto.isPresent()) {
System.out.println("Se obtuvo la cadena - " + envuelto.get());
}
demás {
System.out.println("¡Te tengo!");
}
}
La forma más sencilla es comprobar si el contenedor opcional realmente tiene un valor (utilizando el método isPresent). Te preguntarás qué ventaja tiene esto sobre el uso de if(myObj! = null). No te preocupes, te lo explicaré claramente.
Copie el código de código de la siguiente manera:
vacío estático público consumiendoNullableOptional() {
Entrada de cadena = nulo;
si (nuevo Aleatorio().nextBoolean()) {
entrada = "iCanBeNull";
}
Opcional<Cadena> envuelto = Opcional.ofNullable(entrada);
System.out.println(wrapped.orElse("predeterminado"));
}
Puede utilizar el método orElse, de modo que si el valor encapsulado es realmente un valor nulo, pueda utilizarlo para devolver un valor predeterminado; sus beneficios son obvios. Al extraer el valor real, puede evitar el método obviamente redundante de llamar al método ifPresent.
Copie el código de código de la siguiente manera:
vacío estático público consumiendoEmptyOptional() {
Entrada de cadena = nulo;
si (nuevo Aleatorio().nextBoolean()) {
entrada = "iCanBeNull";
}
Opcional<Cadena> envuelto = Opcional.ofNullable(entrada);
System.out.println(wrapped.orElseGet(
() -> {
devolver "predeterminadoPorProveedor";
}
));
}
Estoy un poco confundido acerca de esto. ¿Por qué existen dos métodos diferentes para el mismo propósito? Obviamente, orElse y orElseGet se pueden sobrecargar (con el mismo nombre pero con diferentes parámetros).
De todos modos, la diferencia obvia entre estos dos métodos son sus parámetros: puede optar por utilizar expresiones lambda en lugar de instancias de Proveedor para lograr esto (una interfaz funcional).
¿Por qué usar Opcional es mejor que la verificación nula común?
1. La mayor ventaja de usar Opcional es que puede expresar su intención más claramente: devolver un valor nulo confundirá a los consumidores (cuando ocurre NPE) si esto se devuelve intencionalmente, por lo que debe verificar la posición del javadoc para obtener más detalles. . Usar Opcional es bastante sencillo.
2. Con Opcional, puede evitar completamente la NPE; como se mencionó anteriormente, usar Opcional.ofNullable, orElse y orElseGet puede mantenernos alejados de la NPE.
¡Otro salvador!
Eche un vistazo a este fragmento de código y copie el código a continuación:
paquete com.abhirockzz.wordpress.npesaviors;
importar java.util.Map;
importar java.util.Objects;
clase pública UsandoObjetos {
String getVal(Map<String, String> aMap, String key) {
devolver aMap.containsKey (clave)? aMap.get (clave): nulo;
}
público estático vacío principal (String [] argumentos) {
UsandoObjetos obj = nuevo UsandoObjetos();
obj.getVal(nulo, "ficticio");
}
}
¿Cuál podría estar vacío?
1.Objeto de mapa
2. Clave utilizada para la búsqueda
3. Esta instancia de llamada a método.
Si se lanza NPE, ¿cómo podemos determinar cuál es nulo?
Copie el código de código de la siguiente manera:
paquete com.abhirockzz.wordpress.npesaviors;
importar java.util.Map;
importar java.util.Objects;
clase pública UsandoObjetos {
String getValSafe(Map<String, String> aMap, String key) {
Mapa<Cadena, Cadena> safeMap = Objects.requireNonNull(aMap,
"El mapa es nulo");
String safeKey = Objects.requireNonNull(clave, "La clave es nula");
devolver safeMap.containsKey(safeKey)? safeMap.get(safeKey): nulo;
}
público estático vacío principal (String [] argumentos) {
UsandoObjetos obj = nuevo UsandoObjetos();
obj.getValSafe(nulo, "ficticio");
}
}
método requireNonNull
1. Si el objeto no es nulo, regresa solo
2. Si el valor es nulo, el NPE devuelto tendrá el mensaje especificado.
¿Por qué es mejor que if(myObj!=null)?
El seguimiento de la pila que ve verá claramente la llamada al método Objects.requireNonNull. Esto, combinado con su propio registro de errores, puede permitirle localizar el problema más rápidamente. . . Al menos en mi opinión es más rápido.
También puede personalizar su propio validador, como implementar un validador simple para garantizar que no haya valores nulos.
Copie el código de código de la siguiente manera:
importar java.util.Collections;
importar java.util.List;
importar java.util.Objects;
importar java.util.function.Predicate;
clase pública RandomGist {
public static <T> T requireNonEmpty(objeto T, predicado <T> predicado, cadena msgToCaller){
Objetos.requireNonNull(objeto);
Objects.requireNonNull(predicado);
si (predicado.prueba(objeto)){
lanzar una nueva IllegalArgumentException (msgToCaller);
}
objeto de retorno;
}
público estático vacío principal (String [] argumentos) {
//Uso 1: una cadena vacía (intencional)
Cadena s = "";
System.out.println(requireNonEmpty(Objects.requireNonNull(s), (s1) -> s1.isEmpty(), "¡Mi cadena está vacía!"));
//Uso 2: una lista vacía (intencional)
Lista lista = Collections.emptyList();
System.out.println(requireNonEmpty(Objects.requireNonNull(lista), (l) -> l.isEmpty(), "¡La lista está vacía!").size());
//Uso 3: un usuario vacío (intencional)
Usuario usuario = nuevo Usuario("");
System.out.println(requireNonEmpty(Objects.requireNonNull(usuario), (u) -> u.getName().isEmpty(), "¡El usuario está vacío!"));
}
Usuario de clase estática privada {
nombre de cadena privada;
Usuario público (nombre de cadena) {
this.nombre = nombre;
}
cadena pública getName(){
nombre de retorno;
}
}
}
No permita que la NPE se convierta en un dolor en el lugar equivocado. ¡Tenemos muchas herramientas para abordar mejor las NPE e incluso erradicarlas por completo!