Kotlin-Bootcamp für Programmierer 3: Funktionen

Dieses Codelab ist Teil des Kotlin-Bootcamps für Programmierer. Sie können diesen Kurs am besten nutzen, wenn Sie die Codelabs der Reihe nach durcharbeiten. Je nach Ihrem Wissen können Sie einige Abschnitte möglicherweise überfliegen. Dieser Kurs richtet sich an Programmierer, die eine objektorientierte Sprache kennen und Kotlin lernen möchten.

Einführung

In diesem Codelab erstellen Sie ein Kotlin-Programm und lernen Funktionen in Kotlin kennen, einschließlich Standardwerte für Parameter, Filter, Lambdas und kompakte Funktionen.

In diesem Kurs wird keine einzelne Beispiel-App entwickelt. Stattdessen sollen die Lektionen Ihr Wissen erweitern, sind aber weitgehend unabhängig voneinander, sodass Sie Abschnitte, mit denen Sie vertraut sind, überspringen können. Um die Beispiele zu veranschaulichen, wird in vielen ein Aquarium verwendet. Wenn Sie die ganze Geschichte des Aquariums sehen möchten, können Sie sich den Udacity-Kurs Kotlin Bootcamp for Programmers ansehen.

Was Sie bereits wissen sollten

  • Die Grundlagen einer modernen, objektorientierten, statisch typisierten Programmiersprache
  • Programmieren mit Klassen, Methoden und Ausnahmebehandlung in mindestens einer Sprache
  • So arbeiten Sie mit der REPL (Read-Eval-Print Loop) von Kotlin in IntelliJ IDEA
  • Die Grundlagen von Kotlin, einschließlich Typen, Operatoren und Schleifen

Dieses Codelab richtet sich an Programmierer, die eine objektorientierte Sprache kennen und mehr über Kotlin erfahren möchten.

Lerninhalte

  • Programm mit einer main()-Funktion und Argumenten in IntelliJ IDEA erstellen
  • Standardwerte und kompakte Funktionen verwenden
  • Filter für Listen anwenden
  • Grundlegende Lambdas und Funktionen höherer Ordnung erstellen

Aufgaben

  • Mit dem REPL können Sie Code ausprobieren.
  • Mit IntelliJ IDEA grundlegende Kotlin-Programme erstellen

In dieser Aufgabe erstellen Sie ein Kotlin-Programm und lernen die Funktion main() kennen. Außerdem erfahren Sie, wie Sie Argumente über die Befehlszeile an ein Programm übergeben.

Sie erinnern sich vielleicht an die Funktion printHello(), die Sie in einem früheren Codelab in den REPL eingegeben haben:

fun printHello() {
    println ("Hello World")
}

printHello()
⇒ Hello World

Sie definieren Funktionen mit dem Schlüsselwort fun, gefolgt vom Namen der Funktion. Wie bei anderen Programmiersprachen werden die Klammern () für Funktionsargumente verwendet, sofern vorhanden. Geschweifte Klammern {} umschließen den Code für die Funktion. Für diese Funktion gibt es keinen Rückgabetyp, da sie nichts zurückgibt.

Schritt 1: Kotlin-Datei erstellen

  1. Öffnen Sie IntelliJ IDEA.
  2. Im Bereich Project (Projekt) links in IntelliJ IDEA wird eine Liste der Projektdateien und -ordner angezeigt. Suchen Sie unter Hello Kotlin nach dem Ordner src und klicken Sie mit der rechten Maustaste darauf. (Sie sollten das Projekt Hello Kotlin aus dem vorherigen Codelab bereits haben.)
  3. Wählen Sie New > Kotlin File / Class (Neu > Kotlin-Datei / -Klasse) aus.
  4. Lassen Sie Art als Datei und geben Sie der Datei den Namen Hallo.
  5. Klicken Sie auf OK.

Im Ordner src befindet sich jetzt eine Datei mit dem Namen Hello.kt.

Schritt 2: Code hinzufügen und Programm ausführen

  1. Wie bei anderen Sprachen gibt die Kotlin-Funktion main() den Einstiegspunkt für die Ausführung an. Alle Befehlszeilenargumente werden als String-Array übergeben.

    Geben Sie den folgenden Code in die Datei Hello.kt ein oder fügen Sie ihn dort ein:
fun main(args: Array<String>) {
    println("Hello, world!")
}

