[EN] Warum Senior-Engineers fast nie `!= null` schreiben

Julian | Oct 3, 2025 min read

Hello everyone,

If you’ve been around the Java world for a while, you know the picture: your code is littered with defensive queries like:

if (user != null) {
    // mach was Sinnvolles
}

It looks harmless. In fact, it’s probably one of the first things you learn to keep the dreaded NullPointerException at bay. But take a look at the production code of experienced engineers: You’ll notice that senior engineers almost never write != null.

Why is that? And what do they do instead? The answer lies not just in the syntax, but in a fundamental mindset shift.


1. != null is a code smell

The explicit != null check is a low-level defensive programming. It is loud, repetitive and overshadows the actual business logic. As soon as you start throwing it everywhere, the code quickly becomes unreadable and maintenance-intensive:

// Die Null-Check-Pyramide an einem Konfigurationsobjekt
if (config != null && config.getConnection() != null && config.getConnection().getTimeout() > 0) {
    logger.info("Verbindungs-Timeout ist: " + config.getConnection().getTimeout());
}

This so-called “zero-check pyramid” is a red flag. It directs the focus away from the actual intention and towards endless conditions.


2. Seniors rely on abstractions

Instead of constantly checking for null, experienced engineers use language features and design principles that eliminate null from everyday code.

a) Use Optional (Java 8+)

Optional<T> makes the absence of a value explicit and forces the caller to handle this case gracefully.

New example: Retrieve and process an HTTP header.

// Simulierter Abruf eines Headers, der fehlen koennte
Optional<String> authHeader = request.getHeader("Authorization"); 

authHeader.filter(h -> h.startsWith("Bearer "))
          .map(h -> h.substring(7))
          .ifPresentOrElse(
              token -> System.out.println("Token gefunden: " + token),
              () -> System.out.println("Kein Bearer Token vorhanden.")
          );

No != null, no pyramid. Just a fluid chain that reads naturally.

b) Objects.nonNull und Objects.requireNonNull

Rather than writing their own terms, seniors prefer utility methods that clearly express their intent.

New example: Validation of method parameters and filtering of collections.

// Feste Garantie am Beginn einer Methode (anstelle von if (param == null))
public void processItems(List<Item> items) {
    Objects.requireNonNull(items, "Die Item-Liste darf nicht null sein.");
    
    // Entfernen von Null-Eintraegen in einer Liste
    items.stream()
         .filter(Objects::nonNull)
         .map(Item::getName)
         .forEach(System.out::println);
}

Readable, expressive and free of boilerplate code.

c) Defensive constructors and immutability

Instead of spreading != null checks throughout the code, experienced engineers enforce invariants at the boundaries of the object.

New example: Creating an immutable configuration object.

public final class ServerConfig {
    private final String host;
    private final Integer port;

    public ServerConfig(String host, Integer port) {
        // Hier wird die Bedingung einmalig und klar durchgesetzt
        this.host = Objects.requireNonNull(host, "Host-Name ist erforderlich");
        this.port = Objects.requireNonNull(port, "Port-Nummer ist erforderlich");
    }
    // ... danach muss host und port nie wieder auf null geprueft werden
}

Once validated during design, you never have to check again - because the values ​​are guaranteed to be non-zero.


3. Framework-Level Null Safety

In enterprise projects, seniors use the support of the frameworks to postpone zero checks at compile time:

  • Springs @NonNull and @Nullable annotations: These clearly communicate intent and integrate seamlessly with IDE warnings.
  • Kotlin’s null safety: When you mix Java and Kotlin, Kotlin simply prevents unsafe null code from compiling unless you handle it explicitly.
  • JSR 305 / Checker Framework: Tools that enforce null contracts at compile time.

4. The real mindset shift

The key is mindset. Senior engineers don’t see null as “just another state”; they see it as a design flaw.

Instead of guarding against null everywhere, they push null handling to the edges of the system (e.g. when interacting with a database, an external API, or legacy code). Within the core domain they strive for null-free objects.

This leads to:

  • Clearer, more readable code
  • Fewer surprises at runtime
  • A domain model that more accurately reflects reality

5. When != null still makes sense

Of course there are exceptions. You will still see != null in low-level code, in performance-critical loops, or when integrating legacy systems. But in business logic it is the last resort – not the norm.

Final Thoughts

Next time you catch yourself typing != null, stop and ask yourself:

👉 “Can I restructure this so that null isn’t even an option?”

👉 “Can I use Optional, Objects or Annotations instead?”

👉 “Can I force non-zero at the object boundary?”

This shift in thinking is one of those small but powerful habits that separates senior engineers from the rest. They don’t just treat null - they design it out of existence.

💡 Pro tip: Do a quick search in your codebase for != null. Every hit is an opportunity to refactor toward cleaner, safer, and more maintainable code.