Explicação detalhada dos novos recursos do JDK8 sobre o uso da classe Opcional

I. Visão geral

        Acredito que NullPointerException é familiar a todo programador JAVA e é a exceção mais comum em aplicativos JAVA. Anteriormente, o projeto Google Guava propunha o uso da classe Opcional para agrupar objetos para resolver NullPointerException. Afetado por isso, a classe Opcional também foi introduzida nas classes JDK8, e o suporte para este método foi implementado na nova versão do SpringData Jpa e Spring Redis Data.

2. Aula 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;

   // 其他省略
}

A anotação deste método significa aproximadamente: Opcional é um objeto contêiner, que pode conter valores nulos ou valores não nulos. Quando o valor do atributo é definido, o método isPesent() retornará verdadeiro e o método get() retornará este valor. Esta classe suporta genéricos, ou seja, seu valor de atributo pode ser uma instância de qualquer objeto.

3. Métodos de classe opcional

número de série método Descrição do método
1 private Optional() Construção sem parâmetro, constrói um Opcional vazio
2 private Optional(T value) Construa um Opcional com base no valor não vazio passado
3 public static<T> Optional<T> empty() Retorna um Opcional vazio, o valor desta instância está vazio
4 public static <T> Optional<T> of(T value) Construa um Opcional com base no valor não vazio passado, que tem o mesmo efeito que o método Opcional (valor T)
5 public static <T> Optional<T> ofNullable(T value) Diferente do método of(T value), ofNullable(T value) permite que você passe um valor vazio. Quando o valor passado é um valor nulo, ele cria um opcional vazio. Quando o valor passado não está vazio, ele é o mesmo que de. () tem o mesmo efeito
6 public T get() Retorna o valor de Opcional. Se o contêiner estiver vazio, uma NoSuchElementException será lançada.
7 public boolean isPresent() Determine se o valor do Opcional do proprietário foi definido
8 public void ifPresent(Consumer<? super T> consumer) Determine se o Opcional do proprietário definiu um valor. Se houver um valor, chame a interface funcional do Consumidor para processamento.
9 public Optional<T> filter(Predicate<? super T> predicate) Se um valor for definido e as condições de julgamento do Predicado forem atendidas, o Opcional será retornado, caso contrário, um Opcional vazio será retornado.
10 public<U> Optional<U> map(Function<? super T, ? extends U> mapper) Se Opcional definir um valor, chame Function para processar o valor e retornar um Opcional contendo o valor processado, caso contrário, um Opcional vazio será retornado.
11 public<U> Optional<U> flatMap(Function<? super T, Optional<U>> mapper) Diferente do tipo de método map(), o resultado do mapeador já é Opcional e não há necessidade de agrupar o resultado.
12 public T orElse(T other) Se o valor Opcional não estiver vazio, retorne esse valor, caso contrário, retorne outro
13 public T orElseGet(Supplier<? extends T> other) Se o valor Opcional não estiver vazio, retorne este valor, caso contrário gere outro baseado em outro
14 public <X extends Throwable> T orElseThrow(Supplier<? extends X> exceptionSupplier)throws X Se o valor Opcional não estiver vazio, retorne o valor, caso contrário, lance uma exceção por meio do fornecedor

4. Exemplos de métodos da classe Opcional

Exemplo um:

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 da operação:

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

ilustrar:

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

Exemplo dois:

        Modifique o Exemplo 1 para gerar uma instância Opcional com um valor não 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 da operação:

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

A diferença do Exemplo 1 pode ser vista claramente. Isso não apenas simplifica nosso código, mas também torna-o mais fácil de ler.

5. Código-fonte opcional

        Vamos dar uma olhada no código-fonte de vários métodos usados ​​no exemplo:

de

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

é presente

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

ou entãoObtenha

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

se não

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

6. Use Opcional para evitar ponteiros nulos

Em nosso processo de desenvolvimento diário, inevitavelmente encontraremos problemas de ponteiro nulo. No passado, quando ocorriam problemas de ponteiro nulo, geralmente precisávamos depurar e outros métodos para finalmente localizar o local específico, especialmente ao chamar entre serviços de sistema distribuído. O problema é mais difícil de localizar. Depois de usar Opcional, podemos empacotar o objeto de parâmetro recebido. Por exemplo, o serviço de pedido precisa chamar uma interface do serviço do produto e passar as informações do produto por meio dos parâmetros. Nesse momento, os parâmetros do produto recebido podem ser passados ​​​​diretamente. É nulo. Neste momento, o método do produto pode usar opcional.of(T) para agrupar o objeto recebido. Se T estiver vazio, uma exceção de ponteiro nulo será lançada diretamente. Quando vemos as informações da exceção, podemos saber imediatamente que ocorreu um ponteiro nulo. O motivo é que o parâmetro T está vazio; ou, quando o parâmetro de entrada está vazio, podemos usar o método Opcional.orElse() ou Opcional.orElseGet() para gerar uma instância padrão e então executar operações subsequentes.

  Vejamos um exemplo específico: há uma classe Address na classe User, uma classe Street na classe Address e um atributo streetName na classe Street. O requisito atual é: obter o streetName correspondente com base na instância de User recebida. Se If User for nulo ou Address for nulo ou Street for nulo, "nada encontrado" será retornado, caso contrário, o streetName correspondente será retornado.

        1. Maneira normal
@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.Use Opcional

O problema óbvio na implementação é que o nível de julgamento é muito profundo.As seguintes reutilizações são opcionais para reescrever:

@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;
}

Usar o método orElse() para fornecer um valor padrão garante que o problema do ponteiro nulo não será relatado e que os requisitos também poderão ser atendidos.

Acho que você gosta

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