Optional
Motivation
Die Tatsache, dass eine Referenz in Java auf ein Objekt zeigen kann oder null sein, macht die Programmierung für Anfänger schwierig. Aber auch Profis kämpfen mit der null-Referenz, die eine Quelle vieler Fehler sein kann. Der Erfinder dieser Referenz nennt sie rückblickend sein „billion-dollar mistake“.
Tony Hoare, 2009
Andere Programmiersprachen, z. B. Ruby, haben den Fehler nicht gemacht und kennen keine null-Referenz. In Ruby gibt es zwar nil, dies ist aber ein normales Objekt, mit Methoden und Eigenschaften.
Optional
In Java kann der Datentyp Optional verwendet werden, um auszudrücken, dass ein Wert möglicherweise leer sein kann. Im Gegensatz zu null als leerem Wert, ist Optional eine explizite Möglichkeit, um auszudrücken, dass ein Wert nicht vorhanden sein kann und ermöglicht dadurch eine klarere und sicherere Programmierung.
java.util.Optional bietet einen sicheren Ersatz für null
Optional.of(...)- erzeugt ein neues Optional mit einem Wert
- ist der Wert
nullwird eineNullpointerExceptiongeworfen Optional.ofNullable(...)erzeugt ein neuesOptional- wenn das übergebene Objekt
nullist, wird einOptional.empty()zurückgegeben - wenn das übergebene Objekt nicht
nullist, wird einOptional.of(...)zurückgegeben Optional.empty()erzeugt ein neues Optional, das leer ist
isPresent()prüft, ob ein Wert vorhanden istisEmpty()zeigt an, dass kein Wert vorhanden istget()- liest den Wert aus dem
Optionalaus - ist kein Wert vorhanden, gibt es eine Ausnahme vom Typ
NoSuchElementException orElse(...)führt einget()- wenn kein Wert vorhanden ist, wird der übergebene Wert geliefert
- wenn ein Wert vorhanden ist, wird dieser zurückgegeben
Optional kann verwendet werden, um die Fehleranfälligkeit in Java-Programmen zu reduzieren, indem es den Programmierer:innen ermöglicht, Fehler zu behandeln oder auszulösen, wenn ein Wert nicht vorhanden ist.
Ein weiteres Beispiel ist die Rückgabe von Werten aus einer Methode, wo ein Ergebnis nicht immer garantiert werden kann. Anstatt null zurückzugeben, könnte man eine Optional-Instanz zurückgeben, um auszudrücken, dass das Ergebnis optional ist.
Beispielhafte Verwendung
class Person {
private Person partner;
Person(Person partner) { this.partner = partner; }
Person() { this(null); };
Optional<Person> getPartner() {
return Optional.ofNullable(partner);
}
}
Bei dem Rückgabetyp Optional<Person> von getPartner() wird ein Typ-Parameter verwendet, weil Optional ein generischer Datentyp ist. Diese werden wir in einem späteren Kapitel betrachten. Hier muss die Information genügen, dass man durch das <Person> gestlegen kann, welchen Typ das Objekt hat, welches von Optional verwaltet wird.
Person peter = new Person();
Person klaus = new Person(peter);
Person hans = new Person();
System.out.println(klaus.getPartner().isPresent()); // -> true
System.out.println(hans.getPartner().isPresent()); // -> false
System.out.println(klaus.getPartner().get()); // -> Person@7530d0a
Primitive Datentypen
Die primitiven Datentypen nehmen in Java immer eine Sonderstellung ein. Wie bereits erläutert, kann man sie mithilfe der Wrapper-Typen in Objekte verwandeln. Dies ist aber – wegen des ständigen Ein- und Auspackens – nicht effizient. Deswegen gibt es eine Reihe von speziellen Klassen, um Optional einfach für die wichtigsten primitive Datentypen verwenden zu können.
Optional für primitive Datentypen
OptionalInt: Daten vom Typint,short,byte,charof(int i)getAsInt()OptonalLong: Daten vom Typlongof(long l)getAsLong()OptonalDouble: Daten vom Typfloatunddoubleof(double d )getAsDouble()
Für die anderen Datentypen wird kein Optional angeboten, diese lassen sich aber alle problemlos in den drei vorhandenen speichern.
Im Folgenden ein Beispiel für eine Klasse Person bei der das Alter optional angegeben werden kann.
class Student {
private String name;
private OptionalInt age;
public Student(String name, int age) {
this.name = name;
this.age = OptionalInt.of(age);
}
public Student(String name) {
this.name = name;
this.age = OptionalInt.empty();
}
public OptionalInt getAge() {
return age;
}
}
Die Verwendung von OptionalInt ermöglicht es uns, klar auszudrücken, dass das Alter optional ist und dass entsprechende Maßnahmen getroffen werden müssen, um mit dieser Möglichkeit umzugehen.
Person max = new Student("Max"); // Kein Alter angegeben
Person anna = new Student("Anna", 25); // Alter 25 angegeben
if (max.getAge().isPresent()) {
System.out.println("Age: " + max.getAge().getAsInt());
}
else {
System.out.println("Age not available.");
}