0Pricing
Java Academy · Aula

Boas Práticas com Optional

Aplique orElse, orElseGet e orElseThrow, evitando padrões inadequados comuns ao usar Optional.

Boas Práticas com Optional é uma aula grátis de Java Academy no CoddyKit. Esta é a aula 4 de 4. Você pode ler a aula completa abaixo gratuitamente — depois pratica ao vivo no navegador com um editor de código integrado e um tutor de IA 24/7. Faz parte do caminho de aprendizado de Java Academy, e seu progresso é sincronizado entre a web e o app CoddyKit. O curso de Java Academy inclui 4 aulas no total.

Práticas recomendadas para Optional

Optional é uma ferramenta poderosa quando usado corretamente. Esta lição aborda o que fazer e o que evitar, com exemplos concretos de bases de código reais.

Faça: use Optional como tipo de retorno

O principal caso de uso de Optional é como tipo de retorno de métodos que talvez não encontrem ou produzam um valor.

import java.util.Optional;

// Good: signals to caller that result might be absent
public Optional<User> findByUsername(String username) { ... }
public Optional<Config> getConfig(String key) { ... }
public Optional<String> getHeader(String name) { ... }

// These are all cases where absence is a normal outcome,
// not an exceptional condition

Não faça: Optional como campo

Campos Optional aumentam a sobrecarga dos objetos e complicam a serialização. Use null ou um valor sentinela para campos opcionais dentro das classes.

// BAD
class User {
    private Optional<String> middleName; // wrong
}

// GOOD: use null for absent optional field
class User {
    private final String middleName; // null = absent
    public Optional<String> middleName() {
        return Optional.ofNullable(middleName); // expose as Optional in getter
    }
}
User u = new User(null); // null field
System.out.println(u.middleName().isPresent()); // false

Não faça: Optional como parâmetro de método

Parâmetros Optional obrigam os chamadores a encapsular valores em Optional sem necessidade. Use sobrecarga ou @Nullable.

// BAD
void sendNotification(String message, Optional<String> subject) { ... }
// caller must write: sendNotification("Hello", Optional.of("News"))

// GOOD: overloading
void sendNotification(String message) { sendNotification(message, null); }
void sendNotification(String message, String subject) {
    // subject may be null
}
// caller writes: sendNotification("Hello", "News") — clean

Não faça: Optional em coleções

Nunca coloque Optionals dentro de um List, nem como valor de um conjunto ou mapa. Optionals vazios em coleções não têm significado — simplesmente omita a entrada.

// BAD: List of Optionals
List<Optional<User>> results = ...; // meaningless empty Optionals

// GOOD: List of present values only
List<User> presentUsers = maybeUsers.stream()
    .flatMap(Optional::stream)
    .collect(Collectors.toList());

// BAD: Map with Optional values
Map<String, Optional<String>> config = ...;

// GOOD: just use null or omit the key for absent values
Map<String, String> config2 = ...;
String value = config2.getOrDefault("key", "default");

Faça: use orElseGet para valores padrão dispendiosos

Quando o valor padrão envolver um cálculo (consulta ao banco de dados ou chamada de rede), use sempre orElseGet — o fornecedor só será chamado quando necessário.

import java.util.Optional;

// BAD: buildDefault() always called, even when value is present!
String config = getConfig("timeout").orElse(buildDefault());

// GOOD: supplier called lazily only when empty
String config2 = getConfig("timeout").orElseGet(() -> buildDefault());

// Or with method reference:
String config3 = getConfig("timeout").orElseGet(this::buildDefault);

// For cheap literals, orElse is fine
String name = getConfig("name").orElse("default");

Faça: use orElseThrow para valores obrigatórios

Quando um valor ausente representar um erro de programação ou uma violação de invariante, use orElseThrow com uma exceção descritiva.

import java.util.Optional;

// Good: throw when absence is an error
User user = userRepository.findById(userId)
    .orElseThrow(() -> new UserNotFoundException("User not found: " + userId));

// Good: in validation code
String apiKey = Optional.ofNullable(System.getenv("API_KEY"))
    .orElseThrow(() -> new IllegalStateException(
        "API_KEY environment variable is required"));

System.out.println("Key found: " + apiKey.length() + " chars");

Antipadrão: isPresent + get()

Evite o antipadrão de verificar isPresent() e depois chamar get(). Isso não é melhor do que uma verificação de null e frustra o objetivo de Optional.

import java.util.Optional;

Optional<String> opt = findValue();

// BAD: isPresent() + get() — no improvement over null check
if (opt.isPresent()) {
    String val = opt.get();
    process(val);
}

// GOOD: use the functional API
opt.ifPresent(this::process);

// GOOD: transform and return
return opt.map(this::process).orElse(null);

// GOOD: provide a default
String result = opt.orElse("default");

Prática recomendada para encadeamento

Crie uma cadeia limpa: buscar → filter → transformar → fallback. Cada etapa explica a si mesma.

import java.util.Optional;

record User(long id, String plan, boolean active) {}

static Optional<User> findUser(long id) { return Optional.empty(); }

String result = findUser(42L)
    .filter(User::active)           // keep only active users
    .filter(u -> "PRO".equals(u.plan())) // keep only PRO users
    .map(u -> "Welcome, Pro user #" + u.id()) // transform
    .orElse("Upgrade to Pro!");     // fallback

System.out.println(result); // Upgrade to Pro!

Optional na camada de serviço

Um exemplo realista de camada de serviço que segue as práticas recomendadas.

import java.util.Optional;

class OrderService {
    public Optional<OrderSummary> getOrderSummary(long orderId) {
        return orderRepo.findById(orderId)
            .filter(o -> !o.isCancelled())
            .map(this::toSummary);
    }

    public OrderSummary requireOrderSummary(long orderId) {
        return getOrderSummary(orderId)
            .orElseThrow(() -> new OrderNotFoundException(orderId));
    }

    private OrderSummary toSummary(Order o) { return new OrderSummary(o); }
}
// API callers choose: Optional (handle absence) or require (exception)

Optional e ferramentas de segurança contra null

Optional complementa as anotações @Nullable/@NonNull e ferramentas como SpotBugs/NullAway para uma cobertura completa de segurança contra null.

// Annotation-based: declares intent for in-class nulls
import org.jetbrains.annotations.*;

class ProductService {
    @Nullable  // may return null — for framework/bean use
    public String getCachedName(String id) { return cache.get(id); }

    // Optional — for service API that handles absence
    public Optional<Product> findProduct(String id) {
        return repo.findById(id);
    }
}
// Use @Nullable for fields/parameters; Optional for return types

Verificação rápida

O que há de errado com o código a seguir?

if (opt.isPresent()) {
    process(opt.get());
}

Recapitulação: práticas recomendadas para Optional

Principais conclusões:

  • Use Optional somente como tipo de retorno — nunca como campo ou parâmetro de método
  • Prefira orElseGet a orElse quando o valor padrão for dispendioso de calcular
  • Use orElseThrow quando a ausência representar um erro de programação
  • Evite isPresent() + get() — use ifPresent, map ou orElse
  • Nunca coloque Optional dentro de coleções — filtre os fluxos em vez disso
  • Crie cadeias legíveis: filter → map → orElse para um fluxo de dados claro

Perguntas Frequentes

A aula “Boas Práticas com Optional” é grátis?

Sim — o texto completo de “Boas Práticas com Optional” é grátis para ler aqui na web. Para praticá-la interativamente (um editor de código integrado e um tutor de IA 24/7) e desbloquear o restante do curso de Java Academy, atualize para CoddyKit PRO. O curso de Java Academy inclui 4 aulas no total.

O que vou aprender em “Boas Práticas com Optional”?

Aplique orElse, orElseGet e orElseThrow, evitando padrões inadequados comuns ao usar Optional. Você pratica Java Academy com código prático que executa diretamente no navegador, e um tutor de IA 24/7 responde suas dúvidas enquanto trabalha na aula.

Preciso ter experiência prévia para começar Java Academy?

Nenhuma experiência prévia é necessária. Java Academy no CoddyKit é estruturado para alunos iniciantes até avançados, então você pode começar aqui ou desde o início e aprender no seu ritmo. Esta é a aula 4 de 4.

Quanto tempo leva a aula “Boas Práticas com Optional”?

A maioria das aulas CoddyKit leva cerca de 5–10 minutos. Cada uma é compacta e interativa, então você faz progresso constante e retoma exatamente de onde parou entre web e app.

Posso escrever e executar código nesta aula de Java Academy?

Sim. Cada aula de Java Academy inclui um editor de código integrado, então você escreve e executa código real direto no navegador e recebe feedback de IA instantaneamente — nenhuma configuração local necessária.

Todas as aulas deste curso

  1. Por que Optional Existe
  2. Criação e Inspeção de Optionals
  3. Transformação de Optionals: map e flatMap
  4. Boas Práticas com Optional
← Voltar para Java Academy