Wieso sollte man Null-Prüfungen nicht mit Optional-Objekten nutzen?

Zrebna

Bekanntes Mitglied
Hi!

Dieser SonarQube Warnhinweis hat mein Interesse erneut geweckt - siehe Bild im Anhang.

Folgendes ist in dem Code passiert:

Java:
public void foo(Optional<String> identifier) {
    if(identifier == null) {
        // some action
    }
}

Ich würde hier nie ein Optional-Objekt auf Null checken sondern so:


Java:
if(!identifier.isPresent()) {...}

// oder
if(identifier.isEmpty()) {...}

Aber ich will verstehen warum wir das im Kontext einer langfristigen Verringerung von Fehleranfälligkeit einer Software so machen und nicht wie im ersten Code-Snippet?

Mich interessiert an der Stelle nicht, dass wir Optional-Objekte nicht auf Null checken, weil wir gegen irgendwelche Verträge verstoßen, Verwirrung kreiieren oder die Grundidee, dass Optionals an Nulls "ersetzen".

Das sind alles gute Gründe, aber ich will verstehen, warum uns diese Empfehlung dabei hilft langfristig Fehler zu vermeiden?
Am besten an einem konkreten Beispiel.

Lg
Zrebna
 

Anhänge

  • OptionalNoUsageWithNull.PNG
    OptionalNoUsageWithNull.PNG
    20,6 KB · Aufrufe: 0
Zuletzt bearbeitet:

Oneixee5

Top Contributor
Zunächst: Optional soll man nicht in Parametern verwenden. Optional ist nur sinnvoll als Rückgabe. Damit erzwingt man die Behandlung von null, falls es keine andere sinnvolle Rückgabelmöglichkeit gibt. Optional als Parameter ist vermeidbarer Overhead. Die Verwendung von optionalen Parametern, die eine bedingte Logik innerhalb der Methoden verursachen, ist buchstäblich kontraproduktiv. Weiterhin ist die Notwendigkeit, ein Argument in ein Optional zu packen, für den Compiler suboptimal und führt zu einem unnötigen Wrapping.
 

Oneixee5

Top Contributor
Ich würde hier nie ein Optional-Objekt auf Null checken sondern so:


Java:
Code:
if(!identifier.isPresent()) {...}

// oder
if(identifier.isEmpty()) {...}
So etwas würde nur in Ausnahmefällen machen. Ich würde eher eine Verzweigung verwenden wie z.B. orElseGet, orElseThrow oder ifPresentOrElse.
Diese if-else-Spagetti-Treppen-Konstrukte will man ja gerade vermeiden. Man will ja damit besseren Code mit weniger Komplexität erreichen.
 

KonradN

Super-Moderator
Mitarbeiter
Damit erzwingt man die Behandlung von null, falls es keine andere sinnvolle Rückgabelmöglichkeit gibt.
Das ist wirklich der ganz wichtige Kernpunkt. Und das führt aus meiner Sicht zu paar Schlussfolgerungen:
a) es gibt nie eine null „Zuweisung“ zu einem Optional. (Zuweisung im erweiterten Sinn, also auch automatische Initialisierung oder Return Befehl.
b) es gibt keine Optional Fields (die würden ja automatisch mit null initialisiert)
c) Deklaration und Nutzung ist beieinander - Also Methode mit Rückgabe oder lokale Variable

Und durch diese Vorgaben können statische Codeanalysen da direkt meckern. Das hilft (neben den Code Reviews mit obligatorischer Peitsche)

Bezüglich Parameter: eher unüblich, aber auch das geht …. Gerade wenn man viel mit Optionals macht und es die Methode ggf. vereinfacht (s.u.). Ich habe es nur, wenn ich bei einem Refactoring hat an der Stelle ein Optional habe und weitere Refactorings den Code in erster Linie aufblasen / unleserlich machen (Vermutlich oft einfach nur ein Ausdruck für: Ich bin im Augenblick zu faul es richtig zu machen. In Legacy Code bricht man halt ab sonst hat man Jahre Arbeit vor sich …)

