Trabalhando com Optional

26926 words javajava

Neste guia você irá aprender como funciona o Optional, um novo recurso adicionado no Java 8 e saberá como usá-lo.

Introdução

A classe Optional foi adicionada na versão do 8 no pacote java.util. Esta classe foi introduzida para verificar se um valor está presente, evitando o famoso erro de NullPointerException.

Um objeto Optional é um container que pode ou não conter um valor.

Métodos mais usados

A classe Optional possui vários métodos, entre eles temos o isPresent() e get().

  • isPresent(): Verifica se o objeto Optional possui algum valor que seja diferente de vazio ou null. Retorna true se tiver algum valor, caso contrário retorna false.
  • get(): Recupera o valor de um objeto Optional.

Semelhante ao isPresent() o método isEmpty() retorna true se estiver vazio, caso contrário, retornará true. Este método foi adicionado no Java 11.

package to.dev;

import java.util.Optional;

public class OptionalExample {

    public static void main(String[] args) {
        Optional<String> stringOptional = Optional.of("Hello");

        if (stringOptional.isPresent()) {
            System.out.println(stringOptional.get()); // Hello
        }
    }
}

Para criar um Optional é preciso usar o método Optional.of(T value), este método retorna um Optional<T> do mesmo tipo do argumento fornecido em of(T value).
Ex. Optional<Long> longOptional = Optional.of(1L);

Optional.of(T value) e Optional.ofNullable(T value)

Só use of(T value) quando o argumento fornecido NUNCA será null. Caso contrário, será lançado um NullPointerException. Para evitar esse erro use ofNullable(T value)

public class OptionalExample {

    public static void main(String[] args) {
        Optional<String> stringOptional = Optional.ofNullable(null);

        if (stringOptional.isPresent()) {
            System.out.println(stringOptional.get());
        }
    }
}

Criando um Optional vazio

Para criar um Optional vazio use Optional.empty(). Ex. Optional<String> stringOptional = Optional.empty();

Optional com valores default - orElse(T other)

Caso um Optional esteja vazio e você queira retorna um valor padão basta usar o método orElse(T other).

package to.dev;

import java.util.Optional;

public class OptionalExample {

    public static void main(String[] args) {
        Optional<Long> longOptional = Optional.ofNullable(null);
        System.out.println(longOptional.orElse(99L)); // 99
    }
}

Optional com valores default - orElseGet(Supplier<? extends T> supplier)

Esta alternativa recebe um Supplier como argumento, permitindo que você execute alguma operação.

Supplier: É uma interface funcional que não recebe argumentos, mas sempre retorna um valor.

package to.dev;

import java.time.LocalDate;
import java.util.Optional;

public class OptionalExample {

    public static void main(String[] args) {
        Optional<Long> longOptional = Optional.ofNullable(null);
        System.out.println(longOptional.orElseGet(() -> { // 29
            int i = LocalDate.now().getDayOfMonth();
            return (long) i;
        }));
    }
}

orElse(T other) vs orElseGet(Supplier<? extends T> supplier)

orElse(T other) retorna o valor dentro do container Optional se estiver presente, caso contrário, irá retornar o valor fornecido no argumento do método. orElseGet(Supplier<? extends T> supplier): retorna o valor dentro do container Optional, caso contrário, irá invocar o Supplier e retornará o resultado da invocação.

Filtrando um Optional

Para filtrar algum valor de Optional use o método filter(Predicate<? super T> predicate).

Predicate: É uma interface funcional que recebe um valor e sempre retorna um valor booleano.

package to.dev;

import java.util.Optional;

public class OptionalExample {

    public static void main(String[] args) {
        Optional<Long> longOptional = Optional.ofNullable(30L);

        Optional<Long> longFilter = longOptional.filter(v -> v > 18); // true

        if (longOptional.isPresent()) {
            System.out.println(longFilter.get()); // 30
        }
    }
}

Modificando o valor de um Optional com map(Function<? super T, ? extends U> mapper)

O método map() serve para modificar um valor dentro de um container Optional. Para isso é passado uma Function com argumento.

Function: É uma interface funcional que recebe um valor como argumento e retorna um valor que pode igual ou diferente do argumento passado.

package to.dev;

import java.util.Optional;

public class OptionalExample {

    public static void main(String[] args) {
        Optional<String> longOptional = Optional.ofNullable("Hello");

        Optional<String> longMap = longOptional.map(v -> {
            if (v.contains("Hello")) {
                return "Hello World";
            } else {
                return "Hello";
            }
        });

        System.out.println(longMap.get()); // Hello World
    }
}

Recebendo um Optional de outro Optional com flatMap(Function<? super T, ? extends Optional<? extends U>> mapper)

O flatMap(Function<? super T, ? extends Optional<? extends U>> mapper) é usado quando você recebe um objeto Optional de um container Optional, Optional<Optional<Long>> longOptional = Optional.of(Optional.empty());.

package to.dev;

import java.util.Optional;

public class OptionalExample {

    public static void main(String[] args) {
        Optional<String> stringOptional = Optional.of("Hello World");
        Optional<Optional<String>> optionalStringOptional = Optional.of(stringOptional);

        System.out.println(optionalStringOptional);

        Optional<String> output = optionalStringOptional.flatMap(value -> value.map(String::toLowerCase));

        System.out.println(output);
    }
}

Executando uma lógica se o Optional estiver presente

Caso queira executar alguma operação se um valor estiver presente, uma alternativa é usar o método ifPresent(Consumer<? super T> consumer).

Consumer: É uma interface funcional que recebe argumentos, mas não retorna nenhum valor.

package to.dev;

import java.util.Optional;

public class OptionalExample {

    public static void main(String[] args) {
        Optional<String> longOptional = Optional.ofNullable("Hello");

        Optional<String> longMap = longOptional.map(v -> {
            if (v.contains("Hello")) {
                return "Hello World";
            } else {
                return "Hello";
            }
        });

        longMap.ifPresent(v -> System.out.println(v)); // Hello World
    }
}

Tratando exceções com orElseThrow(Supplier<? extends X> exceptionSupplier)

O método orElseThrow(Supplier<? extends X> exceptionSupplier) retorna o valor caso ele esteja presente, caso contrário, ele irá lançar um exceção fornecida pelo desenvolvedor.

Este método só está disponível no Java 10.

package to.dev;

import java.util.Optional;

class EmptyException extends Exception {
    public EmptyException() {
        super("Not found value");
    }
}

public class OptionalExample {
    public static void main(String[] args) throws EmptyException {
        Optional<String> stringOptional = Optional.ofNullable(null);

        System.out.println(stringOptional.orElseThrow()); // throws -> NoSuchElementException: No value present
        System.out.println(stringOptional.orElseThrow(EmptyException::new)); // throws -> EmptyException: Not found value

    }
}

Referência: https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/util/Optional.html