Warum Senior-Engineers fast nie `!= null` schreiben

Julian | Oct 3, 2025 min read

Hallo zusammen,

wenn ihr schon eine Weile in der Java-Welt unterwegs seid, kennt ihr das Bild: Euer Code ist übersät mit defensiven Abfragen wie:

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

Es sieht harmlos aus. Tatsächlich ist es wahrscheinlich eines der ersten Dinge, die man lernt, um die gefürchtete NullPointerException in Schach zu halten. Aber werft mal einen Blick in den Produktions-Code erfahrener Engineers: Ihr werdet feststellen, dass Senior-Engineers fast nie != null schreiben.

Warum ist das so? Und was machen sie stattdessen? Die Antwort liegt nicht nur in der Syntax, sondern in einem fundamentalen Mindset-Shift.


1. != null ist ein Code Smell

Der explizite != null-Check ist eine Low-Level-Verteidigungsprogrammierung. Er ist laut, repetitiv und überlagert die eigentliche Business-Logik. Sobald ihr anfangt, ihn überall zu streuen, wird der Code schnell unlesbar und wartungsintensiv:

// 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());
}

Diese sogenannte “Null-Check-Pyramide” ist eine rote Flagge. Sie lenkt den Fokus weg von der eigentlichen Intention und hin zu endlosen Konditionen.


2. Senioren setzen auf Abstraktionen

Anstatt ständig nach null zu prüfen, nutzen erfahrene Engineers Sprach-Features und Design-Prinzipien, die null aus dem täglichen Code eliminieren.

a) Nutze Optional (Java 8+)

Optional<T> macht die Abwesenheit eines Wertes explizit und zwingt den Aufrufer, diesen Fall elegant zu behandeln.

Neues Beispiel: Abrufen und Verarbeiten eines HTTP-Headers.

// 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.")
          );

Kein != null, keine Pyramide. Nur eine flüssige Kette, die sich natürlich liest.

b) Objects.nonNull und Objects.requireNonNull

Anstatt eigene Konditionen zu schreiben, bevorzugen Senioren Utility-Methoden, die ihre Absicht klar ausdrücken.

Neues Beispiel: Validierung von Methoden-Parametern und Filterung von Sammlungen.

// 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);
}

Lesbar, ausdrucksstark und befreit von Boilerplate-Code.

c) Defensive Konstruktoren und Immutability

Anstatt != null-Checks über den ganzen Code zu verteilen, erzwingen erfahrene Engineers Invarianten an den Grenzen des Objekts.

Neues Beispiel: Erstellung eines unveränderlichen Konfigurationsobjekts.

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
}

Einmal bei der Konstruktion validiert, muss man nie wieder prüfen – weil garantiert ist, dass die Werte non-null sind.


3. Framework-Level Null Safety

In Enterprise-Projekten nutzen Seniors die Unterstützung der Frameworks, um Null-Checks zur Compile-Zeit zu verschieben:

  • Springs @NonNull und @Nullable Annotationen: Diese kommunizieren die Absicht klar und integrieren sich nahtlos in IDE-Warnungen.
  • Kotlins Null-Safety: Wenn man Java und Kotlin mischt, verhindert Kotlin schlichtweg, dass unsicherer Null-Code kompiliert wird, es sei denn, man behandelt ihn explizit.
  • JSR 305 / Checker Framework: Tools, die Null-Verträge bereits zur Compile-Zeit durchsetzen.

4. Der wahre Mindset-Shift

Der Schlüssel liegt in der Denkweise. Senior-Engineers sehen null nicht als “nur einen weiteren Zustand”; sie sehen es als ein Design-Fehler.

Anstatt überall gegen null zu wachen, drängen sie das Null-Handling an die Ränder des Systems (z.B. bei der Interaktion mit einer Datenbank, einer externen API oder Legacy-Code). Innerhalb des Kern-Domains streben sie nach null-freien Objekten.

Das führt zu:

  • Klarerem, lesbarerem Code
  • Weniger Überraschungen zur Laufzeit
  • Einem Domain-Modell, das die Realität genauer widerspiegelt

5. Wann != null doch noch Sinn macht

Natürlich gibt es Ausnahmen. Ihr werdet != null immer noch sehen in Low-Level-Code, in Performance-kritischen Schleifen oder bei der Integration von Legacy-Systemen. Aber in der Business-Logik ist es der letzte Ausweg – nicht die Norm.

Abschließende Gedanken

Wenn ihr euch das nächste Mal dabei ertappt, wie ihr != null tippt, haltet inne und fragt euch:

👉 “Kann ich das umstrukturieren, sodass null gar keine Option ist?”

👉 “Kann ich stattdessen Optional, Objects oder Annotationen verwenden?”

👉 “Kann ich Non-Null bereits an der Objektgrenze erzwingen?”

Diese Verschiebung im Denken ist eine dieser kleinen, aber mächtigen Gewohnheiten, die Senior-Engineers vom Rest unterscheiden. Sie behandeln null nicht nur – sie designen es aus der Existenz hinaus.

💡 Pro-Tipp: Sucht mal schnell in eurer Codebase nach != null. Jeder Treffer ist eine Gelegenheit zum Refactoring hin zu saubererem, sicherem und wartbarerem Code.