Aber ja - das sind best Practices aber sie helfen - zusammen mit dem zweiten Hinweis:
Ich würde eher eine Verzweigung verwenden wie z.B. orElseGet, orElseThrow oder ifPresentOrElse.
Das ist das A und O dabei, Code soll ja übersichtlich sein. Und das ist eben der zweite, sehr positive Punkt!

Also zusammengefasst: eigentlich war schon alles gesagt - und ich habe es nur mit etwas eigenen Worten noch einmal versucht zu erläutern.
 

Hough

Mitglied
b) es gibt keine Optional Fields (die würden ja automatisch mit null initialisiert)
Würd ich nicht ganz so eng sehen. Schließlich läßt sich ein Optional-Feld ja direkt mit = Optional.empty() initialisieren. Und das kann man durchaus gebrauchen, wenn es den Fall gibt, dass ein Wert unbekannt ist. Eine Alternative wäre das null-object-Pattern.
 

Oneixee5

Top Contributor
Nochmal, das macht keinen Sinn:
Java:
    Optional<String> foo(String param) {
        Optional<String> ret = Optional.empty();
        ret = Optional.of(doAnything(param));
        return ret;
    }

Java:
    Optional<String> foo(String param) {
        return Optional.of(doAnything(param));
    }
 

Hough

Mitglied
Nochmal, das macht keinen Sinn:
Java:
    Optional<String> foo(String param) {
        Optional<String> ret = Optional.empty();
        ret = Optional.of(doAnything(param));
        return ret;
    }

Java:
    Optional<String> foo(String param) {
        return Optional.of(doAnything(param));
    }
Es ging um Felder in Objektklassen, nicht um lokale Variablen.
 

Hough

Mitglied
Das ist doch das selbe Prinzip.
Wie Du meinst. Ist ja auch ne Frage persönlicher Präferenzen. Null, Null-Object-Pattern, Optionals -> drei Möglichkeiten, um anzuzeigen, dass ein Wert nicht existiert. Kommt halt vor, dass in einem Objekt ein Wert erst später berechnet wird, aber von mehr als nur 1 Methode gebraucht wird. z.B. wenn etwas berechnet und dann später in der Swing'schen paintComponent-Methode gezeichnet wird, sofern der Wert existiert.
 

Hough

Mitglied
Das ist doch das selbe Prinzip. Optional ist nur ein Wrapper, den muss man nicht halten. Man kann die Instanz nicht mehr ändern, wenn sie einmal erstellt wurde.
Jetzt noch meine Antwort auf den von Dir nachträglich hinzugefügten Teil ;)
Ich vermute, wir reden gerade aneinander vorbei. Den Wert innerhalb des Optionals kann man natürlich nicht ändern. Aber wenn das Optional ein Feld eines Objektes ist, kann das Objekt natürlich jederzeit eine neue Instanz eines Optionals erzeugen und seinem Feld zuweisen.
 

Zrebna

Bekanntes Mitglied
Zunächst: Optional soll man nicht in Parametern verwenden. Optional ist nur sinnvoll als Rückgabe. Damit erzwingt man die Behandlung von null, falls es keine andere sinnvolle Rückgabelmöglichkeit gibt. Optional als Parameter ist vermeidbarer Overhead. Die Verwendung von optionalen Parametern, die eine bedingte Logik innerhalb der Methoden verursachen, ist buchstäblich kontraproduktiv. Weiterhin ist die Notwendigkeit, ein Argument in ein Optional zu packen, für den Compiler suboptimal und führt zu einem unnötigen Wrapping.
Im Idealfall "erzwingt" man sie, weil die Verwendung eines Optionals ja quasi dem Entwickler sagen soll, dass etwas "leer" sein kann bzw. keinen Wert enthalten könnte, worauf der Entwickler automatisch prüft, ob das Optional-Objekt leer ist oder einen Wert hat. Außer den Entwickler "weigert" sich, wie hier in der Abbildung unten.


Genau hier finde ich das Warning 100% relevant im Sinne einer Fehlervorbeugung, weil durch die fehlende Überprüfung an dieser Stelle tatsächlich ein Fehler in Form einer NoSuchElelementException auftreten kann. Richtig?


