Práctica y análisis de código fuente opcional

1. Introducción

NullPointerException a menudo se encuentra en el proceso de desarrollo, y aparecerá un pequeño error si no tiene cuidado. Si evita este problema, Opcional es una clase especialmente diseñada para resolver este problema, entonces, ¿cómo usar Opcional? ¡Exploremos juntos!

2 Análisis del código fuente

2.1 Definición opcional

La clase opcional es una clase contenedora creada por Java 8 para resolver el problema del juicio de valor nulo. Bajo java.util, el uso de la clase opcional puede evitar el juicio de valor nulo explícito y evitar la excepción NullPointerException causada por nulo. En primer lugar, Opcional es un contenedor que puede contener un valor de tipo T o un objeto contenedor nulo. El contenedor opcional solo puede contener un valor.

2.2 Propiedades opcionales

1) Código fuente:

/**
 * 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;

De acuerdo con el código fuente, puede ver que Opcional tiene dos propiedades, una está VACÍO preparado para valor nulo y el valor de valor genérico;

2.3 Métodos opcionales

Además de los métodos de Object como toString(), hashCode(), equals(), Optional también incluye los siguientes métodos.

2.3.1 Constructores privados

/**
 * Constructs an empty instance.
 *
 * @implNote Generally only one empty instance, {@link Optional#EMPTY},
 * should exist per VM.
 */
private Optional() {
    this.value = null;
}


/**
* Constructs an instance with the value present.
*
* @param value the non-null value to be present
* @throws NullPointerException if value is null
*/
private Optional(T value) {
    this.value = Objects.requireNonNull(value);
}

Cree una instancia vacía y construya una instancia con el valor actual, respectivamente.

2.3.2 Crear método

1) código fuente

public static<T> Optional<T> empty() {
    @SuppressWarnings("unchecked")
    Optional<T> t = (Optional<T>) EMPTY;
    return t;
}
public static <T> Optional<T> of(T value) {
     return new Optional<>(value);
}
public static <T> Optional<T> ofNullable(T value) {
     return value == null ? empty() : of(value);
}

2) Descripción del método

  • vacío (): crea una instancia opcional vacía
  • of(T t) : crea una instancia opcional y lanza una excepción cuando t es nulo
  • ofNullable(T t): crea una instancia opcional, pero no lanza una excepción cuando t es nulo, pero devuelve una instancia vacía

3) Código de prueba

public static void main(String[] args) {
    Integer value1 = null;
    Integer value2 = 1;
    try {
        Optional<Integer> optional1 = Optional.empty();
        System.out.println("optional1创建了");
    }catch (Exception e){
        System.out.println("optional1失败了");
    }
    try {
        Optional<Integer> optional2 = Optional.of(value1);
        System.out.println("optional2创建了");
    }catch (Exception e){
        System.out.println("optional2失败了");
    }
    try {
        Optional<Integer> optional3 = Optional.ofNullable(value1);
        System.out.println("optional3创建了");
    }catch (Exception e){
        System.out.println("optional3失败了");
    }
    try {
        Optional<Integer> optional4 = Optional.of(value2);
        System.out.println("optional4创建了");
    }catch (Exception e){
        System.out.println("optional4失败了");
    }
    try {
        Optional<Integer> optional5 = Optional.ofNullable(value2);
        System.out.println("optional5创建了");
    }catch (Exception e){
        System.out.println("optional5失败了");
    }
}

4) resultado corriente

 

2.3.3 Método de adquisición de valor

1) código fuente

public T get() {
    if (value == null) {
        throw new NoSuchElementException("No value present");
    }
    return value;
}

2) Descripción del método

get(): Devuelve el valor en el contenedor Opcional si el Opcional no está vacío, de lo contrario lanza NoSuchElementExceptio.

3) Código de prueba

public static void main(String[] args) {
    Integer value1 = null;
    Integer value2 = 1;
    Optional<Integer> optional1 = Optional.ofNullable(value1);
    Optional<Integer> optional2 = Optional.of(value2);
    try {
        Integer result=optional1.get();
        System.out.println("optional1的值是:"+result);
    }catch (Exception e){
        System.out.println("optional1的值获取失败,原因:"+e.getMessage());
    }
    try {
        Integer result=optional2.get();
        System.out.println("optional2的值是:"+result);
    }catch (Exception e){
        System.out.println("optional2的值获取失败,原因:"+e.getMessage());
    }
}

4) resultado corriente

 

2.3.4 Método de juicio

1) código fuente

public boolean isPresent() {
    return value != null;
}
public void ifPresent(Consumer<? super T> consumer) {
    if (value != null)
        consumer.accept(value);
}
public T orElse(T other) {
    return value != null ? value : other;
 }   
public T orElseGet(Supplier<? extends T> other) {
     return value != null ? value : other.get();
}
public <X extends Throwable> T orElseThrow(Supplier<? extends X> exceptionSupplier) throws X {
   if (value != null) {
      return value;
   } else {
      throw exceptionSupplier.get();
   }
}

2) Descripción del método

  • isPresent (): determina si el opcional está vacío, si está vacío, devuelve falso, de lo contrario, devuelve verdadero
  • ifPresent (Consumidor c): si opcional no está vacío, pase el objeto en opcional a la función Consumidor
  • orElse(T otro): Si opcional no está vacío, devuelve el objeto en opcional; si es nulo, devuelve el otro objeto.
  • orElseGet(Otro proveedor): si opcional no está vacío, devuelve el objeto en opcional; si es nulo, de lo contrario llama a otras funciones y devuelve el resultado de la llamada
  • orElseThrow (excepción del proveedor): si opcional no está vacío, devuelve el objeto en opcional; si es nulo, lanza la excepción generada por la función del proveedor

3) Código de prueba

public static void main(String[] args) {
    Integer value1 = null;
    Integer value2 = 1;
    Optional<Integer> optional1 = Optional.ofNullable(value1);
    Optional<Integer> optional2 = Optional.of(value2);
    try {
        if(optional1.isPresent()){
            System.out.println("optional1的isPresent结果不为空");
        }else{
            System.out.println("optional1的isPresent结果为空");
        }
    }catch (Exception e){
        System.out.println("optional1的isPresent判空失败,原因:"+e.getMessage());
    }
    try {
        if(optional2.isPresent()){
            System.out.println("optional2的isPresent结果不为空");
        }else{
            System.out.println("optional2的isPresent结果为空");
        }
    }catch (Exception e){
        System.out.println("optional2的isPresent判空失败,原因:"+e.getMessage());
    }


    optional1.ifPresent(t->{
        int i =t+1;
        System.out.println("optional1处理后的值是"+i);
    });
    optional2.ifPresent(t->{
        int i =t+1;
        System.out.println("optional2处理后的值是"+i);});


    Integer value3 = 2;
    Integer result = optional1.orElse(value3);
    System.out.println("optional1执行orElse处理后的值是"+result);


    result = optional2.orElse(value3);
    System.out.println("optional2执行orElse处理后的值是"+result);


    result = optional1.orElseGet(()-> new Integer(-1));
    System.out.println("optional1执行orElseGet处理后的值是"+result);


    result = optional2.orElseGet(()-> new Integer(-1));
    System.out.println("optional2执行orElseGet处理后的值是"+result);
    try {
    result = optional1.orElseThrow (()-> new RuntimeException("值是空的"));
    System.out.println("optional1执行orElseThrow处理后的值是"+result);
    }catch (Exception e){
        System.out.println("optional1的orElseThrow抛出异常:"+e.getMessage());
    }
    try {
    result = optional2.orElseThrow (()-> new RuntimeException("值是空的"));
    System.out.println("optional2执行orElseThrow处理后的值是"+result);
    }catch (Exception e){
        System.out.println("optional2的orElseThrow抛出异常:"+e.getMessage());

4) resultado corriente

 

2.3.5 Método de filtrado

1) código fuente

public Optional<T> filter(Predicate<? super T> predicate) {
    Objects.requireNonNull(predicate);
    if (!isPresent())
        return this;
    else
        return predicate.test(value) ? this : empty();
}

2) Descripción del método

filtro (Predicado p): si opcional no está vacío, ejecute Predicado p, si el resultado de p es verdadero, devuelva el original opcional, de lo contrario, devuelva vacío opcional

3) Código de prueba

public static void main(String[] args) {
    Integer value1 = 5;
    Integer value2 = 6;
    Optional<Integer> optional1 = Optional.ofNullable(value1);
    Optional<Integer> optional2 = Optional.of(value2);


    Optional<Integer> result =optional1.filter(t->t > 5);
    System.out.println("optional1的filter后的值:"+result);
     result =optional2.filter(t->t > 5);
    System.out.println("optional2的filter后的值:"+result);

4) resultado corriente

 

2.3.6 Método de mapeo

1) código fuente

public<U> Optional<U> map(Function<? super T, ? extends U> mapper) {
    Objects.requireNonNull(mapper);
    if (!isPresent())
        return empty();
    else {
        return Optional.ofNullable(mapper.apply(value));
    }
}
public<U> Optional<U> flatMap(Function<? super T, Optional<U>> mapper) {
    Objects.requireNonNull(mapper);
    if (!isPresent())
        return empty();
    else {
        return Objects.requireNonNull(mapper.apply(value));
    }
}

2) Descripción del método

  • map (Mapeador de funciones): si existe un valor, aplique la función de mapa proporcionada y, si el resultado no es nulo, devuelva un Opcional que describa el resultado. De lo contrario, devuelve un Opcional vacío.
  • flatMap(Function<T,Optional> mapper): si hay un valor, aplique la función de mapeador opcional proporcionada y devuelva el resultado; de lo contrario, devuelva una función opcional vacía. Este método es similar a map(Function), pero el resultado del mapeador proporcionado ya es opcional, si se llama, flatMap no lo envolverá con un extra opcional.
  • Diferencia: el mapa lo pondrá automáticamente en opcional, mientras que flatMap necesita crear manualmente un opcional para usted

3) Código de prueba

    public static void main(String[] args) {
        User user1 = null;
        User user2 = new User("user2名字",19);
        Optional<User> optional1 = Optional.ofNullable(user1);
        Optional<User> optional2 = Optional.of(user2);
        System.out.println("=========map==========");
        System.out.println("optional1的map前的值:"+optional1);
        Optional<String> result =optional1.map(t->t.getName());
        System.out.println("optional1的map后的值:"+result);


        System.out.println("optional2的map前的值:"+optional2);
        result =optional2.map(t->t.getName());
        System.out.println("optional2的map后的值:"+result);


        System.out.println("===========flatMap========");


        System.out.println("optional1的flatMap前的值:"+optional1);
        Optional<Integer> result2 =optional1.flatMap(t->Optional.ofNullable(t.getAge()));
        System.out.println("optional1的flatMap后的值:"+result2);


        System.out.println("optional2的flatMap前的值:"+optional2);
        result2 =optional2.flatMap(t->Optional.ofNullable(t.getAge()));
        System.out.println("optional2的flatMap后的值:"+result2);

    }
public class User {
    String name;
    Integer age;
    public User(String name,Integer age){
        this.name = name;
        this.age=age;
    }


    public String getName() {
        return name;
    }


    public Integer getAge() {
        return age;

4) resultado corriente

 

3 Ejemplos de aplicación

3.1 Uso incorrecto

  • Dado que Optional no implementa la interfaz Serializable, no se puede usar como una propiedad de la clase.
  • No utilice Optional como parámetro de método.
  • Reemplace if(x!=null) directamente con Optional.ofNullable(x).isPresent(), que se sospecha que está sobrecodificado.
  • Use directamente el valor de retorno de Optional.get() para operar, String result =Optional.ofNullable(null).get().toString(); esto seguirá generando una excepción.

3.2 Uso recomendado

La clase A tiene el atributo Clase B, la clase B tiene el atributo Clase C y la clase C tiene el nombre de campo.
Antes de usar Opcional:

if(atest!=null){
    Btest btest =atest.getBtest();
    if(btest!=null){
      Ctest ctest = btest.getCtest();
      if (ctest != null) {
          name =ctest.getName();
      }
    }
}

Después de usar Opcional:

name = Optional.ofNullable(atest).map(t->t.getBtest()).map(t->t.getCtest()).map(t->t.getName()).orElse("默认值");

¿El código se ve más limpio?

4 Resumen

Mediante el análisis del código fuente Opcional y los resultados de ejecución del código de prueba de caso de uso, se puede ver que el uso de Opcional puede optimizar el código de juicio de valor nulo, haciendo que el código sea más elegante y ordenado.


Autor: Chen Changhao

{{o.nombre}}
{{m.nombre}}

Supongo que te gusta

Origin my.oschina.net/u/4090830/blog/5581362
Recomendado
Clasificación