Verwendung von Optional für Null-Sicherheit
In diesem Schritt werden wir einen moderneren Ansatz zur Behandlung potenzieller null
-Werte in Java mithilfe der Optional
-Klasse untersuchen, die in Java 8 eingeführt wurde. Optional
ist ein Containerobjekt, das einen nicht-null
-Wert enthalten kann oder auch nicht. Es bietet eine Möglichkeit, das Vorhandensein oder Fehlen eines Werts deutlicher darzustellen, was dazu beitragen kann, das Risiko von NullPointerException
s zu verringern.
Während if (collection != null)
-Prüfungen in vielen Situationen völlig gültig und notwendig sind, kann Optional
Ihren Code lesbarer und ausdrucksstärker machen, insbesondere wenn es um Methoden geht, die einen Wert zurückgeben können oder auch null
zurückgeben können.
Schauen wir uns an, wie wir Optional
mit einer Sammlung verwenden können. Obwohl Optional
typischerweise für einzelne Werte verwendet wird, können Sie Szenarien antreffen, in denen eine Methode ein Optional<List<SomeObject>>
zurückgibt.
-
Öffnen Sie die Datei HelloJava.java
im WebIDE-Editor.
-
Ersetzen Sie den Inhalt durch folgenden Code, der die Verwendung von Optional
mit einer potenziell null
-Liste demonstriert:
import java.util.List;
import java.util.ArrayList;
import java.util.Optional; // Import Optional
public class HelloJava {
// A method that might return an Optional containing a list, or an empty Optional
public static Optional<List<String>> getNames(boolean includeNames) {
if (includeNames) {
List<String> names = new ArrayList<>();
names.add("Alice");
names.add("Bob");
return Optional.of(names); // Return an Optional containing the list
} else {
return Optional.empty(); // Return an empty Optional
}
}
public static void main(String[] args) {
// Case 1: Get names when includeNames is true
Optional<List<String>> namesOptional1 = getNames(true);
System.out.println("Checking namesOptional1:");
// Check if the Optional contains a value
if (namesOptional1.isPresent()) {
List<String> names = namesOptional1.get(); // Get the list from the Optional
System.out.println("List is present. Size: " + names.size());
// You can also check if the list itself is empty
if (names.isEmpty()) {
System.out.println("List is empty.");
} else {
System.out.println("List is not empty. First name: " + names.get(0));
}
} else {
System.out.println("List is not present (Optional is empty).");
}
System.out.println("---");
// Case 2: Get names when includeNames is false
Optional<List<String>> namesOptional2 = getNames(false);
System.out.println("Checking namesOptional2:");
if (namesOptional2.isPresent()) {
List<String> names = namesOptional2.get();
System.out.println("List is present. Size: " + names.size());
if (names.isEmpty()) {
System.out.println("List is empty.");
} else {
System.out.println("List is not empty. First name: " + names.get(0));
}
} else {
System.out.println("List is not present (Optional is empty).");
}
System.out.println("\nProgram finished.");
}
}
In diesem Code:
- Wir definieren eine Methode
getNames
, die ein Optional<List<String>>
zurückgibt. Diese Methode simuliert ein Szenario, in dem Sie eine Liste erhalten können oder auch nichts (repräsentiert durch ein leeres Optional
).
- In der
main
-Methode rufen wir getNames
mit true
und false
auf, um beide Fälle zu testen.
- Wir verwenden
namesOptional.isPresent()
, um zu prüfen, ob das Optional
eine Liste enthält.
- Wenn
isPresent()
true
ist, verwenden wir namesOptional.get()
, um die Liste abzurufen. Dies ist sicher, da wir bereits auf das Vorhandensein geprüft haben.
- Innerhalb des
isPresent()
-Blocks können wir dann Prüfungen an der Liste selbst durchführen, wie z. B. names.isEmpty()
.
-
Speichern Sie die Datei.
-
Kompilieren Sie das Programm im Terminal:
javac HelloJava.java
-
Führen Sie das Programm aus:
java HelloJava
Sie sollten eine Ausgabe ähnlich der folgenden sehen:
Checking namesOptional1:
List is present. Size: 2
List is not empty. First name: Alice
---
Checking namesOptional2:
List is not present (Optional is empty).
Program finished.
Diese Ausgabe zeigt, wie Optional
uns hilft, den Fall zu behandeln, in dem eine Liste überhaupt nicht zurückgegeben wird.
Optional
bietet auch andere nützliche Methoden zur Behandlung des Fehlens eines Werts, wie z. B.:
orElse(defaultValue)
: Gibt den Wert zurück, wenn er vorhanden ist, andernfalls einen Standardwert.
orElseGet(supplier)
: Gibt den Wert zurück, wenn er vorhanden ist, andernfalls das Ergebnis der supplier
-Funktion.
orElseThrow(exceptionSupplier)
: Gibt den Wert zurück, wenn er vorhanden ist, andernfalls wirft es eine Ausnahme, die von der exceptionSupplier
-Funktion erzeugt wird.
ifPresent(consumer)
: Führt die angegebene Aktion aus, wenn ein Wert vorhanden ist.
Ändern wir den Code, um ifPresent
zu verwenden, um die Liste auf eine kompaktere Weise zu behandeln, wenn sie vorhanden ist.
-
Öffnen Sie HelloJava.java
im Editor.
-
Ändern Sie die main
-Methode, um ifPresent
zu verwenden:
import java.util.List;
import java.util.ArrayList;
import java.util.Optional;
public class HelloJava {
public static Optional<List<String>> getNames(boolean includeNames) {
if (includeNames) {
List<String> names = new ArrayList<>();
names.add("Alice");
names.add("Bob");
return Optional.of(names);
} else {
return Optional.empty();
}
}
public static void main(String[] args) {
// Case 1: Get names when includeNames is true
Optional<List<String>> namesOptional1 = getNames(true);
System.out.println("Checking namesOptional1 using ifPresent:");
namesOptional1.ifPresent(names -> {
// This block only runs if namesOptional1 contains a list
System.out.println("List is present. Size: " + names.size());
if (names.isEmpty()) {
System.out.println("List is empty.");
} else {
System.out.println("List is not empty. First name: " + names.get(0));
}
});
if (!namesOptional1.isPresent()) { // Still need a check if you need to handle the absence case
System.out.println("List is not present (Optional is empty).");
}
System.out.println("---");
// Case 2: Get names when includeNames is false
Optional<List<String>> namesOptional2 = getNames(false);
System.out.println("Checking namesOptional2 using ifPresent:");
namesOptional2.ifPresent(names -> {
System.out.println("List is present. Size: " + names.size());
if (names.isEmpty()) {
System.out.println("List is empty.");
} else {
System.out.println("List is not empty. First name: " + names.get(0));
}
});
if (!namesOptional2.isPresent()) {
System.out.println("List is not present (Optional is empty).");
}
System.out.println("\nProgram finished.");
}
}
Wir haben die Struktur if (namesOptional.isPresent()) { ... namesOptional.get() ... }
durch namesOptional.ifPresent(names -> { ... })
ersetzt. Der Code innerhalb des Lambda-Ausdrucks (names -> { ... }
) wird nur ausgeführt, wenn das Optional
einen Wert enthält. Wir haben weiterhin eine if (!namesOptional.isPresent())
-Prüfung hinzugefügt, um den Fall zu behandeln, in dem das Optional
leer ist, da ifPresent
nur den Fall des Vorhandenseins behandelt.
-
Speichern Sie die Datei.
-
Kompilieren Sie das Programm:
javac HelloJava.java
-
Führen Sie das Programm aus:
java HelloJava
Die Ausgabe sollte die gleiche wie zuvor sein, was zeigt, dass ifPresent
eine alternative Möglichkeit bietet, das Vorhandensein eines Werts in einem Optional
zu behandeln.
Die Verwendung von Optional
kann die Absicht Ihres Codes dahingehend klarer machen, ob ein Wert fehlen kann, und es ermutigt Sie, dieses Fehlen explizit zu behandeln, wodurch die Wahrscheinlichkeit unerwarteter NullPointerException
s verringert wird.