Chega de NullPointer, comece a utilizar Optional em sua codificação!

I'm Sassine, Java Specialist and Engineering Manager at NTT DATA, based in Brazil. My main strengths are architecture, performance, quality and agility in the Java and Spring universe with AWS.
Sou Sassine, especialista em Java e gerente de engenharia da NTT DATA, com sede no Brasil. Meus principais pontos fortes são arquitetura, desempenho, qualidade e agilidade no universo Java e Spring com AWS.
Introdução
Sempre que estou entrevistando um novo candidato eu o questiono sobre o uso ou conhecimento do Optional, e quase sempre ouço a mesma resposta "Já utilizei, quando usei o JPA "😢
📦 Caso queira acompanhar a classe completa enquanto lê o artigo acesse ele no GitHub - Optional-Stream-usecase-example
Optional
O uso do Optional vai muito além do JPA ele veio como uma solução para ser utilizado para simplificar as validações de objetos nulos, neste post vou mostrar a vocês todas as formas de utilizar ele no seu dia dia e com isso reduzir em 99.9% as chances de se obter um NullPointer e tornar o seu código mais limpo.
isPresent
Quando manipulamos Optional ele nos entrega uma função que é os .isPresent() que é responsável por nos informar se existe um valor ou se é nulo retorna um booleano falso e existir valor será verdadeiro
private boolean methodExampleReceivesOptional(Optional<String> opt) {
return opt.isPresent();
}
empty
Sempre que tiver um método que o retorno poderá ser nulo invés de retornar null retorne .empty()
private void returnEmptyOptional() {
Optional<String> opt = Optional.empty();
if (methodExampleReceivesOptional(opt))
msg(VALUE_FOUND);
else
msg(VALUE_NOT_FOUND);
}
// print: "value not found"
of
Quando tiver certeza que o valor a ser retornado não será nulo, ou quando você for enviar um valor para um método/função que recebe Optional, você devera criar ele utilizando .of(Object)
private void returnOptionalFixValue() {
var opt = Optional.of("Sassine");
if (methodExampleReceivesOptional(opt))
msg(VALUE_FOUND);
else
msg(VALUE_NOT_FOUND);
}
// print: "value found"
Se tentarmos passar um valor direto para o método
methodExampleReceivesOptional("Sassine");
não funcionará pois ele não pode receber um valor que não seja Optional
ofNullable
Neste caso não temos certeza se o valor irá existir ou será nulo, vai depender do valor gerado então utilizamos o .ofNullable(Object) esse cara é quem irá te acompanhar para evitar e tratar todos seus NullPointers agora!
private void returnDynamicOptional() {
Random r = new Random();
var n = r.nextInt((2 - 1) + 1) + 1;
var opt = Optional.ofNullable(n == 1 ? null : "Sassine");
if (methodExampleReceivesOptional(opt))
msg(VALUE_FOUND);
else
msg(VALUE_NOT_FOUND);
}
// print: "value found" or "value not found"
get
Quando temos a confirmação de que o valor existe com o "ifPresent" podemos recuperar o valor contido no Optional e manipularmos da forma que quisermos utilizando a chamada .get()
private void getOptionalValue() {
Optional<String> valueOpt = Optional.of("Sassine");
if (methodExampleReceivesOptional(valueOpt))
msg(valueOpt.get());
else
msg(VALUE_NOT_FOUND);
}
// print: Sassine
orElse
Com Optional OfNullable se o seu valor for nulo conseguimos falar para ele nos entregar um valor padrão fixado ou até mesmo chamar outra função para recuperar outro valor utilizando .orElse(Object) ou .orElseGet(() -> args())
private void returnDefaultValueWhenNull() {
String ex = null;
String valueOpt = Optional.ofNullable(ex).orElse("Sassine - Default");
msg("value found > %s".formatted(valueOpt));
String valueOpt2 = Optional.ofNullable(ex).orElse(getName());
msg("value found > %s".formatted(valueOpt2));
String valueOpt3 = Optional.ofNullable(ex).orElseGet(Person::getName);
msg("value found > %s".formatted(valueOpt3));
}
/*
print1: value found > Sassine - Default
print2: value found > Sassine - Function
print3: value found > Sassine - Class
*/
orElseThrow
Conseguimos fazer com que o Optional lance uma Exception conforme a gente definir quando o valor for nulo utilizando .orElseThrow(() -> new Exception())
private void returnCustomExecutionIfNull() {
try {
String ex = null;
Optional.ofNullable(ex).orElseThrow(() -> new RuntimeException("value not found - exception"));
} catch (RuntimeException e) {
msg(e.getMessage());
}
}
//print: value not found - exception
Optional Java 9+
ifPresentOrElse
Para simplificar os ifPresent e o get, no java 9 foi disponibilizado o .ifPresentOrElse((),()) que simplifica a implementação e a tomada de decisão
private void ifPresentOrElse() {
String ex = null;
Optional.ofNullable(ex)
.ifPresentOrElse(v -> msg(VALUE_FOUND_S.formatted(v)), () -> msg(VALUE_NOT_FOUND));
Optional.ofNullable("Sassine")
.ifPresentOrElse(v -> msg(VALUE_FOUND_S.formatted(v)), () -> msg(VALUE_NOT_FOUND));
}
//print: value not found
//print2: value found > Sassine
getValueOr
Com .or(() -> ...) se o 1 valor não estiver presente ele executa uma ação ... neste exemplo buscar o valor existente na função getName
private void getValueOr() {
String ex = null;
Optional.ofNullable(ex)
.or(() -> Optional.of(getName()))
.ifPresent(this::msg);
}
//print: Sassine - Function
optionalStream
Optional também permite o uso de .stream(), se um valor estiver presente ele retorna o stream caso contrario retorna uma stream vazia!
private void optionalStream() {
var list = List.of("AB", "CD");
Optional.ofNullable(list).stream().forEach(l -> {
l.forEach(this::msg);
});
List<String> x = null;
Optional.ofNullable(x).stream().forEach(l -> {
l.forEach(this::msg);
});
}
//print: ABCD
//print2:
Se quiser dar uma olhada/testar o projeto está em meu github ;)