Wie bei Ihrer früheren printHello()-Funktion gibt es auch hier keine return-Anweisung. Jede Funktion in Kotlin gibt etwas zurück, auch wenn nichts explizit angegeben ist. Eine Funktion wie die main()-Funktion gibt also den Typ kotlin.Unit zurück, was in Kotlin bedeutet, dass kein Wert vorhanden ist.

  1. Klicken Sie zum Ausführen des Programms auf das grüne Dreieck links neben der Funktion main(). Wählen Sie im Menü Run 'HelloKt' (HelloKt ausführen) aus.
  2. IntelliJ IDEA kompiliert das Programm und führt es aus. Die Ergebnisse werden unten in einem Logbereich angezeigt, wie unten dargestellt.

Schritt 3: Argumente an main() übergeben

Da Sie Ihr Programm in IntelliJ IDEA und nicht über die Befehlszeile ausführen, müssen Sie alle Argumente für das Programm etwas anders angeben.

  1. Wählen Sie Run > Edit Configurations aus. Das Fenster Run/Debug Configurations (Ausführungs-/Fehlerbehebungskonfigurationen) wird geöffnet.
  2. Geben Sie in das Feld Programmargumente Kotlin! ein.
  3. Klicken Sie auf OK.

Schritt 4: Code für die Verwendung einer Stringvorlage ändern

Mit einer Stringvorlage wird eine Variable oder ein Ausdruck in einen String eingefügt. $ gibt an, dass ein Teil des Strings eine Variable oder ein Ausdruck ist. Geschweifte Klammern {} umschließen den Ausdruck, falls vorhanden.

  1. Ändern Sie in Hello.kt die Begrüßungsnachricht so, dass anstelle von "world" das erste Argument verwendet wird, das an das Programm übergeben wird, nämlich args[0].
fun main(args: Array<String>) {
    println("Hello, ${args[0]}")
}
  1. Führen Sie das Programm aus. Die Ausgabe enthält das von Ihnen angegebene Argument.
⇒ Hello, Kotlin!

In dieser Aufgabe erfahren Sie, warum fast alles in Kotlin einen Wert hat und warum das nützlich ist.

In einigen anderen Sprachen gibt es Anweisungen, also Codezeilen ohne Wert. In Kotlin ist fast alles ein Ausdruck und hat einen Wert, auch wenn dieser Wert kotlin.Unit ist.

  1. Schreiben Sie in Hello.kt Code in main(), um einer Variablen namens isUnit einen println() zuzuweisen und ihn auszugeben. (println() gibt keinen Wert zurück, daher wird kotlin.Unit zurückgegeben.)
// Will assign kotlin.Unit
val isUnit = println("This is an expression")
println(isUnit)
  1. Führen Sie das Programm aus. Mit dem ersten println() wird der String "This is an expression" ausgegeben. Die zweite println() gibt den Wert der ersten println()-Anweisung aus, also kotlin.Unit.
⇒ This is an expression
kotlin.Unit
  1. Deklarieren Sie eine val mit dem Namen temperature und initialisieren Sie sie mit dem Wert 10.
  2. Deklarieren Sie ein weiteres val namens isHot und weisen Sie isHot den Rückgabewert einer if-/else-Anweisung zu, wie im folgenden Code gezeigt. Da es sich um einen Ausdruck handelt, können Sie den Wert des if-Ausdrucks sofort verwenden.
val temperature = 10
val isHot = if (temperature > 50) true else false
println(isHot)
⇒ false
  1. Verwenden Sie den Wert eines Ausdrucks in einer Stringvorlage. Füge etwas Code hinzu, um die Temperatur zu prüfen und festzustellen, ob ein Fisch sicher oder zu warm ist, und führe dann das Programm aus.
val temperature = 10
val message = "The water temperature is ${ if (temperature > 50) "too warm" else "OK" }."
println(message)
⇒ The water temperature is OK.

In dieser Aufgabe erfahren Sie mehr über Funktionen in Kotlin und über den sehr nützlichen bedingten Ausdruck when.

Schritt 1: Funktionen erstellen

In diesem Schritt wenden Sie einige der gelernten Konzepte an und erstellen Funktionen mit verschiedenen Typen. Sie können den Inhalt von Hello.kt durch diesen neuen Code ersetzen.

  1. Schreibe eine Funktion namens feedTheFish(), die randomDay() aufruft, um einen zufälligen Wochentag zu erhalten. Verwende eine Stringvorlage, um ein food für den Fisch auszugeben, das er an diesem Tag fressen kann. Im Moment bekommen die Fische jeden Tag dasselbe Futter.
fun feedTheFish() {
    val day = randomDay()
    val food = "pellets"
    println ("Today is $day and the fish eat $food")
}

fun main(args: Array<String>) {
    feedTheFish()
}
  1. Schreiben Sie die Funktion randomDay(), um einen zufälligen Tag aus einem Array auszuwählen und zurückzugeben.

Die Funktion nextInt() verwendet einen ganzzahligen Grenzwert, der die Zahl von Random() auf 0 bis 6 begrenzt, um dem week-Array zu entsprechen.

fun randomDay() : String {
    val week = arrayOf ("Monday", "Tuesday", "Wednesday", "Thursday",
            "Friday", "Saturday", "Sunday")
    return week[Random().nextInt(week.size)]
}
  1. Die Funktionen Random() und nextInt() sind in java.util.* definiert. Fügen Sie oben in der Datei den erforderlichen Import hinzu:
import java.util.*    // required import
  1. Führen Sie das Programm aus und prüfen Sie die Ausgabe.
⇒ Today is Tuesday and the fish eat pellets

Schritt 2: „when“-Ausdruck verwenden

Ändern Sie den Code so, dass für verschiedene Tage unterschiedliche Lebensmittel ausgewählt werden, indem Sie einen when-Ausdruck verwenden. Die when-Anweisung ähnelt switch in anderen Programmiersprachen, aber when wird am Ende jedes Zweigs automatisch beendet. Außerdem wird sichergestellt, dass Ihr Code alle Zweige abdeckt, wenn Sie ein Enum prüfen.

  1. Fügen Sie in Hello.kt eine Funktion namens fishFood() hinzu, die einen Tag als String entgegennimmt und das Futter des Fisches für den Tag als String zurückgibt. Verwende when(), damit die Fische jeden Tag ein bestimmtes Futter erhalten. Führen Sie das Programm mehrmals aus, um unterschiedliche Ausgaben zu sehen.
fun fishFood (day : String) : String {
    var food = ""
    when (day) {
        "Monday" -> food = "flakes"
        "Tuesday" -> food = "pellets"
        "Wednesday" -> food = "redworms"
        "Thursday" -> food = "granules"
        "Friday" -> food = "mosquitoes"
        "Saturday" -> food = "lettuce"
        "Sunday" -> food = "plankton"
    }
    return food
}

fun feedTheFish() {
    val day = randomDay()
    val food = fishFood(day)

    println ("Today is $day and the fish eat $food")
}
⇒ Today is Thursday and the fish eat granules
  1. Fügen Sie dem when-Ausdruck mit else einen Standardzweig hinzu. Entfernen Sie zum Testen die Verzweigungen Tuesday und Saturday, damit der Standardwert manchmal in Ihrem Programm verwendet wird.

    Durch eine Standardverzweigung wird sichergestellt, dass food einen Wert erhält, bevor er zurückgegeben wird. Er muss also nicht mehr initialisiert werden. Da im Code jetzt nur einmal ein String für food zugewiesen wird, können Sie food mit val anstelle von var deklarieren.
fun fishFood (day : String) : String {
    val food : String
    when (day) {
        "Monday" -> food = "flakes"
        "Wednesday" -> food = "redworms"
        "Thursday" -> food = "granules"
        "Friday" -> food = "mosquitoes"
        "Sunday" -> food = "plankton"
        else -> food = "nothing"
    }
    return food
}
  1. Da jeder Ausdruck einen Wert hat, können Sie diesen Code etwas kompakter gestalten. Gibt den Wert des Ausdrucks when direkt zurück und entfernt die Variable food. Der Wert des Ausdrucks when ist der Wert des letzten Ausdrucks des Zweigs, der die Bedingung erfüllt hat.
fun fishFood (day : String) : String {
    return when (day) {
        "Monday" -> "flakes"
        "Wednesday" -> "redworms"
        "Thursday" -> "granules"
        "Friday" -> "mosquitoes"
        "Sunday" -> "plankton"
        else -> "nothing"
    }
}

Die endgültige Version Ihres Programms sieht in etwa so aus:

import java.util.*    // required import

