Scala Grundkurs

Option

LinkedIn Learning kostenlos und unverbindlich testen!

Jetzt testen Alle Abonnements anzeigen
Fehlende Werte führen bei der Programmierung häufig zu einer sogenannten NullPointerException. Bei einem Option handelt es sich in Scala um einen Datentyp zur Kapselung von Werten, die bereits existieren oder künftig existieren werden.

Transkript

Nicht zuletzt erst Java 8 hat die Möglichkeiten eines sogenannten Optionals in die Programmiersprache gebracht. Scala nutzt die Semantik eines Optionals schon seit Ewigkeiten, denn mit einem Optional lässt sich die Problemstellung fehlender Werte, die oft zu NullPointerExceptions in der Realität führen, sehr gut abbilden. Wie man genau dieses Option innerhalb von Scala nutzen kann, werde ich Ihnen nun zeigen. Ich befinde mich nun in meiner Applikation. Dort gibt es einen Kunden, einen Warenkorb und einen Onlineshop, bei dem ich diesen Warenkorb nutzen kann. Ich will nun gern die Möglichkeit schaffen, dass ein Kunde eine Bezahlmethode hat. Dafür habe ich zunächst einmal eine Abstraktion "PaymentMethod" definiert. Diese hat eine Funktion mit der Bezeichnung "charge". Sie nimmt einen Preis entgegen und überprüft, ob eine Möglichkeit zur Bezahlung besteht und gibt dann "true" oder "false" zurück. Des Weiteren habe ich zwei konkrete Implementierungen. Eine Kreditkarte, die aus einer Nummer und einer Sicherheitskennung besteht, dieses definiert eine Methode beziehungsweise Funktion "charge" mit dem Rückgabewert "false". Des Weiteren gibt es hier ein Bankkonto, das sich anhand einer IBAN definiert und dies lässt sich auf jeden Fall zur Bezahlung nutzen und gibt den Wert "true" zurück. Als nächstes muss ich nun also auf meiner Klasse "customer" diese Bezahlmethoden definieren. Dies tue ich, indem ich eine private Variable mit der Bezeichnung "creditCard" erzeuge. Und diese ist ein Option, allerdings aktuell noch nicht definiert, daher ein "Option.empty". Zusätzlich lege ich hier den Typen fest, konkret hier "CreditCard". Des Weiteren gibt es noch den "checkingAccount". Auch hierbei handelt es sich noch um einen undefinierten Wert, allerdings korrekt typisiert mit "CheckingAccount". Passend dazu benötige ich noch zwei Settermethoden, zum einen "setCreditCard" und zum anderen "setCheckingAccount". Was hier direkt auffällt, ist, dass ich keine direkte Zuweisung einer Credit Card und eines Checking Accounts zu einem Option vornehmen kann. Dafür verwendet man die Notation "Some". Damit wird also ein Optional-Wert aus diesen Werten generiert. Mit einem solchen Option habe ich dann diverse Möglichkeiten. Beispielsweise könnte ich prüfen, ob es bereits definiert ist oder ob es noch leer ist, wie im Initialfall. Dies definiert sich also durch "isDefined". Des Weiteren habe ich viele Möglichkeiten, Zwischenmethoden zu schalten, basierend auf dem Inhalt dieses Options. Konkret implementiere ich nun also eine Funktion mit der Bezeichnung "charge". Damit soll es also möglich sein, dem Kunden Geld abzubuchen. Dafür benötige ich zunächst einmal einen Preis und einen Ausgabewert, ob die Abbuchung erfolgreich war, in dem Fall also ein Boolean. Generell möchte ich, dass innerhalb der Anwendung zuerst mit Kreditkarte bezahlt wird. Das bedeutet, ich beginne mit der Kreditkarte. Sollte keine Kreditkarte vorhanden sein, kann man alternativ den Checking Account verwenden. Das ist eine der besonderen Möglichkeiten, die ich nun mit einem Option habe. Ich tausche also die Implementierung einer Credit Card einfach gegen die Implementierung eines Checking Accounts. Das ist selbstverständlich nur dann möglich, wenn beide auf demselben Typ, wie in diesem Fall, Payment Method basieren. Als nächstes möchte ich nun, unabhängig davon, welcher von beiden ausgewählt wird, dass mein Preis abgebucht wird. Ich benutze also die Funktion "charge" und übergebe den Preis. Das heißt, die Funktion "charge", so wie sie auf der Payment Method definiert ist, wird nun entweder auf der Credit Card oder dem Checking Account ausgeführt, je nachdem, welche von beiden verfügbar ist. Auch nach diesem Mapping habe ich immer noch ein Option. In dem Fall ist es nun also ein Option von Boolean. Ich kann nun einen Ausgabewert definieren, der, falls immer noch kein Wert existiert, verwendet wird. Das heißt, immer dann, wenn beispielsweise keine Kreditkarte existierte oder kein Checking Account, möchte ich trotz allem auf jeden Fall den Wert "false" zurückgeben, denn die Abbuchung war in dem Fall nicht erfolgreich. Sollte irgendwo in die ser Kette bereits vorher ein "false" entstanden sein, so wird auch selbstverständlich dieses als "false" ausgegeben. Sollte tatsächlich eine positive Abbuchung stattgefunden haben, so wird dies ganz normal funktionieren. IntelliJ iDEA schlägt mir an dieser Stelle vor, die Syntax hier zu verkürzen. Allerdings trägt die Semantik von "exists" nicht die Intention, die ich tatsächlich mit dem Code ausdrücken wollte. Deswegen mache ich diese Änderung rückgängig. Als nächstes möchte ich nun, dass man innerhalb des Check-out-Prozesses eben diesen "charge"-Prozess durchführen kann. Dafür begebe ich mich also in den Check-out-Handler und definiere hier eine neue Methode mit der Bezeichnung "confirm". Damit soll also nun die Bestellung bestätigt werden, nachdem die Preise berechnet worden sind. In dem Moment, wo die Bestellung bestätigt wird, soll dem Kunden also das Geld abgebucht werden. Ich brauche also nun den Basket, also den Warenkorb, und dort theoretisch den Kunden. Dieser ist auf dem Basket aktuell nicht sichtbar. Daher begebe ich mich in den Basket und zeige den Customer nach außen. Als nächstes buche ich also dem Customer ganz konkret den gesamten Preis vom Konto ab. Wenn dies gelingt, gebe ich auf die Konsole die Nachricht aus, dass der Kunde bezahlt hat. Sollte dies nicht der Fall sein, gebe ich den Wert aus, "Could not charge customer". Innerhalb der Application definiere ich nun für meinen Kunden einen Checking Account als auch eine Kreditkarte, beispielsweise durch die Kreditkartennummer ABCDEFG und dem Sicherheitscode 123. Genauso gebe ich ihm einen Checking Account mit einer IBAN von DE und einem beliebigen Wert. Als nächstes möchte ich nun also den Kauf abschließen, mit dem Aufruf von "checkout.confirm". Laut meiner Implementierung ist es aktuell nicht möglich, ausschließlich mit einer Kreditkarte zu bezahlen. Sollte hier nun beispielsweise ein Fehler auftreten beim Rekompilieren, sollte man auf jeden Fall das Projekt noch einmal neu bauen, denn es handelt sich hier um einen dynamischen Typ. Wie erwartet konnte der Kunde nun nicht zahlen. Auch wenn ein Checking Account zur Verfügung steht, kann der Kunde nicht zahlen, da die Kreditkarte präferiert wird und nach der Anfrage der Kreditkarte bereits der Wert "false" zurückkommt. Wenn ich allerdings nun die Kreditkarte deaktiviere und der Kunde lediglich einen Checking Account hat und dies seine einzige Bezahlmethode ist, so kann der Kunde erfolgreich zahlen, da der Checking Account aktuell mit Hilfe der "charge"-Funktion belastbar ist. So lassen sich die Möglichkeiten eines Option sowohl innerhalb einer Klasse als auch beispielsweise bei Parametern einer Funktion oder Methode nutzen. Bei einem Option handelt sich also nun um einen Datentyp zur Kapselung von Werten, die bereits existieren oder in der Zukunft existieren werden. Das Besondere daran ist, dass in Scala auch hier eine Typisierung stattfindet. Das bedeutet also, dass beispielsweise auch ein leeres Option schon den korrekten Typ, wie beispielsweise "creditCard", hat. Bedingt dadurch, dass ich ein Option nur dann nutzen kann, wenn ich dessen Methoden und Funktionen nutze, bin ich durch die Semantik gezwungen, mit Problemen, wie beispielsweise NullPointerExceptions, standardmäßig umzugehen. Schließlich muss ich vor der Nutzung des Inhaltes des Options immer erst prüfen, ob es tatsächlich zur Verfügung steht und gegebenenfalls einen Fallback-Wert bereitstellen. Die Hilfsmethoden, um lediglich zu prüfen, ob das Option definiert ist, sind in dem Fall "isDefined" oder "empty". Ein Option würde ich standardmäßig daher immer mit einem "Option.empty" initialisieren und erst später beispielsweise durch einen konkreten Wert mit "Some" initialisieren. Üblicherweise benutzt man also ein Option immer dann, wenn man nicht deterministische Parameter und Werte hat, also solche, die nicht initial bekannt sind und sofort definiert werden können. Das bedeutet also auch, dass jeder Wert, der erst später zur Verfügung steht, immer in ein Option gekapselt werden sollte. Dank der Semantik eines Options können trotzdem verschiedene Dinge, wie beispielsweise das Mapping von Werten zu anderen Werten, vorgenommen werden. Dafür existieren diverse Hilfsmethoden, die es erlauben, unabhängig von der Existenz eines Options bereits damit arbeiten zu können.

Scala Grundkurs

Entdecken Sie die Möglichkeiten und Eigenschaften der modernen Programmiersprache Scala.

4 Std. 44 min (39 Videos)
Derzeit sind keine Feedbacks vorhanden...
Software:
Exklusiv für Abo-Kunden
Erscheinungsdatum:12.04.2017

Dieser Online-Kurs ist als Download und als Streaming-Video verfügbar. Die gute Nachricht: Sie müssen sich nicht entscheiden - sobald Sie das Training erwerben, erhalten Sie Zugang zu beiden Optionen!

Der Download ermöglicht Ihnen die Offline-Nutzung des Trainings und bietet die Vorteile einer benutzerfreundlichen Abspielumgebung. Wenn Sie an verschiedenen Computern arbeiten, oder nicht den ganzen Kurs auf einmal herunterladen möchten, loggen Sie sich auf dieser Seite ein, um alle Videos des Trainings als Streaming-Video anzusehen.

Wir hoffen, dass Sie viel Freude und Erfolg mit diesem Video-Training haben werden. Falls Sie irgendwelche Fragen haben, zögern Sie nicht uns zu kontaktieren!