Nuevas funciones de JDK8: explicación detallada del uso de la clase opcional

I. Descripción general

        Creo que NullPointerException es familiar para todos los programadores de JAVA y es la excepción más común en las aplicaciones JAVA. Anteriormente, el proyecto Google Guava propuso usar la clase Opcional para envolver objetos y resolver NullPointerException. Afectado por esto, la clase Opcional también se introdujo en las clases JDK8, y el soporte para este método se implementó en la nueva versión de SpringData Jpa y Spring Redis Data.

2. Clase opcional

/**
 * A container object which may or may not contain a non-null value.
 * If a value is present, {@code isPresent()} will return {@code true} and
 * {@code get()} will return the value.
 *
 * @since 1.8
 */
public final class Optional<T> {
    /**
     * Common instance for {@code empty()}.
     */
    private static final Optional<?> EMPTY = new Optional<>();

    /**
     * If non-null, the value; if null, indicates no value is present
     */
    private final T value;

   // 其他省略
}

La anotación de este método significa aproximadamente: Opcional es un objeto contenedor, que puede contener valores nulos o no nulos. Cuando se establece el valor del atributo, el método isPesent() devolverá verdadero y el método get() devolverá este valor. ​ Esta clase admite genéricos, es decir, el valor de su atributo puede ser una instancia de cualquier objeto.

3. Métodos de clase opcional.

número de serie método Descripción del método
1 private Optional() Construcción sin parámetros, construye un Opcional vacío
2 private Optional(T value) Cree un opcional basado en el valor pasado no vacío
3 public static<T> Optional<T> empty() Devuelve un Opcional vacío, el valor de esta instancia está vacío
4 public static <T> Optional<T> of(T value) Construya un Opcional basado en el valor pasado no vacío, que tiene el mismo efecto que el método Opcional (valor T)
5 public static <T> Optional<T> ofNullable(T value) A diferencia del método of(valor T), ofNullable(valor T) le permite pasar un valor vacío. Cuando el valor pasado es un valor nulo, crea un opcional vacío. Cuando el valor pasado no está vacío, es lo mismo que de () tiene el mismo efecto
6 public T get() Devuelve el valor de Opcional. Si el contenedor está vacío, se lanza una NoSuchElementException.
7 public boolean isPresent() Determinar si se ha establecido el valor del Opcional del propietario
8 public void ifPresent(Consumer<? super T> consumer) Determine si el Opcional del propietario ha establecido un valor. Si hay un valor, llame a la interfaz funcional del Consumidor para su procesamiento.
9 public Optional<T> filter(Predicate<? super T> predicate) Si se establece un valor y se cumplen las condiciones de juicio del Predicado, se devuelve el Opcional; de lo contrario, se devuelve un Opcional vacío.
10 public<U> Optional<U> map(Function<? super T, ? extends U> mapper) Si Opcional establece un valor, llame a la Función para procesar el valor y devolver un Opcional que contenga el valor procesado; de lo contrario, se devuelve un Opcional vacío.
11 public<U> Optional<U> flatMap(Function<? super T, Optional<U>> mapper) A diferencia del tipo de método map(), el resultado del asignador ya es opcional y no es necesario ajustar el resultado.
12 public T orElse(T other) Si el valor Opcional no está vacío, devuelve ese valor; de lo contrario, devuelve otro
13 public T orElseGet(Supplier<? extends T> other) Si el valor Opcional no está vacío, devuelva este valor; de lo contrario, genere otro basado en otros
14 public <X extends Throwable> T orElseThrow(Supplier<? extends X> exceptionSupplier)throws X Si el valor Opcional no está vacío, devuelve el valor; de lo contrario, lanza una excepción a través del proveedor.

4. Ejemplos de métodos de la clase Opcional.

Ejemplo uno:

public static void main(String[] args) {
  Optional< String > fullName = Optional.ofNullable( null );
  System.out.println( "Full Name is set? " + fullName.isPresent() );
  System.out.println( "Full Name: " + fullName.orElseGet( () -> "[none]" ) );
  System.out.println( fullName.map( s -> "Hey " + s + "!" ).orElse( "Hey Stranger!" ) );
 }

resultado de la operación:

Full Name is set? false
Full Name: [none]
Hey Stranger!

ilustrar:

