Cómo dejar de comprobar null en Java y no volverse loco

Entrenador de Python en Línea para Principiantes

Aprende Python fácilmente sin sobrecargarte de teoría. Resuelve tareas prácticas con verificación automática, recibe pistas y escribe código directamente en el navegador, sin instalar nada.

Start Course

La maldición de null: ¿por qué escribimos lo mismo una y otra vez?

\n\n

Si escribes en Java más de una semana, seguramente te has encontrado con NullPointerException. Y, muy probablemente, tu primera reacción fue: «¡Ajá, solo necesito comprobarlo!». Así nacen kiló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

Este código funciona. Pero es feo. Convierte la lectura de la lógica en un suplicio y el mantenimiento en una pesadilla. La pregunta «How do I avoid checking for nulls in Java?» en Stack Overflow ha acumulado miles de visitas no por casualidad. Todo desarrollador Java tarde o temprano se la plantea.

\n\n

La buena noticia: evitar las comprobaciones de null no solo es posible, sino necesario. Java no es JavaScript, y tenemos herramientas para escribir código limpio y seguro sin construcciones «defensivas». Analicémoslas todas, desde el conjunto básico hasta las técnicas avanzadas.

\n\n

1. Optional<T> — tu principal aliado

\n\n

Desde Java 8, tenemos Optional. Es un contenedor que puede contener un valor o estar vacío. Está literalmente diseñado para evitar comprobaciones de null y hacer el código más declarativo.

\n\n

¿Cómo funciona?

\n\n

En lugar de devolver null desde un método, devuelve un Optional. Y en lugar de comprobaciones, usa cadenas de métodos.

\n\n
// Malo\npublic String getCity(User user) {\n    if (user == null) return "Unknown";\n    Address address = user.getAddress();\n    if (address == null) return "Unknown";\n    return address.getCity();\n}\n\n// Bueno\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(someUser).orElse("Unknown");\n
\n\n

Observa: ni un solo if. map solo funciona si el valor no es null. Si en cualquier paso aparece un null, la cadena se interrumpe y obtienes Optional.empty().

\n\n

Métodos populares de Optional

\n\n
    \n
  • orElse(T other) — devuelve el valor o una alternativa
  • \n
  • orElseGet(Supplier<? extends T> other) — versión perezosa, se calcula solo si es necesario
  • \n
  • orElseThrow(Supplier<? extends X> exceptionSupplier) — lanza tu propia excepción
  • \n
  • ifPresent(Consumer<? super T> consumer) — ejecuta una acción si el valor está presente
  • \n
  • filter(Predicate<? super T> predicate) — filtra según una condición
  • \n
\n\n
// Ejemplo con filtro\nOptional<String> name = Optional.of("Java");\nname.filter(n -> n.startsWith("J"))\n    .ifPresent(System.out::println); // Imprime "Java"\n
\n\n

Importante: Optional está diseñado para valores de retorno, no para campos de clase o parámetros de métodos. No abuses de él.

\n\n

2. Objects.requireNonNull() — utilidad para contratos explícitos

\n\n

A veces null es un error y debe detectarse lo antes posible. En lugar de escribir comprobaciones manualmente, usa 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 must not be null");\n    }\n\n    public User findById(Long id) {\n        Objects.requireNonNull(id, "ID must not be null");\n        return repository.findById(id);\n    }\n}\n
\n\n

Este enfoque llama

Blogs

Book Recommendations