fun randomDay() : String {
    val week = arrayOf ("Monday", "Tuesday", "Wednesday", "Thursday",
        "Friday", "Saturday", "Sunday")
    return week[Random().nextInt(week.size)]
}

fun fishFood (day : String) : String {
    return when (day) {
        "Monday" -> "flakes"
        "Wednesday" -> "redworms"
        "Thursday" -> "granules"
        "Friday" -> "mosquitoes"
        "Sunday" -> "plankton"
        else -> "nothing"
    }
}

fun feedTheFish() {
    val day = randomDay()
    val food = fishFood(day)
    println ("Today is $day and the fish eat $food")
}

fun main(args: Array<String>) {
    feedTheFish()
}

In dieser Aufgabe erfahren Sie mehr über Standardwerte für Funktionen und Methoden. Außerdem erfahren Sie mehr über kompakte Funktionen, mit denen Sie Ihren Code prägnanter und lesbarer gestalten und die Anzahl der zu testenden Codepfade reduzieren können. Kompakte Funktionen werden auch als Funktionen mit einem Ausdruck bezeichnet.

Schritt 1: Standardwert für einen Parameter erstellen

In Kotlin können Sie Argumente nach Parameternamen übergeben. Sie können auch Standardwerte für Parameter angeben. Wenn kein Argument vom Aufrufer angegeben wird, wird der Standardwert verwendet. Wenn Sie später Methoden (Memberfunktionen) schreiben, müssen Sie nicht viele überladene Versionen derselben Methode schreiben.

  1. Schreiben Sie in Hello.kt eine swim()-Funktion mit einem String-Parameter namens speed, der die Geschwindigkeit des Fisches ausgibt. Der Parameter speed hat den Standardwert "fast".
fun swim(speed: String = "fast") {
   println("swimming $speed")
}
  1. Rufen Sie die Funktion swim() aus der Funktion main() auf drei Arten auf. Rufen Sie die Funktion zuerst mit dem Standardwert auf. Rufen Sie dann die Funktion auf und übergeben Sie den Parameter speed ohne Namen. Rufen Sie die Funktion dann auf, indem Sie den Parameter speed benennen.
swim()   // uses default speed
swim("slow")   // positional argument
swim(speed="turtle-like")   // named parameter
⇒ swimming fast
swimming slow
swimming turtle-like

Schritt 2: Erforderliche Parameter hinzufügen

Wenn für einen Parameter kein Standardwert angegeben ist, muss das entsprechende Argument immer übergeben werden.

  1. Schreiben Sie in Hello.kt eine shouldChangeWater()-Funktion, die drei Parameter akzeptiert: day, temperature und eine dirty-Stufe. Die Funktion gibt true zurück, wenn das Wasser gewechselt werden sollte. Das ist der Fall, wenn Sonntag ist, die Temperatur zu hoch ist oder das Wasser zu schmutzig ist. Der Wochentag ist erforderlich, die Standardtemperatur ist jedoch 22 und der Standardverschmutzungsgrad ist 20.

    Verwende einen when-Ausdruck ohne Argument, der in Kotlin als Reihe von if/else if-Prüfungen fungiert.
fun shouldChangeWater (day: String, temperature: Int = 22, dirty: Int = 20): Boolean {
    return when {
        temperature > 30 -> true
        dirty > 30 -> true
        day == "Sunday" ->  true
        else -> false
    }
}
  1. Rufe shouldChangeWater() von feedTheFish() aus an und nenne den Tag. Für den Parameter day gibt es keinen Standardwert. Sie müssen also ein Argument angeben. Die anderen beiden Parameter von shouldChangeWater() haben Standardwerte, sodass Sie keine Argumente für sie übergeben müssen.
fun feedTheFish() {
    val day = randomDay()
    val food = fishFood(day)
    println ("Today is $day and the fish eat $food")
    println("Change water: ${shouldChangeWater(day)}")
}
=> Today is Thursday and the fish eat granules
Change water: false

Schritt 3: Kompakte Funktionen erstellen

Der when-Ausdruck, den Sie im vorherigen Schritt geschrieben haben, enthält viel Logik in wenig Code. Wenn Sie das Ganze etwas aufschlüsseln möchten oder die zu prüfenden Bedingungen komplizierter sind, können Sie einige gut benannte lokale Variablen verwenden. In Kotlin werden dafür jedoch kompakte Funktionen verwendet.

Kompakte Funktionen oder Funktionen mit einem einzelnen Ausdruck sind ein gängiges Muster in Kotlin. Wenn eine Funktion die Ergebnisse eines einzelnen Ausdrucks zurückgibt, können Sie den Funktionsrumpf nach dem Symbol = angeben, die geschweiften Klammern {} und die return weglassen.

  1. Fügen Sie in Hello.kt kompakte Funktionen hinzu, um die Bedingungen zu testen.
fun isTooHot(temperature: Int) = temperature > 30

fun isDirty(dirty: Int) = dirty > 30

fun isSunday(day: String) = day == "Sunday"
  1. Ändern Sie shouldChangeWater(), um die neuen Funktionen aufzurufen.
fun shouldChangeWater (day: String, temperature: Int = 22, dirty: Int = 20): Boolean {
    return when {
        isTooHot(temperature) -> true
        isDirty(dirty) -> true
        isSunday(day) -> true
        else  -> false
    }
}
  1. Führen Sie das Programm aus. Die Ausgabe von println() mit shouldChangeWater() sollte dieselbe sein wie vor der Umstellung auf kompakte Funktionen.

Standardwerte

Der Standardwert für einen Parameter muss kein Wert sein. Es kann sich auch um eine andere Funktion handeln, wie im folgenden Teilausschnitt gezeigt:

fun shouldChangeWater (day: String, temperature: Int = 22, dirty: Int = getDirtySensorReading()): Boolean {
    ...

In dieser Aufgabe erfahren Sie mehr über Filter in Kotlin. Mit Filtern können Sie einen Teil einer Liste auf Grundlage einer Bedingung abrufen.

Schritt 1: Filter erstellen

  1. Definieren Sie in Hello.kt eine Liste von Aquariendekorationen auf der obersten Ebene mit listOf(). Sie können den Inhalt von Hello.kt ersetzen.
val decorations = listOf ("rock", "pagoda", "plastic plant", "alligator", "flowerpot")
  1. Erstelle eine neue main()-Funktion mit einer Zeile, in der nur die Dekorationen ausgegeben werden, die mit dem Buchstaben „p“ beginnen. Der Code für die Filterbedingung steht in geschweiften Klammern {} und it bezieht sich auf jedes Element, das vom Filter durchlaufen wird. Wenn der Ausdruck true zurückgibt, wird das Element einbezogen.
fun main() {
    println( decorations.filter {it[0] == 'p'})
}
  1. Führen Sie das Programm aus. Im Fenster Ausführen wird die folgende Ausgabe angezeigt:
⇒ [pagoda, plastic plant]

Schritt 2: Eager- und Lazy-Filter vergleichen

Wenn Sie mit Filtern in anderen Sprachen vertraut sind, fragen Sie sich vielleicht, ob Filter in Kotlin eager oder lazy sind. Wird die Ergebnisliste sofort oder erst beim Zugriff auf die Liste erstellt? In Kotlin ist das ganz einfach. Standardmäßig ist filter eifrig und jedes Mal, wenn Sie den Filter verwenden, wird eine Liste erstellt.

Um den Filter verzögert auszuführen, können Sie ein Sequence verwenden. Das ist eine Sammlung, die jeweils nur ein Element betrachten kann, beginnend am Anfang und bis zum Ende. Praktischerweise ist das genau die API, die ein Lazy-Filter benötigt.

  1. Ändern Sie in Hello.kt den Code so, dass die gefilterte Liste einer Variablen namens eager zugewiesen und dann ausgegeben wird.
fun main() {
    val decorations = listOf ("rock", "pagoda", "plastic plant", "alligator", "flowerpot")

    // eager, creates a new list
    val eager = decorations.filter { it [0] == 'p' }
    println("eager: " + eager)
  1. Bewerten Sie den Filter unter diesem Code mit einem Sequence mit asSequence(). Weisen Sie die Sequenz einer Variablen mit der Bezeichnung filtered zu und geben Sie sie aus.
   // lazy, will wait until asked to evaluate
    val filtered = decorations.asSequence().filter { it[0] == 'p' }
    println("filtered: " + filtered)

Wenn Sie die Filterergebnisse als Sequence zurückgeben, enthält die Variable filtered keine neue Liste, sondern ein Sequence der Listenelemente und Informationen zum Filter, der auf diese Elemente angewendet werden soll. Immer wenn Sie auf Elemente von Sequence zugreifen, wird der Filter angewendet und das Ergebnis wird an Sie zurückgegeben.

  1. Erzwingen Sie die Auswertung der Sequenz, indem Sie sie mit toList() in eine List umwandeln. Geben Sie das Ergebnis aus.
    // force evaluation of the lazy list
    val newList = filtered.toList()
    println("new list: " + newList)
  1. Führen Sie das Programm aus und beobachten Sie die Ausgabe.
⇒ eager: [pagoda, plastic plant]
filtered: kotlin.sequences.FilteringSequence@386cc1c4
new list: [pagoda, plastic plant]

Um zu visualisieren, was mit Sequence und der verzögerten Auswertung passiert, verwenden Sie die Funktion map(). Die Funktion map() führt eine einfache Transformation für jedes Element in der Sequenz aus.

  1. Verwenden Sie dieselbe decorations-Liste wie oben und führen Sie eine Transformation mit map() durch, die nichts bewirkt und einfach das übergebene Element zurückgibt. Fügen Sie ein println() hinzu, um jedes Mal anzuzeigen, wenn auf ein Element zugegriffen wird, und weisen Sie die Sequenz einer Variablen mit dem Namen lazyMap zu.
    val lazyMap = decorations.asSequence().map {
        println("access: $it")
        it
    }
  1. Gibt lazyMap, das erste Element von lazyMap mit first() und lazyMap als List aus.
    println("lazy: $lazyMap")
    println("-----")
    println("first: ${lazyMap.first()}")
    println("-----")
    println("all: ${lazyMap.toList()}")
  1. Führen Sie das Programm aus und beobachten Sie die Ausgabe. Beim Drucken von lazyMap wird nur ein Verweis auf Sequence gedruckt. Das innere println() wird nicht aufgerufen. Beim Ausgeben des ersten Elements wird nur auf das erste Element zugegriffen. Wenn Sie die Sequence in eine List umwandeln, können Sie auf alle Elemente zugreifen.
⇒ lazy: kotlin.sequences.TransformingSequence@5ba23b66
-----
access: rock
first: rock
-----
access: rock
access: pagoda
access: plastic plant
access: alligator
access: flowerpot
all: [rock, pagoda, plastic plant, alligator, flowerpot]
  1. Erstellen Sie mit dem ursprünglichen Filter eine neue Sequence, bevor Sie map anwenden. Drucke dieses Ergebnis.
    val lazyMap2 = decorations.asSequence().filter {it[0] == 'p'}.map {
        println("access: $it")
        it
    }
    println("-----")
    println("filtered: ${ lazyMap2.toList() }")
  1. Führen Sie das Programm aus und sehen Sie sich die zusätzliche Ausgabe an. Wie beim Abrufen des ersten Elements wird das innere println() nur für die Elemente aufgerufen, auf die zugegriffen wird.
⇒
-----
access: pagoda
access: plastic plant
filtered: [pagoda, plastic plant]

In dieser Aufgabe erhalten Sie eine Einführung in Lambdas und Funktionen höherer Ordnung in Kotlin.

Lambdas

Zusätzlich zu herkömmlichen benannten Funktionen unterstützt Kotlin auch Lambdas. Eine Lambda-Funktion ist ein Ausdruck, der eine Funktion erstellt. Anstatt eine benannte Funktion zu deklarieren, deklarieren Sie eine Funktion ohne Namen. Ein Grund dafür, dass das so nützlich ist, ist, dass der Lambda-Ausdruck jetzt als Daten übergeben werden kann. In anderen Sprachen werden Lambdas als anonyme Funktionen, Funktionsliterale oder ähnliche Namen bezeichnet.

Funktionen höherer Ordnung

Sie können eine Funktion höherer Ordnung erstellen, indem Sie eine Lambda-Funktion an eine andere Funktion übergeben. In der vorherigen Aufgabe haben Sie eine Funktion höherer Ordnung namens filter erstellt. Sie haben den folgenden Lambda-Ausdruck als zu prüfende Bedingung an filter übergeben:
{it[0] == 'p'}

map ist ebenfalls eine Funktion höherer Ordnung und das Lambda, das Sie ihr übergeben haben, war die anzuwendende Transformation.

Schritt 1: Informationen zu Lambdas

  1. Wie benannte Funktionen können auch Lambdas Parameter haben. Bei Lambdas stehen die Parameter (und ihre Typen, falls erforderlich) links von einem sogenannten Funktionspfeil ->. Der auszuführende Code wird rechts neben dem Funktionspfeil angegeben. Sobald die Lambda-Funktion einer Variablen zugewiesen wurde, können Sie sie wie eine Funktion aufrufen.

    Probieren Sie diesen Code mit der REPL aus (Tools > Kotlin > Kotlin REPL):
var dirtyLevel = 20
val waterFilter = { dirty : Int -> dirty / 2}
println(waterFilter(dirtyLevel))
⇒ 10

In diesem Beispiel akzeptiert die Lambda-Funktion ein Int mit dem Namen dirty und gibt dirty / 2 zurück. (Durch die Filterung wird Schmutz entfernt.)

  1. Die Syntax von Kotlin für Funktionstypen ähnelt stark der Syntax für Lambdas. Verwenden Sie diese Syntax, um eine Variable, die eine Funktion enthält, sauber zu deklarieren:
val waterFilter: (Int) -> Int = { dirty -> dirty / 2 }

Das steht im Code:

  • Erstellen Sie eine Variable mit dem Namen waterFilter.
  • waterFilter kann eine beliebige Funktion sein, die ein Int akzeptiert und ein Int zurückgibt.
  • Weisen Sie waterFilter eine Lambda-Funktion zu.
  • Die Lambda-Funktion gibt den Wert des Arguments dirty geteilt durch 2 zurück.

Sie müssen den Typ des Lambda-Arguments nicht mehr angeben. Der Typ wird durch die Typinferenz berechnet.

Schritt 2: Funktion höherer Ordnung erstellen

Bisher sehen die Beispiele für Lambdas meist wie Funktionen aus. Die eigentliche Stärke von Lambdas liegt darin, dass sie zum Erstellen von Funktionen höherer Ordnung verwendet werden können, bei denen das Argument einer Funktion eine andere Funktion ist.

  1. Funktion höherer Ordnung schreiben Hier ist ein einfaches Beispiel für eine Funktion, die zwei Argumente akzeptiert. Das erste Argument ist eine Ganzzahl. Das zweite Argument ist eine Funktion, die eine Ganzzahl annimmt und eine Ganzzahl zurückgibt. Probieren Sie es in der REPL aus.
fun updateDirty(dirty: Int, operation: (Int) -> Int): Int {
   return operation(dirty)
}

Im Hauptteil des Codes wird die Funktion aufgerufen, die als zweites Argument übergeben wurde, und das erste Argument wird an sie übergeben.

  1. Um diese Funktion aufzurufen, übergeben Sie ihr eine Ganzzahl und eine Funktion.
val waterFilter: (Int) -> Int = { dirty -> dirty / 2 }
println(updateDirty(30, waterFilter))
⇒ 15

Die übergebene Funktion muss kein Lambda sein, sondern kann auch eine reguläre benannte Funktion sein. Wenn Sie das Argument als reguläre Funktion angeben möchten, verwenden Sie den Operator ::. So weiß Kotlin, dass Sie die Funktionsreferenz als Argument übergeben und nicht versuchen, die Funktion aufzurufen.

  1. Versuchen Sie, eine reguläre benannte Funktion an updateDirty() zu übergeben.
fun increaseDirty( start: Int ) = start + 1

println(updateDirty(15, ::increaseDirty))
⇒ 16
var dirtyLevel = 19;
dirtyLevel = updateDirty(dirtyLevel) { dirtyLevel -> dirtyLevel + 23}
println(dirtyLevel)
⇒ 42
  • Wenn Sie in IntelliJ IDEA eine Kotlin-Quelldatei erstellen möchten, beginnen Sie mit einem Kotlin-Projekt.
  • Wenn Sie ein Programm in IntelliJ IDEA kompilieren und ausführen möchten, klicken Sie neben der Funktion main() auf das grüne Dreieck. Die Ausgabe wird unten in einem Logfenster angezeigt.
  • Geben Sie in IntelliJ IDEA Befehlszeilenargumente an, die an die Funktion main() übergeben werden sollen (Run > Edit Configurations).
  • Fast alles in Kotlin hat einen Wert. Sie können diese Tatsache nutzen, um Ihren Code zu verkürzen, indem Sie den Wert eines if oder when als Ausdruck oder Rückgabewert verwenden.
  • Durch Standardargumente sind keine mehreren Versionen einer Funktion oder Methode mehr erforderlich. Beispiel:
    fun swim(speed: String = "fast") { ... }
  • Kompakte Funktionen oder Funktionen mit nur einem Ausdruck können Ihren Code lesbarer machen. Beispiel:
    fun isTooHot(temperature: Int) = temperature > 30
  • Sie haben einige Grundlagen zu Filtern kennengelernt, die Lambda-Ausdrücke verwenden. Beispiel:
    val beginsWithP = decorations.filter { it [0] == 'p' }
  • Ein Lambda-Ausdruck ist ein Ausdruck, der eine unbenannte Funktion erstellt. Lambda-Ausdrücke werden in geschweifte Klammern {} gesetzt.
  • Bei einer Funktion höherer Ordnung übergeben Sie eine Funktion, z. B. einen Lambda-Ausdruck, als Daten an eine andere Funktion. Beispiel:
    dirtyLevel = updateDirty(dirtyLevel) { dirtyLevel -> dirtyLevel + 23}

In dieser Lektion gibt es viel zu lernen, insbesondere wenn Sie noch nicht mit Lambdas vertraut sind. In einer späteren Lektion werden Lambdas und Funktionen höherer Ordnung noch einmal behandelt.

Kotlin-Dokumentation

Wenn Sie weitere Informationen zu einem Thema in diesem Kurs benötigen oder nicht weiterkommen, ist https://kotlinlang.org der beste Ausgangspunkt.

Kotlin-Tutorials

Die Website https://try.kotlinlang.org enthält umfangreiche Tutorials namens „Kotlin Koans“, einen webbasierten Interpreter und eine vollständige Referenzdokumentation mit Beispielen.

Udacity-Kurs

Den Udacity-Kurs zu diesem Thema finden Sie unter Kotlin Bootcamp for Programmers.

IntelliJ IDEA

Dokumentation für IntelliJ IDEA finden Sie auf der JetBrains-Website.

In diesem Abschnitt werden mögliche Hausaufgaben für Schüler und Studenten aufgeführt, die dieses Codelab im Rahmen eines von einem Kursleiter geleiteten Kurses durcharbeiten. Es liegt in der Verantwortung des Kursleiters, Folgendes zu tun:

  • Weisen Sie bei Bedarf Aufgaben zu.
  • Teilen Sie den Schülern/Studenten mit, wie sie Hausaufgaben abgeben können.
  • Benoten Sie die Hausaufgaben.

Lehrkräfte können diese Vorschläge nach Belieben nutzen und auch andere Hausaufgaben zuweisen, die sie für angemessen halten.

Wenn Sie dieses Codelab selbst durcharbeiten, können Sie mit diesen Hausaufgaben Ihr Wissen testen.

Beantworten Sie diese Fragen

Frage 1

Die Funktion contains(element: String) gibt true zurück, wenn der String element im String enthalten ist, für den sie aufgerufen wird. Was ist die Ausgabe des folgenden Codes?

val decorations = listOf ("rock", "pagoda", "plastic plant", "alligator", "flowerpot")

println(decorations.filter {it.contains('p')})

▢ [pagoda, plastic, plant]

▢ [pagoda, plastic plant]

▢ [pagoda, plastic plant, flowerpot]

▢ [rock, alligator]

Frage 2

Welcher der Parameter in der folgenden Funktionsdefinition ist erforderlich?
fun shouldChangeWater (day: String, temperature: Int = 22, dirty: Int = 20, numDecorations: Int = 0): Boolean {...}

▢ numDecorations

▢ dirty

▢ day

▢ temperature

Frage 3

Sie können eine reguläre benannte Funktion (nicht das Ergebnis des Aufrufs) an eine andere Funktion übergeben. Wie würden Sie increaseDirty( start: Int ) = start + 1 an updateDirty(dirty: Int, operation: (Int) -> Int) übergeben?

▢ updateDirty(15, &increaseDirty())

▢ updateDirty(15, increaseDirty())

▢ updateDirty(15, ("increaseDirty()"))

▢ updateDirty(15, ::increaseDirty)

Fahren Sie mit der nächsten Lektion fort: 4. Klassen und Objekte

Eine Übersicht über den Kurs mit Links zu anderen Codelabs finden Sie unter „Kotlin Bootcamp for Programmers: Welcome to the course“.