18_Optional
Videos
| Dateiname | Aktion |
|---|---|
| VIDEOVideo_Student_D | Abspielen |
Lernmaterialien
Optional
Allgemein
In Java ist Optional ein Container-Objekt, das
ausdrückt:
„Hier könnte ein Wert vorhanden sein – oder eben nicht.“
Es wird oft benutzt, um null sauberer und sicherer zu
behandeln.
Beispiel
Statt so:
String name = htl.minAlter();
if (name != null) {
System.out.println(name);
}kann man schreiben:
Optional<String> name = htl.minAlter();
name.ifPresent(System.out::println);Was steckt drin?
Ein Optional<T> enthält entweder:
einen Wert vom Typ
Tkeinen Wert
Wichtige Methoden
Optional<String> opt = Optional.of("Hallo");oder leer:
Optional<String> leer = Optional.empty();Häufige Methoden:
isPresent()→ prüft, ob ein Wert da istifPresent(...)→ führt etwas aus, wenn ein Wert da istorElse(...)→ liefert Standardwert, falls leerorElseGet(...)→ liefert alternativ berechneten WertorElseThrow(...)→ wirft Exception, falls leermap(...)→ verarbeitet den Wert weiterfilter(...)→ behält den Wert nur bei erfüllter Bedingung
Beispiele
Optional<String> opt = Optional.of("Max");
System.out.println(opt.isPresent()); // true
System.out.println(opt.orElse("Unbekannt")); // MaxLeeres Optional:
Optional<String> opt = Optional.empty();
System.out.println(opt.isPresent()); // false
System.out.println(opt.orElse("Unbekannt")); // UnbekanntMit map:
Optional<String> opt = Optional.of("Max");
Optional<Integer> laenge = opt.map(String::length);
System.out.println(laenge.orElse(0)); // 3Warum benutzt man
Optional?
Vorteile:
macht klar, dass ein Wert fehlen kann
reduziert
NullPointerExceptionzwingt zu bewusster Behandlung fehlender Werte
oft lesbarer als viele
null-Prüfungen
Wichtiger Hinweis
Optional wird vor allem als Rückgabetyp
verwendet, nicht typischerweise für:
Felder in Klassen
Methodenparameter
Also eher so:
public Optional<Kunde> getStudent(int pos)als so:
public void setKunde(Optional<Kunde> kunde)Kurz gesagt
Optional bedeutet in Java:
Ein Wert ist optional vorhanden.
Es ist eine Alternative zu null, um fehlende Werte
sicherer und ausdrücklicher zu behandeln.
Methoden
Optional.of(wert)
Für einen sicher vorhandenen Wert.
Ist wert == null, dann gibt es sofort eine
Exception.
Gerne:
Das hier wäre falsch:
String name = null;
Optional<String> opt = Optional.of(name); // FehlerOptional.ofNullable(wert)
Für einen Wert, der auch null sein darf.
Wenn wert null ist, entsteht einfach ein
leeres Optional.
String name = null;
Optional<String> opt = Optional.ofNullable(name);Optional.empty()
Erzeugt direkt ein leeres Optional.
Optional<String> opt = Optional.empty();Merksatz:
of(...)→ Wert muss da seinofNullable(...)→ Wert kann null seinempty()→ gar kein Wert
Beispiele
avgAlter()
public double avgAlter()
{
int summe;
if (sessel.size() > 0)
{
summe = 0;
for (Student s : sessel)
{
summe += s.getAlter();
}
return (double)summe / sessel.size();
}
else
{
return -999;
}
}Hier ist Optional sinnvoll, weil -999 nur
ein künstlicher Fehlerwert ist.
Das Problem an -999:
fachlich ist das kein sinnvolles Durchschnittsalter
der Aufrufer muss wissen, dass
-999„kein Ergebnis“ bedeutetdas ist fehleranfällig
OptionalDouble ist die bessere Lösung, da die Methode
einen double liefert kann.
public OptionalDouble avgAlter() {
if (sessel.size() > 0) {
int summe = 0;
for (Student s : sessel) {
summe += s.getAlter();
}
return OptionalDouble.of((double) summe / sessel.getAnzahl());
}
else {
return OptionalDouble.empty();
}
}Warum OptionalDouble?
Für primitive Typen gibt es spezielle Varianten:
OptionalIntOptionalLongOptionalDouble
Das ist meist passender als Optional<Double>.
Noch etwas kürzer
import java.util.OptionalDouble;
public OptionalDouble avgAlter() {
if (sessel.isEmpty()) {
return OptionalDouble.empty();
}
int summe = 0;
for (Student s : sessel) {
summe += s.getAlter();
}
return OptionalDouble.of((double) summe / sessel.getAnzahl());
}Verwendung
OptionalDouble avg = htl.avgAlter();
if (avg.isPresent()) {
System.out.println(avg.getAsDouble());
}
else {
System.out.println("Keine Studenten vorhanden");
}oder:
System.out.println(htl.avgAlter().orElse(0.0));Mit Streams
Das ist besonders elegant, weil average() direkt ein
OptionalDouble liefert.
public OptionalDouble avgAlter() {
return sessel.stream()
.mapToInt(Student::getAlter)
.average();
}Das ist besonders elegant, weil average() direkt ein
OptionalDouble liefert.
maxAlter()
public Student maxAlter()
{
int max;
Student maxStudent;
max = -999;
maxStudent = null;
for (Student s : sessel)
{
if (s.getAlter() > max)
{
max = s.getAlter();
maxStudent = s;
}
}
return maxStudent;
}maxAlter() liefert einen
Optional<Student>, weil die Methode kein
Ergebnis haben kann, wenn sessel leer ist.
Umbau mit Optional<Student>
public Optional<Student> maxAlter() {
Student maxStudent = null;
for (Student s : sessel) {
if (maxStudent == null || s.getAlter() > maxStudent.getAlter()) {
maxStudent = s;
}
}
return Optional.ofNullable(maxStudent);
}Die erste Version hat zwei typische Probleme:
-999ist wieder ein künstlicher StartwertmaxStudentkannnullbleiben, wennsesselleer ist
Mit Optional<Student> wird klarer:
Es gibt vielleicht einen ältesten Studenten, vielleicht aber auch keinen.
Verwendung
Optional<Student> opt = maxAlter();
opt.ifPresent(s -> System.out.println(s.getName()));oder:
Student s = maxAlter().orElse(null);oder:
System.out.println(
maxAlter()
.map(Student::getName)
.orElse("Kein Student vorhanden")
);Mit Streams
Falls Streams schon Thema sind:
Das ist sehr elegant, weil max(...) direkt ein
Optional<Student> zurückgibt.
Parameter
public void aufnehmen(Student wen) {
if (wen != null) {
if (sessel.contains(wen) == false)
sessel.add(wen);
else
System.out.println("Fehler: schon in dieser Schule!");
}
else {
System.out.println("Fehler: kein Student!");
}
}public void aufnehmen(Optional<Student> wen) {
if (wen.isEmpty()) {
System.out.println("Fehler: kein Student!");
return;
}
Student student = wen.get();
if (sessel.contains(student)) {
System.out.println("Fehler: schon in dieser Schule!");
return;
}
sessel.add(student);
}Warum ist Optional hier nicht
ideal?
So etwas wäre zwar möglich:
public void aufnehmen(Optional<Student> wen)aber das ist meistens keine gute Lösung, weil der Aufrufer dann so etwas machen müsste:
aufnehmen(Optional.of(student));
aufnehmen(Optional.empty());Das macht den Aufruf eher umständlicher als besser.
Optional ist als Parameter nicht
sinnvoll!
Optional wird in Java hauptsächlich als
Rückgabewert verwendet, nicht für
Methodenparameter.