Skip to main content

Command Palette

Search for a command to run...

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

Updated
4 min read
Chega de NullPointer, comece a utilizar Optional em sua codificação!
S

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 ;) MyGithub badge