JavaRush /Blogue Java /Random-PT /Pausa para café #161. Como lidar com Null em Java usando ...

Pausa para café #161. Como lidar com Null em Java usando Opcional

Publicado no grupo Random-PT
Fonte: Médio Este artigo irá ajudá-lo a entender melhor o propósito de Opcional ao trabalhar com código Java. Pausa para café #161.  Como lidar com Null em Java usando Opcional - 1Quando comecei a trabalhar com código Java, muitas vezes fui aconselhado a usar Opcional. Mas na época eu não entendia por que usar Opcional era melhor do que implementar o tratamento de valores nulos. Neste artigo, quero compartilhar com você por que acho que todos deveríamos usar mais o opcional e como evitar a opcionalização excessiva do seu código, o que é prejudicial à qualidade do código.

O que é opcional?

O parâmetro Opcional é usado para transportar objetos e permitir que referências nulas sejam tratadas por várias APIs. Vejamos o trecho de código:
Coffee coffee = new Coffee();
Integer quantity = coffee.getSugar().getQuantity();
Temos uma instância Coffee na qual obtemos um pouco de açúcar de uma instância do objeto Sugar . Se assumirmos que o valor da quantidade nunca foi definido no construtor Coffee , então coffee.getSugar().getQuantity() retornará um NullPointerException . Claro, sempre podemos usar as boas e velhas verificações de nulos para resolver o problema.
Coffee coffee = new Coffee();
Integer quantity = 0;
if (coffee.getSugar() != null) {
  quantity = coffee.getSugar().getQuantity();
}
Agora tudo parece estar bem. Mas ao escrever código Java, é melhor evitarmos implementar verificações de nulos . Vamos ver como isso pode ser feito usando Opcional.

Como criar Opcional

Existem três maneiras de criar objetos opcionais:
  • of(T value) — instanciação de um objeto opcional não nulo. Esteja ciente de que usar of() para se referir a um objeto nulo gerará um NullPointerException .

  • ofNullable(T value) - cria um valor Opcional para um objeto que pode ser nulo.

  • vazio() - Cria uma instância Opcional que representa uma referência a null .

// пример использования Optional.of(T Value)
String name = "foo";
Optional<String> stringExample = Optional.of(name)
// пример использования Optional.ofNullable(T Value)
Integer age = null;
Optional<Integer> integerExample= Optional.ofNullable(age)
// пример использования Optional.empty()
Optional<Object> emptyExample = Optional.empty();
Então você tem um objeto Opcional. Agora vamos dar uma olhada nos dois métodos principais para Opcional:
  • isPresent() – Este método informa se o objeto Opcional contém um valor não nulo.

  • get() - Recupera o valor de Opcional com o valor atual. Esteja ciente de que chamar get() em um opcional vazio resultará em NullPointerException .

Observe que se você usar apenas get() e isPresent() ao trabalhar com Opcional, você estará perdendo! Para entender isso, vamos agora reescrever o exemplo acima com Opcional.

Melhorando a verificação de nulos com opcional

Então, como podemos melhorar o código acima? Com Opcional podemos entender a presença de um objeto usando isPresent() e recuperá-lo usando get() . Vamos começar empacotando o resultado de coffee.getSugar() com Opcional e usando o método isPresent() . Isso nos ajudará a determinar se getSugar() retorna nulo.
Coffee coffee = new Coffee();
Optional<String> sugar = Optional.ofNullable(coffee.getSugar());
int quantity = 0;
if (sugar.isPresent()) {
  Sugar sugar = sugar.get();
  int quantity = sugar.getQuantity();
}
Olhando para este exemplo, empacotar o resultado de coffee.getSugar() em Opcional não parece agregar nenhum valor, mas sim adicionar complicações. Podemos melhorar o resultado usando o que considero minhas funções favoritas da classe Opcional:
  • map(Function<? super T,? extends U> mapper) - Mapeia o valor contido em Opcional para a função fornecida. Se o parâmetro Opcional estiver vazio, map() retornará Opcional.empty() .

  • orElse(T other) é uma versão “especial” do método get() . Pode obter o valor contido em Opcional. Porém, no caso de um Opcional vazio, isso retornará o valor passado para o método orElse() .

O método retornará o valor contido na instância Opcional. Mas se o parâmetro Opcional estiver vazio, o que significa que não contém nenhum valor, então orElse() retornará o valor passado para a assinatura do método, que é conhecido como valor padrão.
Coffee coffee = new Coffee();

Integer quantity = Optional.ofNullable(coffee.getSugar())
    .map(it -> it.getQuantity())
    .orElse(0);
Isso é muito legal – pelo menos eu acho. Agora, se no caso de valor vazio não quisermos retornar o valor padrão, então precisamos lançar algum tipo de exceção. orElseThrow(Supplier<? extends X> exceçãoSupplier) retorna o valor contido nos parâmetros Opcionais ou lança uma exceção se Opcional estiver vazio.
Coffee coffee = new Coffee();

Integer quantity = Optional.ofNullable(coffee.getSugar())
  .map(it -> it.getQuantity())
  .orElseThrow(IllegalArgumentException::new);
Como você pode ver, Opcional oferece várias vantagens:
  • abstrai verificações nulas
  • fornece uma API para lidar com objetos nulos
  • permite que a abordagem declarativa expresse o que está sendo alcançado

Como se tornar eficaz com Opcional

Em meu trabalho, uso Opcional como tipo de retorno quando um método pode retornar um estado “sem resultado”. Eu costumo usá-lo ao definir tipos de retorno para métodos.
Optional<Coffee> findByName(String name) {
   ...
}
Às vezes isso não é necessário. Por exemplo, se eu tiver um método que retorne um int , como getQuantity() na classe Sugar , então o método poderá retornar 0 se o resultado for nulo para representar “sem quantidade”. Agora, sabendo disso, podemos pensar que o parâmetro Sugar na classe Coffee pode ser representado como Opcional. À primeira vista, parece uma boa ideia já que, em tese, o açúcar não precisa estar presente no café. No entanto, é aqui que gostaria de abordar quando não usar Opcional. Devemos evitar o uso de Opcional nos seguintes cenários:
  • Como tipos de parâmetros para POJOs , como DTOs . Os opcionais não são serializáveis, portanto, usá-los em um POJO torna o objeto não serializável.

  • Como um argumento de método. Se um argumento de método puder ser null , então, de uma perspectiva de código puro, passar null ainda é preferível a passar Opcional. Além disso, você pode criar métodos sobrecarregados para lidar abstratamente com a ausência de um argumento de método nulo.

  • Para representar um objeto Collection que está faltando. As coleções podem estar vazias, portanto, uma Collection vazia , como um Set ou List vazio , deve ser usada para representar uma Collection sem valores.

Conclusão

Opcional tornou-se uma adição poderosa à biblioteca Java. Ele fornece uma maneira de lidar com objetos que podem não existir. Portanto, deve ser levado em consideração no desenvolvimento de métodos sem cair na armadilha do abuso. Sim, você pode escrever um ótimo código que implemente verificações e tratamento de nulos, mas a comunidade Java prefere usar Opcional. Ele comunica com eficácia como lidar com valores ausentes, é muito mais fácil de ler do que verificações nulas confusas e resulta em menos bugs em seu código no longo prazo.
Comentários
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION