Codierung funktionale Reine Android Apps in Kotlin: Lambdas, Null Safety und mehr
German (Deutsch) translation by Nikol Angelowa (you can also view the original English article)
In dieser dreiteiligen Serie haben wir uns eingehend mit Kotlin befasst, einer modernen Programmiersprache für Android-Apps, die in der Java Virtual Machine (JVM) ausgeführt wird.
Kotlin ist zwar bei weitem nicht die einzige alternative Programmiersprache, die für die Ausführung auf der JVM entwickelt wurde, hat Android-Entwicklern jedoch viel zu bieten. Wenn Sie in letzter Zeit mit dem Java-Teil der Android-Entwicklung frustriert waren, sollten Sie Kotlin ausprobieren.
In den ersten beiden Raten haben wir Folgendes behandelt:
Java vs. Kotlin: Sollten Sie Kotlin für die Android-Entwicklung verwenden? In diesem Einführungsartikel haben wir uns mit den Angeboten von Kotlin für Android-Entwickler sowie mit einigen potenziellen Nachteilen befasst, die Sie berücksichtigen müssen, bevor Sie entscheiden, ob Kotlin für Sie geeignet ist.
Codierung funktionaler Android-Apps in Kotlin: Erste Schritte. In diesem Beitrag haben wir uns mit der Konfiguration von Android Studio für die Unterstützung von Kotlin-Code befasst, eine vollständig in Kotlin geschriebene Android-App erstellt, uns mit der grundlegenden Syntax von Kotlin vertraut gemacht und sogar gesehen, wie ein Wechsel zu Kotlin bedeuten kann, dass Sie nie wieder eine
findViewByIdschreiben müssen .
Nachdem Sie nun in der Lage sind, die Java-Teile Ihrer Projekte durch Kotlin-Code mit demselben Endergebnis zu ersetzen, wollen wir uns einige Bereiche ansehen, in denen Kotlin den Vorteil gegenüber Java hat.
In dieser letzten Ausgabe werden wir einige der erweiterten Kotlin-Funktionen untersuchen, mit denen Sie Aufgaben ausführen können, die in Java entweder viel ausführlicher sind oder mit Java allein nicht erreichbar sind.
Am Ende dieses Artikels erfahren Sie, wie Sie mit Kotlin eine Menge Code aus Ihren Projekten entfernen, vorhandene Klassen mit neuen Funktionen erweitern und diese frustrierenden NullPointerExceptions der Vergangenheit angehören lassen.
Keine Nullen mehr
Wie oft sind Sie beim Testen Ihres Codes auf eine NullPointerException gestoßen? Heutzutage ist es ziemlich klar, dass es nicht die beste Wahl war, Entwicklern zu erlauben, einer Objektreferenz Null zuzuweisen! Der Versuch, eine Objektreferenz mit einem Nullwert zu verwenden, ist eine große Fehlerquelle in vielen verschiedenen Programmiersprachen, einschließlich Java. Tatsächlich war NullPointerException eine so große Quelle der Belästigung, dass Java 8 die Annotation @NonNull speziell hinzufügte, um diesen Fehler in seinem Typsystem zu beheben.
Das Problem liegt in der Tatsache, dass Sie mit Java jede Variable eines Referenztyps auf null setzen können. Wenn Sie jedoch zu irgendeinem Zeitpunkt versuchen, eine Referenz zu verwenden, die auf null zeigt, weiß die Variable aufgrund des Objekts nicht, wo sie suchen soll existiert eigentlich nicht. Zu diesem Zeitpunkt kann die JVM den normalen Ausführungspfad nicht fortsetzen. Ihre Anwendung stürzt ab und es tritt eine NullPointerException auf. Der Versuch, eine Methode für eine Nullreferenz aufzurufen oder auf ein Feld einer Nullreferenz zuzugreifen, löst beide eine NullPointerException aus.
Wenn Sie den Schmerz von NullPointerExceptions erlebt haben (und haben wir nicht alle irgendwann?), Gibt es eine gute Nachricht: Null-Sicherheit ist in die Kotlin-Sprache integriert. Mit dem Kotlin-Compiler können Sie einer Objektreferenz keinen Nullwert zuweisen, da Ihr Code während der Kompilierung speziell auf das Vorhandensein möglicher Nullobjekte überprüft wird. Wenn der Kotlin-Compiler feststellt, dass zur Laufzeit möglicherweise eine NullPointerException ausgelöst wird, schlägt Ihr Code zur Kompilierungszeit fehl.
Das null-sichere Design von Kotlin bedeutet, dass Sie (fast) nie auf Nullsituationen und NullPointerExceptions stoßen, die aus Kotlin-Code stammen. Die einzige Ausnahme besteht darin, dass Sie eine NullPointerException auslösen, indem Sie einen der speziellen Operatoren von Kotlin falsch verwenden, oder wenn Sie einen dieser Operatoren verwenden, um absichtlich eine NullPointerException auszulösen (wir werden die Operatoren später in diesem Artikel genauer untersuchen).
Null Sicherheit in der Praxis
In Kotlin werden alle Variablen standardmäßig als nicht nullwertfähig betrachtet. Wenn Sie also versuchen, einer Variablen einen Nullwert zuzuweisen, führt dies zu einem Kompilierungsfehler. Folgendes wird beispielsweise nicht kompiliert:
1 |
var example: String = null |
Wenn eine Variable einen Nullwert akzeptieren soll, müssen Sie diese Variable explizit als nullwert markieren. Dies ist das genaue Gegenteil von Java, bei dem jedes Objekt standardmäßig als nullwertfähig betrachtet wird. Dies ist ein wesentlicher Grund dafür, warum NullPointerExceptions in Java so häufig vorkommen.
Wenn Sie explizit deklarieren möchten, dass eine Variable einen Nullwert akzeptieren kann, müssen Sie einen ? auf den Variablentyp. Zum Beispiel wird Folgendes kompiliert:
1 |
var example: String? = null |
Wenn der Compiler diese Art von Deklaration sieht, erkennt er, dass dies eine nullfähige Variable ist, und behandelt sie etwas anders. Dies verhindert insbesondere, dass Sie eine Methode aufrufen oder auf eine Eigenschaft für diese nullfähige Referenz zugreifen, und hilft Ihnen erneut, diese lästigen NullPointerExceptions zu vermeiden. Folgendes wird beispielsweise nicht kompiliert:
1 |
var example : String? = null |
2 |
example.size |
Obwohl das Design von Kotlin bedeutet, dass es schwierig ist, NullPointerExceptions zu finden, die aus Kotlin-Code stammen. Wenn Ihr Projekt eine Mischung aus Kotlin und Java enthält, können die Java-Teile Ihres Projekts dennoch eine Quelle für NullPointerExceptions sein.
Wenn Sie mit einer Mischung aus Kotlin- und Java-Dateien arbeiten (oder möglicherweise speziell Nullwerte in Ihren Kotlin-Code einfügen müssen), enthält Kotlin eine Reihe spezieller Vorgänge, mit denen Sie alle auftretenden Nullwerte ordnungsgemäß verarbeiten können .
1. Der Safe Call Operator
Der Safe Call-Betreiber ?. bietet Ihnen eine Möglichkeit, mit Referenzen umzugehen, die möglicherweise einen Nullwert enthalten, und gleichzeitig sicherzustellen, dass ein Aufruf dieser Referenz nicht zu einer NullPointerException führt.
Wenn Sie einer Referenz einen Safe Call-Operator hinzufügen, wird diese Referenz auf einen Nullwert getestet. Wenn der Wert null ist, wird null zurückgegeben, andernfalls wird die Objektreferenz wie ursprünglich beabsichtigt verwendet. Während Sie mit einer if-Anweisung denselben Effekt erzielen können, können Sie mit dem Safe Call-Operator dieselbe Arbeit mit viel weniger Code ausführen.
Im Folgenden wird beispielsweise a.size nur zurückgegeben, wenn a nicht null ist. Andernfalls wird null zurückgegeben:
1 |
a?.size |
Sie können Safe Call-Operatoren auch miteinander verketten:
1 |
val number = person?.address?.street?.number |
Wenn einer der Ausdrücke in dieser Reihe null ist, ist das Ergebnis null, andernfalls ist das Ergebnis der angeforderte Wert.
2. Der Elvis-Operator
Manchmal haben Sie einen Ausdruck, der möglicherweise einen Nullwert enthalten könnte, aber Sie möchten keine NullPointerException auslösen, selbst wenn sich herausstellt, dass dieser Wert null ist.
In diesen Situationen können Sie den Elvis-Operator ?: Von Kotlin verwenden, um einen alternativen Wert bereitzustellen, der verwendet wird, wenn sich herausstellt, dass der Wert null ist. Dies ist auch eine gute Möglichkeit, die Weitergabe von Nullwerten in Ihrem Code zu verhindern.
Schauen wir uns ein Beispiel für den Elvis-Operator in Aktion an:
1 |
fun setName(name: String?) { |
2 |
username = name ?: "N/A" |
Wenn hier der Wert links vom Elvis-Operator nicht null ist, wird der Wert der linken Seite zurückgegeben (name). Wenn der Wert links vom Elvis-Operator jedoch null ist, wird der Ausdruck rechts zurückgegeben, der in diesem Fall N/A ist.
3. Die !! Operator
Wenn Sie Ihren Kotlin-Code jemals zwingen möchten, eine NullPointerException im Java-Stil auszulösen, können Sie die !! Operator. Beispielsweise:
1 |
val number = firstName!!.length |
Hier verwenden wir das !! Operator, um zu behaupten, dass die Variable firstName nicht null ist. Solange firstName eine gültige Referenz enthält, wird die Variablennummer auf die length der Zeichenfolge festgelegt. Wenn firstName keine gültige Referenz enthält, löst Kotlin eine NullPointerException aus.
Lambda-Ausdrücke
Ein Lambda-Ausdruck repräsentiert eine anonyme Funktion. Lambdas sind eine großartige Möglichkeit, die Menge an Code zu reduzieren, die zum Ausführen einiger Aufgaben erforderlich ist, die in der Android-Entwicklung ständig ausgeführt werden, z. B. zum Schreiben von Listenern und Rückrufen.
Java 8 hat native Lambda-Ausdrücke eingeführt, die jetzt in Android Nougat unterstützt werden. Obwohl diese Funktion nicht nur bei Kotlin verfügbar ist, lohnt es sich dennoch, sie sich anzusehen. Wenn Sie an einem Projekt arbeiten, das sowohl Kotlin- als auch Java-Code enthält, können Sie jetzt Lambda-Ausdrücke für Ihr gesamtes Projekt verwenden!
Ein Lambda-Ausdruck besteht aus einer Reihe von Parametern, einem Lambda-Operator (->) und einem Funktionskörper, die im folgenden Format angeordnet sind:
1 |
{ x: Int, y: Int -> x + y }
|
Bei der Erstellung von Lambda-Ausdrücken in Kotlin müssen Sie die folgenden Regeln beachten:
Der Lambda-Ausdruck sollte von geschweiften Klammern umgeben sein.
Wenn der Ausdruck Parameter enthält, müssen Sie diese vor dem Pfeilsymbol
->deklarieren.Wenn Sie mit mehreren Parametern arbeiten, sollten Sie diese durch Kommas trennen.
Der Körper geht nach dem
->Zeichen.
Der Hauptvorteil von Lambda-Ausdrücken besteht darin, dass Sie anonyme Funktionen definieren und diese Funktionen dann sofort als Ausdruck weitergeben können. Auf diese Weise können Sie viele gängige Entwicklungsaufgaben prägnanter ausführen als in Java 7 und früheren Versionen, da Sie die Spezifikation der Funktion nicht mehr in eine abstrakte Klasse oder Schnittstelle schreiben müssen. Tatsächlich ist das Fehlen von Lambdas in Java 7 und früheren Versionen ein wesentlicher Grund dafür, warum das Schreiben von Listenern und Rückrufen in Android traditionell so umständlich war.
Schauen wir uns ein allgemeines Beispiel an: Hinzufügen eines Klick-Listeners zu einer Schaltfläche. In Java 7 und früheren Versionen ist hierfür normalerweise der folgende Code erforderlich:
1 |
button.setOnClickListener(new View.OnClickListener() { |
2 |
|
3 |
@Override
|
4 |
public void onClick(View v) { |
5 |
Toast.makeText(this, "Button clicked", Toast.LENGTH_LONG).show(); |
6 |
}
|
7 |
});
|
Mit den Kotlin-Lambda-Funktionen können Sie jedoch einen Klick-Listener mit einer einzigen Codezeile festlegen:
1 |
button.setOnClickListener({ view -> toast("Button clicked") }) |
Dies ist bereits viel prägnanter und leichter zu lesen, aber wir können noch weiter gehen - wenn eine Funktion eine andere Funktion als letzten Parameter verwendet, können Sie sie außerhalb der Klammerliste übergeben:
1 |
button.setOnClickListener() { toast("Button clicked") } |
Und wenn die Funktion nur einen Parameter hat, der eine Funktion ist, können Sie die Klammern vollständig entfernen:
1 |
button.setOnClickListener { toast("Button clicked") } |
Erweiterungsfunktionen
Ähnlich wie bei C# können Sie mit Kotlin vorhandenen Klassen neue Funktionen hinzufügen, die Sie sonst nicht ändern könnten. Wenn Sie also der Meinung sind, dass einer Klasse eine nützliche Methode fehlt, können Sie sie über eine Erweiterungsfunktion selbst hinzufügen.
Sie erstellen eine Erweiterungsfunktion, indem Sie dem Namen der Klasse, die Sie erweitern möchten, den Namen der Funktion voranstellen, die Sie erstellen.
Beispielsweise:
1 |
fun AppCompatActivity.toast(msg: String) { |
2 |
|
3 |
Toast.makeText(this, msg, Toast.LENGTH_LONG).show() |
4 |
}
|
Beachten Sie, dass das Schlüsselwort this in der Erweiterungsfunktion der AppCompatActivity-Instanz entspricht, für die .toast aufgerufen wird.
In diesem Beispiel müssen Sie nur die Klassen AppComptActivity und Toast in Ihre .kt-Datei importieren und können dann die aufrufen . Notation auf Instanzen der erweiterten Klasse.
Wenn es um die Android-Entwicklung geht, sind Erweiterungsfunktionen möglicherweise besonders nützlich, um ViewGroups die Möglichkeit zu geben, sich selbst aufzublasen, zum Beispiel:
1 |
fun ViewGroup.inflate( |
2 |
@LayoutRes layoutRes: Int, |
3 |
attachToRoot: Boolean = false): View { |
4 |
|
5 |
return LayoutInflater |
6 |
.from(context) |
7 |
.inflate(layoutRes, this, attachToRoot) |
8 |
}
|
Also anstatt folgendes schreiben zu müssen:
1 |
val view = LayoutInflater |
2 |
|
3 |
.from(parent) |
4 |
.inflate(R.layout.activity_main, parent, false) |
Sie können einfach Ihre Erweiterungsfunktion verwenden:
1 |
val view = parent.inflate(R.layout.activity_main) |
Singleton-Objekte
In Java war das Erstellen von Singletons normalerweise ziemlich ausführlich, sodass Sie eine Klasse mit einem privaten Konstruktor erstellen und diese Instanz dann als privates Attribut erstellen müssen.
Das Endergebnis ist normalerweise ungefähr so:
1 |
public class Singleton { |
2 |
|
3 |
private static Singleton singleton = new Singleton( ); |
4 |
|
5 |
private Singleton() { } |
6 |
|
7 |
public static Singleton getInstance( ) { |
8 |
return singleton; |
9 |
}
|
Anstatt eine Klasse zu deklarieren, können Sie in Kotlin ein einzelnes Objekt, das semantisch mit einem Singleton identisch ist, in einer Codezeile definieren:
1 |
object KotlinSingleton {} |
Sie können diesen Singleton dann sofort verwenden, zum Beispiel:
1 |
object KotlinSingleton { |
2 |
fun myFunction() { [...] } |
3 |
}
|
4 |
KotlinSingleton.myFunction() |
Abschluss
In diesem Artikel haben wir uns eingehend mit dem null-sicheren Design von Kotlin befasst und herausgefunden, wie Sie sicherstellen können, dass Ihre Android-Projekte auch dann null-sicher bleiben, wenn sie eine Mischung aus Java- und Kotlin-Code enthalten, indem Sie eine Reihe spezieller Operatoren verwenden. Wir haben uns auch angesehen, wie Sie Lambda-Ausdrücke verwenden können, um einige gängige Entwicklungsaufgaben in Android zu vereinfachen, und wie Sie vorhandenen Klassen neue Funktionen hinzufügen können.
In Kombination mit dem, was wir in Teil 1: Java vs. Kotlin und Teil 2: Erste Schritte gelernt haben, haben Sie jetzt alles, was Sie zum Erstellen effektiver Android-Apps mit der Programmiersprache Kotlin benötigen.
Viel Spaß mit der Kotlin-Sprache und schauen Sie sich einige unserer anderen Kurse und Tutorials zur Android-Programmierung an.











