Como parar de verificar null em Java e não enlouquecer

Treinador Online de Python para Iniciantes

Aprenda Python facilmente sem sobrecarga teórica. Resolva tarefas práticas com verificação automática e escreva código diretamente no navegador.

Start Course

A maldição do null: por que escrevemos a mesma coisa repetidamente?

\n\n

Se você programa em Java há mais de uma semana, certamente já encontrou um NullPointerException. E, muito provavelmente, sua primeira reação foi: "Ah, é só verificar!". Assim nascem quilômetros de código como:

\n\n
if (user != null) {\n    if (user.getAddress() != null) {\n        String city = user.getAddress().getCity();\n        if (city != null) {\n            System.out.println(city.toUpperCase());\n        }\n    }\n}\n
\n\n

Esse código funciona. Mas é feio. Ele transforma a leitura da lógica em um suplício e a manutenção em um pesadelo. A pergunta "How do I avoid checking for nulls in Java?" no Stack Overflow acumulou milhares de visualizações não por acaso. Todo desenvolvedor Java, mais cedo ou mais tarde, se faz essa pergunta.

\n\n

A boa notícia: evitar verificações de null não só é possível, como é necessário. Java não é JavaScript, e temos ferramentas para escrever código limpo e seguro sem construções "defensivas". Vamos analisar todas elas — desde o conjunto básico até técnicas avançadas.

\n\n

1. Optional<T> — seu principal aliado

\n\n

A partir do Java 8, temos o Optional. É um contêiner que pode conter um valor ou estar vazio. Ele foi literalmente criado para evitar verificações de null e tornar o código mais declarativo.

\n\n

Como funciona?

\n\n

Em vez de retornar null de um método, retorne Optional. E em vez de verificações, use encadeamento de métodos.

\n\n
// Ruim\npublic String getCity(User user) {\n    if (user == null) return "Desconhecido";\n    Address address = user.getAddress();\n    if (address == null) return "Desconhecido";\n    return address.getCity();\n}\n\n// Bom\npublic Optional<String> getCity(User user) {\n    return Optional.ofNullable(user)\n            .map(User::getAddress)\n            .map(Address::getCity);\n}\n\n// Uso\nString city = getCity(algumUsuario).orElse("Desconhecido");\n
\n\n

Observe: nenhum if. O map só funciona se o valor não for null. Se em qualquer etapa encontrar null — a cadeia é interrompida e você obtém Optional.empty().

\n\n

Métodos populares do Optional

\n\n
    \n
  • orElse(T other) — retornar o valor ou uma alternativa
  • \n
  • orElseGet(Supplier<? extends T> other) — versão lazy, calculada apenas se necessário
  • \n
  • orElseThrow(Supplier<? extends X> exceptionSupplier) — lançar sua própria exceção
  • \n
  • ifPresent(Consumer<? super T> consumer) — executar uma ação se o valor existir
  • \n
  • filter(Predicate<? super T> predicate) — filtrar por uma condição
  • \n
\n\n
// Exemplo com filtro\nOptional<String> nome = Optional.of("Java");\nnome.filter(n -> n.startsWith("J"))\n    .ifPresent(System.out::println); // Exibirá "Java"\n
\n\n

Importante: Optional foi projetado para valores de retorno, não para campos de classe ou parâmetros de métodos. Não abuse.

\n\n

2. Objects.requireNonNull() — utilitário para contratos explícitos

\n\n

Às vezes, null é um erro e precisa ser detectado o mais cedo possível. Em vez de escrever verificações manualmente, use java.util.Objects.requireNonNull().

\n\n
public class UserService {\n    private final UserRepository repository;\n\n    public UserService(UserRepository repository) {\n        this.repository = Objects.requireNonNull(repository, \n            "UserRepository não deve ser nulo");\n    }\n\n    public User findById(Long id) {\n        Objects.requireNonNull(id, "ID não deve ser nulo");\n        return repository.findById(id);\n    }\n}\n
\n\n

Essa abordagem chama

Blogs

Book Recommendations