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

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

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

Did you find this article valuable?

Support Sassine EL-Asmar by becoming a sponsor. Any amount is appreciated!