Mit den Klassen und (Companion) Objekten
Option
, Some
und None
können wir in Scala optionale
Werte verwalten. Mit diesen Elementen können wir auch das aus Java bekannte null
vermeiden, welches kein Objekt ist, bzw. wir können null
-bezogene Werte objektorientiert
verarbeiten.
Option
ist die abstrakte Basisklasse für Some
und None
.
None
ist ein Singleton-Objekt
zur Aussage, dass der optionale Wert nicht gegeben ist. Some
hingegen enthält einen
existierenden optionalen Wert.
Stellen wir uns nun der Aufgabe Option
-Objekte zu erzeugen und einer Variablen
zuweisen können. Lassen wir die null
-Vermeidung
erst mal außen vor, bieten sich zwei grundsätzliche Möglichkeiten. Erstens durch Zuweisung
von None
und zweitens durch Zuweisung eines parametrisierten Some
Objektes.
Sehen wir uns diese Vorgehensweise nun mal an einem kleinen Beispiel an.
object OSN1 { def main(args: Array[String]): Unit = { val oNone = None val oSome: Some[Int] = Some(42) } }
None
ist in Scala ein Singlton-Objekt,
dass bei erster Verwendung erzeugt wird.
Dieses eine Singleton-Objekt verwenden wir für alle optionalen Werte, dessen
Wert nicht gegeben ist. Die Some
-Klasse verwenden wir für alle
optionalen Werte die gegeben sind. Das entsprechende Some
-Objekt
kapselt dabei den gegebenen Wert.
null
ist in der Java - Welt ein Wert, der für nicht gegeben steht.
null
ist kein Objekt und hat keinen Typ. Wir können jeder Referenzvariablen
den Wert null
zuweisen, was sogar der initiale Wert ist, sofern wir bei der
Definition einer Variablen keine explizites Objekt der Referenz zuweisen.
Variablen für primitive Datentypen in Java können wir null
nicht als Wert zuweisen.
Auch wenn wir das, wenn irgendwie möglich, vermeiden sollten:
Auch in Scala können wir null
als Rückgabewert von Methoden / Funktionen
verwenden oder einer Referenzvariablen zuordnen.
Das Hauptproblem in der Verwendung von null
liegt darin, dass null
kein Objekt ist. Das führt unter anderem zu Problemen in der Verarbeitung von
Collections, wenn ein Objekt erwartet und bearbeitet werden soll. Wir müssten dann,
für jede Bearbeitung einen Sonderfall für null
betrachten und
auch zumeist programmieren.
In Scala schafft der Datentyp Option
mit den zwei Ausprägungen
Some
und None
Abhilfe. Sollte irgendwo im Programm die
Möglichkeit auftreten, dass ein bestimmter Wert nicht gegeben ist, so verwenden wir
den Datentyp Option
. Ist der Wert gegeben "verpacken" wir diesen in
die Ausprägung Some
. Ist der Wert nicht gegeben, verwenden wir an dessen
Stelle None
.
Die Zuweisung zu Some
oder None
müssen wir nicht explizit
ausprogrammieren. Wir übergeben einfach den zuzuweisenden Wert an die
apply
- Methode
des Option
- Companion Objektes.
Ist der übergebene Wert null
erhalten wir ein None
als
Ergebnis. Andernfalls erhalten wir ein Some
Objekt mit dem übergebenen
Wert.
Das nachfolgende Beispiel zeigt die Erzeugung von Option
Objekten, deren
Wert möglicherweise nicht gegeben ist (also entsprechend null
in Java).
object Main { def main(args: Array[String]): Unit = { val avoidNull = new PossibleNull val myOption1 = Option[String](avoidNull.possibleNullMethod(4)) val myOption2 = Option[String](avoidNull.possibleNullMethod(3)) println(myOption1) println(myOption2) } } class PossibleNull { def possibleNullMethod(value: Int): String = { if (value % 2 == 0) "even" else null } }
Die Ausführung des Programms führt zu folgender Ausgabe auf der Systemausgabe.
Some(even) None
Da Option
Objekte None
oder Some
Ausprägungen sein
können, werden wir für Option
Objekte, bei Verwendung, häufig zwei unterschiedliche
Behandlungen programmieren wollen. Hier kommt uns die Methode getOrElse[B >: A](default: ? B): B
von Option entgegen, die bei Some
sich selbst und im entgegengesetzten Fall
das als default
definierte Objekt zurückgibt .
object GetOrElse { def main(args: Array[String]): Unit = { new GetOrElse() } } class GetOrElse() { def getNullable(nullValue: Boolean): String = { if (nullValue) return null else return "Not null" } val test1 = Option(getNullable(false)) val test2 = Option(getNullable(true)) println(test1.getOrElse("I'm None")) println(test2.getOrElse("I'm None")) }
Die Ausführung des Programms führt zu folgender Ausgabe auf der Systemausgabe:
Not null I'm None
isDefined
prüft, ob das zugehörige Objekt vom Typ Some
ist.
Im Falle von Some
liefert isDefined
true
andernfalls false
als Ergebnis.
object ODEF { def main(args: Array[String]): Unit = { val someValue: Option[String] = Some("Hello") val noneValue: Option[String] = None println(someValue.isDefined) println(noneValue.isDefined) } }
Die Ausführung des Programms führt zu folgender Ausgabe auf der Systemausgabe:
true false
Daniel Westheide
The Neophyte's Guide to Scala Part 5: The Option Type
http://danielwestheide.com/blog/2012/12/19/the-neophytes-guide-to-scala-part-5-the-option-type.html
Tony Morris
scala.Option Cheat Sheet
http://blog.tmorris.net/posts/scalaoption-cheat-sheet/
http://stackoverflow.com/
When to use Option
http://stackoverflow.com/questions/9698391/when-to-use-option
API Dokumentation:
Option (class)
Option (object)
Some
None