PreventingNoSuchElementException.PNG
 

Oneixee5

Top Contributor
Der Fall ist doch klar. Es wird an die Methode ein Optional übergeben. Dieser Umstand selbst macht deutlich, dass hier etwas zu beachten ist. Der Vorschlag von Sonar ist so semi. Sonar kennt aber auch nicht den Sinn deines Programm. Also macht Sonar sichere Vorschläge.

So etwas würde ein erfahrener Entwickler aber nicht machen:
Java:
if(!identifier.isPresent()) {...}

// oder
if(identifier.isEmpty()) {...}

Wenn man funktional programmiert, dann sollte man das auch richtig machen und sich darauf einlassen. Je nach Context kann man das verschieden behandeln. Hier eine Möglichkeit von vielen:
Java:
    void foo(Optional<Long> oId) {
        oId.ifPresentOrElse(this::doWithId, this::doWithoutId);      
    }

    void doWithId(Long id) {
        // ->
    }
  
    void doWithoutId() {
        // ->
    }
Hier verzweigt man im Programm, je nachdem auf welchen Zustand man trifft. Es wird keine Methode mit X-Zeilen Code für den if- oder else-Zweig erstellt. Es erfolgt eine einfache Entscheidung: wenn das mache das, ansonsten das. So kann man auch super mit Vererbung agieren, denn die Logik ist immer klar und wird immer verstanden.

Für Java-Programmierer ist das Vorgehen erstmal etwas schwer oder wie ein Fremdkörper. Man muss sich darauf einlassen um den Flow zu verstehen. Das liegt einfach daran, das Java auch schon eine alte Sprache ist und keine breaking changes will. Code, der in älteren Versionen gültig war, soll auch zukünftig gültig sein. (Das ist keine Kritik) Also sickert diese Art, etwas durchzuführen langsamer in Java ein, als in junge dynamische Sprachen, wie z.B. Golang oder Rust. Dort sind quasi alle Api's auf diese Art gestaltet. Ein if-else findet man dort, bei guten Leuten, so gut wie nicht. Die Arbeitsweise ist stabil und fehlerresistent - und darum geht es am Ende. Jede Möglichkeit muss behandelt werden - den Milliarden-Dollar-Fehler kann man damit schon mit dem Compiler vermeiden.
Ein anderes Problem sind die Java-Kurse oder Lehrer. Es wird auf Neuerungen in der Sprache oft sehr wenig Wert gelegt. Ich habe erst kürzlich einen Kurs gesehen, welcher mit Java 1.6 aufgebaut war. Der Kursleiter hielt den Kurs für großartig. Was aber dann im Extremfall passiert: der Kunde lässt unseren Code von seinem Experten prüfen - dieser kann aber unseren Code gar nicht lesen/interpretieren ...
 
Zuletzt bearbeitet:
Ähnliche Java Themen
  Titel Forum Antworten Datum