ifPresent()方法当Optional实例的值非空时返回true,否则返回false;
orElseGet()方法当Optional包含非空值时返回该值,否则通过接收的function生成一个默认的;
map()方法转换当前Optional的值,并返回一个新的Optional实例;
orElse()方法与orElseGet方法相似,不同的是orElse()直接返回传入的默认值。

Ejemplo dos:

        Modifique el ejemplo 1 para generar una instancia opcional con un valor no nulo.

Optional< String > firstName = Optional.of( "Tom" );
System.out.println( "First Name is set? " + firstName.isPresent() );
System.out.println( "First Name: " + firstName.orElseGet( () -> "[none]" ) );
System.out.println( firstName.map( s -> "Hey " + s + "!" ).orElse( "Hey Stranger!" ) );

resultado de la operación:

First Name is set? true
First Name: Tom
Hey Tom!

La diferencia con el ejemplo 1 se puede ver claramente. Esto no solo simplifica nuestro código, sino que también lo hace más fácil de leer.

5.Código fuente opcional

        Echemos un vistazo al código fuente de varios métodos utilizados en el ejemplo:

de

public static <T> Optional<T> of(T value) {
  return new Optional<>(value);
 }

está presente

public boolean isPresent() {
   return value != null;
}

o si no, obtener

public T orElseGet(Supplier<? extends T> other) {
    return value != null ? value : other.get();
}

si no

public T orElse(T other) {
    return value != null ? value : other;
}

6. Utilice Opcional para evitar punteros nulos

En nuestro proceso de desarrollo diario, inevitablemente encontraremos problemas con el puntero nulo. En el pasado, cuando ocurrían problemas con el puntero nulo, generalmente necesitábamos depurar y otros métodos para finalmente ubicar la ubicación específica, especialmente cuando se llama entre servicios del sistema distribuido. más difícil de localizar. Después de usar Opcional, podemos empaquetar el objeto de parámetro recibido. Por ejemplo, el servicio de pedido necesita llamar a una interfaz del servicio del producto y pasar la información del producto a través de los parámetros. En este momento, los parámetros del producto entrantes se pueden pasar directamente. Es nulo. En este momento, el método del producto puede usar Opcional.of(T) para envolver el objeto entrante. Si T está vacío, se generará una excepción de puntero nulo directamente. Cuando veamos la información de la excepción, podremos saberlo inmediatamente. que se ha producido un puntero nulo. La razón es que el parámetro T está vacío; o, cuando el parámetro entrante está vacío, podemos usar el método Opcional.orElse() o Opcional.orElseGet() para generar una instancia predeterminada y luego realizar operaciones posteriores.

  Veamos un ejemplo específico: hay una clase de dirección en la clase de usuario, una clase de calle en la clase de dirección y un atributo de nombre de calle en la clase de calle. El requisito actual es: obtener el nombre de calle correspondiente de acuerdo con la instancia de usuario entrante. Si el usuario es nulo, la dirección es nula o la calle es nula, se devuelve "no se encontró nada"; de lo contrario, se devuelve el nombre de la calle correspondiente.

        1. manera ordinaria
@Data
public class User {
    private String name;
    private Integer age;
    private Address address;
}

@Data
public class Address {
    private Street street;
}

@Data
public class Street {
    private String streetName;
    private Integer streetNo;}
public String getUserSteetName(User user) {

    if(null != user) {

        Address address = user.getAddress();

        if(null != address) {

            Street street = address.getStreet();

            if(null != street) {
                return street.getStreetName();
            }
        }
    }

    return "nothing found";
}
        2.Usar opcional

El problema obvio en la implementación es que el nivel de juicio if es demasiado profundo, lo siguiente se reutiliza Opcional para reescribir:

@Data
public class User {
    private String name;
    private Integer age;
    private Optional<Address> address = Optional.empty();
}

@Data
public class Address {
    private Optional<Street> street = Optional.empty();
}

@Data
public class Street {
    private String streetName;
    private Integer streetNo;
}


public String getUserSteetName(User user) {

    Optional<User> userOptional = Optional.ofNullable(user);
    final String streetName = userOptional.orElse(new User()).getAddress().orElse(new Address()).getStreet().orElse(new Street()).getStreetName();
    return StringUtils.isEmpty(streetName) ? "nothing found" : streetName;
}

El uso del método orElse() para proporcionar un valor predeterminado garantiza que no se informará el problema del puntero nulo y que también se podrán cumplir los requisitos.

Supongo que te gusta

Origin blog.csdn.net/qq_45443475/article/details/133308753
Recomendado
Clasificación