Scala bietet viele verschiedene Optionen für die Behandlung und Meldung von Fehlern, so dass es schwierig sein kann, zu entscheiden, welche für Ihre Situation am besten geeignet ist. In Scala und funktionalen Programmiersprachen ist es üblich, die Fehler, die auftreten können, explizit in der Funktionssignatur (d.h. im Rückgabetyp) anzugeben, im Gegensatz zur gängigen Praxis in anderen Programmiersprachen, wo entweder spezielle Werte verwendet werden (-1 für eine fehlgeschlagene Suche?) oder eine Ausnahme ausgelöst wird. Gehen wir die wichtigsten Optionen durch, die Sie als Scala-Entwickler haben, und sehen wir, wann Sie was verwenden sollten!
Option
Eine besondere Art von Fehler, der auftreten kann, ist das Fehlen eines Wertes. Wenn Sie zum Beispiel einen Wert in einer Datenbank oder einer Liste suchen, können Sie die Find-Methode verwenden. Wenn Sie dies in Java implementieren, besteht die übliche Lösung (zumindest bis Java 7) darin, null zurückzugeben, wenn ein Wert nicht gefunden werden kann, oder eine Version der NotFound-Ausnahme zu werfen. In Scala verwenden Sie in der Regel den Typ Option[T], der Some(value) zurückgibt, wenn der Wert gefunden wurde, und None, wenn der Wert nicht vorhanden ist.
Sie müssen also nicht im Javadoc oder Scaladoc nachsehen, sondern nur im Typ der Funktion, um zu wissen, wie ein fehlender Wert dargestellt wird. Außerdem müssen Sie Ihren Code nicht mit Null-Prüfungen oder try/catch-Blöcken überfrachten.
Ein weiterer Anwendungsfall ist das Parsen von Eingabedaten: Benutzereingaben, JSON, XML usw.. Anstatt eine Exception für ungültige Eingaben auszulösen, geben Sie einfach ein None zurück, um anzuzeigen, dass das Parsen fehlgeschlagen ist. Der Nachteil der Verwendung von Option für diese Situation ist, dass Sie die Art des Fehlers vor dem Benutzer Ihrer Funktion verbergen, was je nach Anwendungsfall ein Problem sein kann oder auch nicht. Wenn diese Informationen wichtig sind, lesen Sie die nächsten Abschnitte.
Ein Beispiel, das sicherstellt, dass ein Name nicht leer ist:
[scala]
def validateName(name: String): Option[String] = {
if (name.isEmpty) None
else Some(name)
}
[/scala]
Sie können die Methode validateName auf verschiedene Weise in Ihrem Code verwenden:
[scala]
// Einen Standardwert verwenden
validateName(inputName).getOrElse("Standardname")
// Eine andere Funktion auf das Ergebnis anwenden
validateName(inputName).map(.toUpperCase)
// Mit anderen Überprüfungen kombinieren und beim ersten Fehler kurzschließen
// Eine neue Option[Person] zurückgeben
for {
name <- validateName(inputName)
age <- validateAge(inputAge)
} yield Person(name, age)
[/scala]
Entweder
Option ist gut geeignet, um einen Fehler anzuzeigen, aber wenn Sie weitere Informationen über den Fehler benötigen, ist Option nicht leistungsfähig genug. In diesem Fall kann Either[L,R] verwendet werden. Es gibt 2 Implementierungen, Left und Right. Beide können einen benutzerdefinierten Typ verpacken, d.h. Typ L und Typ R. Gemäß der Konvention ist Right rechts, d.h. es enthält das erfolgreiche Ergebnis und Left enthält den Fehler. Wenn Sie die validateName-Methode so umschreiben, dass sie eine Fehlermeldung zurückgibt, ergibt sich Folgendes:
[scala]
def validateName(name: String): Either[String, String] = {
if (name.isEmpty) Left("Name darf nicht leer sein")
else Right(name)
}
[/scala]
Ähnlich wie Option Either kann auf verschiedene Weise verwendet werden. Es unterscheidet sich von Option dadurch, dass Sie immer die so genannte Projektion angeben müssen, mit der Sie über die Methode Left oder Right arbeiten wollen:
[scala]
// Wenden Sie eine Funktion auf das erfolgreiche Ergebnis an
validateName(inputName).right.map(.toUpperCase)
// Kombinieren Sie mit anderen Überprüfungen, um beim ersten Fehler einen Kurzschluss zu verursachen.
// Rückgabe einer neuen Either[Person]
für {
Name <- validateName(inputName).right
Alter <- validateAge(inputAge).right
} yield Person(Name, Alter)
// Behandeln Sie sowohl den linken als auch den rechten Fall
validateName(inputName).fold {
Fehler => s "Validierung fehlgeschlagen: $error",
Ergebnis => s "Validierung erfolgreich: $result"
}
// Und natürlich funktioniert auch der Mustervergleich
validateName(inputName) match {
case Links(Fehler) => s "Validierung fehlgeschlagen: $error",
case Rechts(Ergebnis) => s "Validierung erfolgreich: $result"
}
// In eine Option umwandeln:
validateName(inputName).right.toOption
[/scala]
Diese Projektion ist etwas ungeschickt und kann in for-Ausdrücken zu verschiedenen verworrenen Compiler-Fehlermeldungen führen. Siehe z.B. die ausgezeichnete und ausführliche Diskussion des Typs
- Option[T] verwenden Sie, wenn ein Wert fehlen oder eine Validierung fehlschlagen kann und Sie sich nicht um die genaue Ursache kümmern. Typischerweise in der Datenabfrage und Validierungslogik.
- Entweder[L,R], ähnlicher Anwendungsfall wie Option, aber wenn Sie einige Informationen über den Fehler angeben müssen.
- Try[T], verwenden Sie, wenn etwas Außergewöhnliches passieren kann, das Sie in der Funktion nicht behandeln können. Dies schließt im Allgemeinen Validierungslogik und Fehler beim Datenabruf aus, kann aber verwendet werden, um unerwartete Fehler zu melden.
- Ausnahmen sollten Sie nur als letzten Ausweg verwenden. Verwenden Sie beim Abfangen von Ausnahmen die von Scala bereitgestellten Hilfsmethoden und niemals catch { _ => }, sondern catch { NonFatal(_) => }
Ein letzter Ratschlag: Lesen Sie sich das Scaladoc für alle hier besprochenen Typen durch. Es gibt viele nützliche Kombinatoren, deren Verwendung sich lohnt.
Verfasst von

Remco Beckers
Unsere Ideen
Weitere Blogs
Contact