Zrebna Wieso sind eigentlich JUnit-Tests in src/test/java platziert - nur Konvention? Allgemeine Java-Themen 7
P Wieso benutzen PriorityQueues Heaps? Allgemeine Java-Themen 2
Y Wieso krieg ich die Unit Tests nicht hin Allgemeine Java-Themen 55
I Wieso funktioniert das nich? Allgemeine Java-Themen 5
F Input/Output NullPointerException, aber wieso? [Apache POI] Allgemeine Java-Themen 11
R MAC-Adresse eindeutig für einen PC ? Bezug zu Netzwerk, wieso ? Allgemeine Java-Themen 7
P Best Practice Wieso funktioniert der Modulo - Operator nicht? Allgemeine Java-Themen 2
J Jasper ireport - wieso beendet die Anwendung wenn ich die Preview schließe Allgemeine Java-Themen 1
I Interface Interface / Klasse - wieso Abstract? Allgemeine Java-Themen 13
A Methoden Generische Methode mit Arrays - Source Compatibility 1.7 benötigt, wieso? Allgemeine Java-Themen 3
S RemoteException wieso ? Allgemeine Java-Themen 6
J if else Anweisung macht nicht was es soll. Wieso? Allgemeine Java-Themen 10
P wieso kann ich auf bluej exportieren aber auf eclipse nicht? Allgemeine Java-Themen 2
DEvent Wieso ist Javadoc mit Html Tags? Allgemeine Java-Themen 47
D java.util.InputMismatchException im Scanner -wieso? Allgemeine Java-Themen 5
E Wieso returnt das hier 1? Allgemeine Java-Themen 3
DStrohma [Erledigt] Wieso kann ich Taste 'ENTER' in JTable nicht belegen? Allgemeine Java-Themen 2
C Wieso funktioniert das? Allgemeine Java-Themen 6
W Wieso funktioniert dieser Code hier? Allgemeine Java-Themen 6
S Wieso stehen in der API immer wieder abstrakte Methoden ? Allgemeine Java-Themen 7
lacyuu Schleife hängt sich auf, wieso?? Allgemeine Java-Themen 2
V Wieso meckert FindBugs da? Allgemeine Java-Themen 7
P Wieso HashMap-Zugriff mit Object, statt mit MyObject? Allgemeine Java-Themen 12
V Wieso Heap Space Problem? Allgemeine Java-Themen 14
J Wieso implementiert HTTPServlet Serializable? Allgemeine Java-Themen 2
P Wieso skalieren diese beiden Threads unterschiedlich gut? Allgemeine Java-Themen 16
zilti Wieso geht der StreamReader/Writer nicht? Allgemeine Java-Themen 5
T Wieso erfolgt keine Ausgabe. /Excel Allgemeine Java-Themen 19
G wieso wird der String des StringBuilder immer länger? Allgemeine Java-Themen 2
G wieso "implements" Allgemeine Java-Themen 13
S Problem mit generics -> ClassCastException und ka wieso Allgemeine Java-Themen 20
G Übergabe funzt nicht, aber wieso? Allgemeine Java-Themen 3
G NullPointer ? wieso? Allgemeine Java-Themen 7
I Wieso läuft Programm bei Kollegen aber nicht bei mir? Allgemeine Java-Themen 10
MiMa Was sollte man ins JavaDoc implementieren?? Allgemeine Java-Themen 17
MiMa Wie sollte am besten ein Datum gespeichert werden? Allgemeine Java-Themen 8
R In der Ausgabe sollte anstelle des obersten Sterns ein "+" stehen nur scheitere ich bei der Implementierung Allgemeine Java-Themen 9
T Multithreading: Wie viele Threads sollte ich erstellen? Allgemeine Java-Themen 12
J wie sollte man sinnvoll seinen Code aufteilen Allgemeine Java-Themen 6
R Input/Output java.io.EOFException, obwohl sie abgefangen sein sollte? Allgemeine Java-Themen 3
DaniSahne96 Threads Code funktioniert nicht wie er sollte Allgemeine Java-Themen 9
D Wann sollte ich statische Methoden und Variablen benutzen? Allgemeine Java-Themen 44
R Syntax Error, der keiner sein sollte Allgemeine Java-Themen 12
V Fortbildungen oder Zertifikate in Java die man haben sollte? Allgemeine Java-Themen 17
André B. Was sollte eine Template Engine können? Allgemeine Java-Themen 3
A Warum gibts die Main und was sollte drin stehen? Allgemeine Java-Themen 31
B Was sollte ich benutzen Vektor oder ArrayList? Allgemeine Java-Themen 5
A Weshalb man Parameter auf Gültigkeit prüfen sollte Allgemeine Java-Themen 6
D NullPointerException wo keine sein sollte. Allgemeine Java-Themen 2
Zrebna SonarLint: Warum kein Null-Referencing-CodeSmell-Hint hier? Allgemeine Java-Themen 23
OnDemand Java String in Hashmap als Key NULL Allgemeine Java-Themen 27
8u3631984 Argument Captor liefert NULL zurück Allgemeine Java-Themen 2
E Class.getResourceAsStream() gibt null zurück Allgemeine Java-Themen 2
Zrebna Gibt es eine Möglichkeit eine NPE zu vermeiden, wenn null returned wird? Allgemeine Java-Themen 3
J Zahlen Abstand zur Null bestimmen Allgemeine Java-Themen 11
C javax.mail.Message message.setreplyto() null setzen (keine replyto Adresse) Allgemeine Java-Themen 25
S An internal error occurred during: Launching null argument Allgemeine Java-Themen 1
S Validation Null aber nicht Blank und muss Email sein Allgemeine Java-Themen 22
L Google Guice Field Injection returns null Allgemeine Java-Themen 2
E RMI NULL-Pointer-Exeception wenn der RMI-Proxy eine Methode deligiert Allgemeine Java-Themen 2
J Java Objekte = null, Garbagecollector Allgemeine Java-Themen 12
N MsgPack - Null Check Allgemeine Java-Themen 5
T JasperReports mit Null Pointer Allgemeine Java-Themen 3
DanielsLPecke Compiler-Fehler Warum ist der String null? Allgemeine Java-Themen 10
M Warten bis Variabel nicht null ist Allgemeine Java-Themen 18
Thallius Simple JSON Parser Error null Allgemeine Java-Themen 6
M Null byte in verschiedenen charsets Allgemeine Java-Themen 2
S Lambda Ausdrücke: @FunctionalInterface Instanzen auf null prüfen Allgemeine Java-Themen 9
B [Android] EditText-Object ist null - Nimmt nicht den Wert des enthaltenen Textfeldes ein Allgemeine Java-Themen 2
D Java Process OutputStream ist null Allgemeine Java-Themen 4
O log4j, Problem bei Ausgabe null-Wert Allgemeine Java-Themen 0
T InvalidClassException - Read null attempting to read class descriptor for object Allgemeine Java-Themen 8
D Problem mit führender Null bei Schlüsselerzeugung Allgemeine Java-Themen 5
T Variablenübergabe liefert immer null Allgemeine Java-Themen 13
K Image beim catchen ist immer null Allgemeine Java-Themen 9
B Load of Known null Value Allgemeine Java-Themen 9
W Kleine Frage zu Null-Pinter-Exception Allgemeine Java-Themen 21
T Array Sortieren (null Werte ans Ende) Allgemeine Java-Themen 2
S Null Pointer Exception bei BufferedReader Allgemeine Java-Themen 4
M Objekt prüfen auf null ->Invocation Target Exception??? Allgemeine Java-Themen 2
Tobse Vererbung null aus Elternklasse "dominant"? Allgemeine Java-Themen 15
E Queue: Wie kann hier ein null-Pointer Exception auftreten?! Allgemeine Java-Themen 11
I newInstance() liefert null zurück Allgemeine Java-Themen 4
R Attribut null Allgemeine Java-Themen 6
C Regex: Zahl ohne führende Null Allgemeine Java-Themen 13
E rückgabewert ist immer null Allgemeine Java-Themen 2
N List auf null prüfen Allgemeine Java-Themen 2
TiME-SPLiNTER Von Unix, InputStreams und Null Bytes Allgemeine Java-Themen 2
R dateFormat - Uhr fängt nicht bei null an Allgemeine Java-Themen 2
P Null in ArrayList Allgemeine Java-Themen 3
N Strings mit null wiedergabe Splitten Allgemeine Java-Themen 4
mongole Formatter + null Allgemeine Java-Themen 4
X Prozess-Objekt nach Ausführung der destroy-Methode null oder nicht null ? Allgemeine Java-Themen 10
A Umgang mit null Allgemeine Java-Themen 16
L Object = null? Allgemeine Java-Themen 16
L null pointer exception Allgemeine Java-Themen 10
nrg Leere Objektreferenz mit != null vergleichen Allgemeine Java-Themen 4
J Null Pointer in der compare-Methode des Comparators? Allgemeine Java-Themen 18
T Set.contains() auch false wenn value == null? Allgemeine Java-Themen 4
D Matrix, ArrayList, null-Zellen Allgemeine Java-Themen 6

Ähnliche Java Themen

Neue Themen


Oben