Kotlin

Einführung in Kotlin für Java-Entwickler

Erstellt von Frank Rahn

Abstrakt

{Abstrakt}

Tastenkombinationen

  • Space oder N springt zur nächsten Folie
  • P springt zur vorherigen Folie
  • F zeigt die Präsentation im Vollbildmodus
  • B zeigt die Pause Folie
  • Esc oder O zeigt die Übersicht der Folien
  • S wird die Speakers-Ansicht gestartet

Über mich

Kontakt

Frank Rahn
Frank Rahn
Twitter

Zur Person

Seit 1992 arbeite ich als freiberuflicher unabhängiger Softwarearchitekt und -consultant.

Seitdem beschäftige ich mich mit dem Entwurf und der Realisierung von Anwendungen und verfüge über umfangreiche Erfahrungen in der Integration von Anwendungen.

Meine Einsatzbereiche

  • Softwarearchitekturen mit Java-Technologien
    • mit Spring Framework, Boot, Batch, …
  • Integration von unternehmensübergreifenden IT-Systemen
    • per REST, SOAP, …
  • Entwicklung von großen und komplexen Systemen
  • Performance-Analysen mit entsprechender Optimierung

Voraussetzungen

Gute Programmierkenntnisse in Java 7!

Da beide Programmiersprachen auf der JVM aufbauen, werden nur die Unterschiede dargestellt.

In der Präsentation Changelog Java Versions habe ich alle Änderungen aus Sicht eines Entwicklers aufgeführt.

Einführung in Kotlin

Ein minimales Java-Programm

Java

Datei: Application.java

            package de.rahn.kotlin.java;

            public class Application {
              public static void main(String[] args) {
                System.out.println("Hello World!");
              }
            }
          

Kotlin!

Datei: Intro.kt

            fun main(args: Array<String>): Unit {
              println("Hello World!");
            }
          

Kürzer

Datei: Intro.kt

            fun main(args: Array<String>) {
              println("Hello World!");
            }
          

Weg damit

Datei: Intro.kt

            fun main(args: Array<String>) {
              println("Hello World!")
            }
          

Einfacher

Datei: Intro.kt

            fun main() {
              println("Hello World!")
            }
          

Minimalistisch

Datei: Intro.kt

            fun main() = println("Hello World!")
          
Datei: Application.java

            package de.rahn.kotlin.java;

            public class Application {
              public static void main(String[] args) {
                System.out.println("Hello World!");
              }
            }
          

Grundlegendes zu Kotlin

  • Drastische Reduktion von Boilerplate Code
    • Typinferenz: der Typ kann oft weg-
      gelassen werden
    • Als Anweisungsende genügt häufig
      der Zeilenumbuch
  • Erzwungene Null-Sicherheit
    • (Null / Call Safety)
  • Freundlich zu Entwicklungswerkzeugen
  • Hervorragende Interoperabilität mit Java
    • Kotlin kann in existierenden Projekte
      schrittweise eingeführt werden
  • Programmierung
    • Objektorientiert
    • Prozedural
    • Funktional
  • DSLs mit Kotlin

Ein wenig Syntax

Kurze Einführung in die Syntax von Kotlin

Datei: Syntax.kt

            class NamedValue(val name: String, var value: Int,) {
                fun print() {
                    println("$name = ${value + 1}")
                }
            }

            fun start(name: String, value: Int,) {
                val namedValue = NamedValue(name, value,)
                namedValue.print()
                namedValue.value = 10
                namedValue.print()
            }

            fun main() = start("index", 5,)
          

Kurze Einführung in die Syntax von Kotlin

Datei: Syntax.kt

            class NamedValue(val name: String, var value: Int,) {
                fun print() {
                    println("$name = ${value + 1}")
                }
            }

            fun start(name: String, value: Int,) {
                val namedValue = NamedValue(name, value,)
                namedValue.print()
                namedValue.value = 10
                namedValue.print()

                val array = arrayOf(
                    "Frank Rahn",
                    "Martin Rahn",
                    "Gerd Rahn",
                    "Anita Rahn",
                    "Alfred Rahn",
                    "Ruth Rahn",
                )

                array.forEach { element -> println(element) }
            }

            fun main() = start("index", 5,)
          

Interoperabilität mit Java

Die Java Klasse

Datei: TheJavaClass.java

            package de.rahn.kotlin.java;

            import de.rahn.kotlin.lang.TheKotlinClass;

            public class TheJavaClass {

              private final String name;
              private final int value;

              public TheJavaClass(String name, int value) {
                this.name = name;
                this.value = value;

                System.out.println("Java: Konstruktor");
              }

              public void print() {
                System.out.println("Java: " + name + " = " + value);
              }

              public static void main(String[] args) {
                System.out.println("Java: Start");
                TheKotlinClass theKotlinClass = new TheKotlinClass("index", 4711);
                System.out.println("Java: Kotlin-Class = " + theKotlinClass);
                theKotlinClass.print();
                System.out.println("Java: Finish");
              }
            }
          

Die Kotlin Klasse

Datei: TheKotlinClass.kt

            package de.rahn.kotlin.lang

            import de.rahn.kotlin.java.TheJavaClass

            class TheKotlinClass(val name: String, val value: Int) {

                fun print() {
                    println("Kotlin: Start with $name = $value")
                    val theJavaClass = TheJavaClass(name, value)
                    println("Kotlin: Java-Class = $theJavaClass")
                    theJavaClass.print()
                    println("Kotlin: Finish")
                }
            }
          

Multiplatform

  • Kotlin/JVM erzeugt Bytecode für die JVM
    • JVM Version 8 reicht aus
  • Kotlin/Android erzeugt eine Android App
  • Kotlin/JS transpile nach JavaScript
  • Kotlin/WASM compiliert nach WebAssembly
  • Kotlin für Data Science
  • Kotlin/Native mit LLVM Maschinensprache
    erstellen
    • Android, iOS, watchOS, tvOS
    • Linux, macOS, Windows
    • WebAssembly (Deprecated)
    • arm32, arm64, x86, x86_64, MIPS, wasm32

Entwicklungsgeschichte

  • Kotlin wird von JetBrains in Sankt Petersburg entwickelt
  • Ist stark geprägt von Scala
  • Erscheinungsjahr war 2011 und gilt seit 2016 als stabil
  • Google hat Kotlin 2019 zur bevorzugten Sprache für Android erklärt, konnte aber schon seit 2017 genutzt werden

Grundlagen von Kotlin

Variablen und Konstanten

Variable

Datei: Variables.kt

            package de.rahn.kotlin.lang

            fun variables() {
              var width: Int = 3840
              val height = 2160
              println("4K-UHD: Breite = $width, Höhe = $height")
            }

            fun main() = variables()
          

Read-only Variable

Datei: Variables.kt

            package de.rahn.kotlin.lang

            fun variables() {
              var width: Int = 3840
              val height = 2160
              println("4K-UHD: Breite = $width, Höhe = $height")
            }

            fun main() = variables()
          

Compile-Time Constants

Datei: Variables.kt

            package de.rahn.kotlin.lang

            const val PI: Double = 3.14159

            fun variables() {
              var width: Int = 3840
              val height = 2160
              println("4K-UHD: Breite = $width, Höhe = $height")

              println("Kreiszahl: $PI")
            }

            fun main() = variables()
          

Destructuring Declarations

Destructuring Declarations

Datei: DestructuringDeclarations.kt

            package de.rahn.kotlin.lang

            fun destructuringDeclarations() {
                val pair = Pair("index", 4711)
                println("First = ${pair.first}, Second = ${pair.second}")

                val (first, second) = pair
                println("First = $first, Second = $second")

                println("First = ${pair.component1()}, Second = ${pair.component2()}")

                val map = mapOf(pair)
                for ((key, value) in map) {
                    println("Key = $key, Value = $value")
                }
            }

            fun main() = destructuringDeclarations()
          

Ungenutzte Variablen

Datei: DestructuringDeclarations.kt

            package de.rahn.kotlin.lang

            fun destructuringDeclarations() {
                val pair = Pair("index", 4711)
                println("First = ${pair.first}, Second = ${pair.second}")

                val (first, second) = pair
                println("First = $first, Second = $second")

                println("First = ${pair.component1()}, Second = ${pair.component2()}")

                val map = mapOf(pair)
                for ((key, value) in map) {
                    println("Key = $key, Value = $value")
                }
                for ((_, value) in map) {
                    println("Value = $value")
                }
            }

            fun main() = destructuringDeclarations()
          

Kotlin Shell

kotlinc-jvm ist die Shell für Kotlin

REPL: Read-eval-print Loop


            $ kotlinc-jvm
            Welcome to Kotlin version 1.4.10 (JRE 11.0.9+11)
            Type :help for help, :quit for quit
            >>> val s = "Hello World!"
            >>> println(s)
            Hello World!
            >>> 1 + 2
            res2: kotlin.Int = 3
            >>> println(res2)
            3
            >>> :quit
          

Null Safety / Call Safety / Safe Casts

Null Safety / Call Safety

Datei: NullSafety.kt

            package de.rahn.kotlin.lang

            fun nullSafety(name: String?) {
              println(name?.length)
              println(name?.length ?: "x")

              name?.let {
                println(name.length)
              }

              println(name!!.length)
            }

            fun main() = nullSafety("Rahn") // nullSafety(null)
          

              4
              4
              4
              4
            

              null
              x
              Exception in thread "main" java.lang.NullPointerException
                at de.rahn.kotlin.lang.NullSafetyKt.nullSafety(NullSafety.kt:11)
            

Safe Casts

Datei: SafeCast.kt

            package de.rahn.kotlin.lang

            fun safeCast(value: Any?) {
              val i: Int? = value as? Int
              println("Int = $i")

              val s: String? = value as? String
              println("String = $s")
            }

            fun main() = safeCast("aa")
          

            Int = null
            String = aa
          

Safe Casts

Datei: SafeCast.kt

            package de.rahn.kotlin.lang

            fun safeCast(value: Any?) {
              val i: Int = value as? Int ?: -1
              println("Int = $i")

              val s: String = value as? String ?: return
              println("String = $s")
            }

            fun main() = safeCast(true)
          

            Int = -1
          

Strings

Strings

Datei: Variables.kt

            package de.rahn.kotlin.lang

            fun variables() {
              var text: String = "Hallo World!"
              println("Bitte das 7. Zeichen: '${text[6]}' aus '$text'")

              var character: Char = text.get(6)
              println(character)

              text = buildString {
                append("Values: ")
                for (i in 1..10) {
                  append("$i, ")
                }
              }
              println(text)
            }

            fun main() = variables()
          

Raw-String

Datei: Strings.kt

            package de.rahn.kotlin.lang

            fun strings() {
              val text = """
                  Lorem ipsum dolor sit amet,
                  consetetur sadipscing elitr,
                  sed diam nonumy eirmod tempor
                  WHERE path = "C:\windows\temp"
                """
              println(text)
            }

            fun main() = strings()
          
Ich hab die Blanks durch . ersetzt

......Lorem ipsum dolor sit amet,
......consetetur sadipscing elitr,
......sed diam nonumy eirmod tempor
......WHERE path = "C:\windows\temp"
....

Raw-String

Datei: Strings.kt

            package de.rahn.kotlin.lang

            fun strings() {
              val text = """
                  Lorem ipsum dolor sit amet,
                  consetetur sadipscing elitr,
                  sed diam nonumy eirmod tempor
                  WHERE path = "C:\windows\temp"
                """.trimIndent()
              println(text)
            }

            fun main() = strings()
          
Ich hab die Blanks durch . ersetzt
Lorem ipsum dolor sit amet,
consetetur sadipscing elitr,
sed diam nonumy eirmod tempor
WHERE path = "C:\windows\temp"

Operationen auf Strings


            $ kotlinc-jvm
            Welcome to Kotlin version 1.4.0 (JRE 11.0.8+10)
            Type :help for help, :quit for quit
            >>> val greetings = "Hello World!"
            >>> println(greetings[10])
            d
            >>> println(greetings.get(10))
            d
            >>> println(greetings.compareTo("asdf"))
            -25
            >>> println(greetings.equals("Hello World!"))
            true
            >>> println(greetings.equals("hello world!", ignoreCase = true))
            true
            >>> println(greetings == "Hello World!")
            true
            >>> println(greetings === "Hello World!")
            true
            >>> println(greetings.subSequence(1, 3))
            el
            >>> println(greetings.substring(1, 3))
            el
            >>> println(greetings.substring(1..2))
            el
            >>> println(greetings.chunked(5))
            [Hello,  Worl, d!]
            >>> println(greetings.capitalize())
            Hello World!
            >>> println(greetings.toUpperCase().decapitalize())
            hELLO WORLD!
            >>> println(greetings.replace(" ", ""))
            HelloWorld!
            >>> println(greetings.split(" "))
            [Hello, World!]
            >>> println(greetings.count())
            12
            >>> for (c in greetings) println(c)
            H
            e
            l
            l
            o

            W
            o
            r
            l
            d
            !
            >>> println(greetings.contains("Wor"))
            true
            >>> println(greetings.startsWith("Hello"))
            true
            >>> println(greetings.endsWith("World!"))
            true
            >>> println(greetings.indexOf("World"))
            6
            >>> println("%s: %02d mit %6.3f".format("Ergebnis", 2, 2.1))
            Ergebnis: 02 mit  2,100
            >>> :quit
            $
          

Nummern

Typ Bytes Minimum Maximum
Byte 1 -128 (-27) 127 (27 - 1)
Short 2 -32768 (-215) 32767 (215 - 1)
Int 4 -231 231 - 1
Long 8 -263 263 - 1

            val byteValue: Byte = 10
            val shortValue: Short = 4711
            val intValue = 4711
            val longValue = 4711L
          
Typ Bytes Dezimalstellen
Float 4 6-7
Double 8 15-16

            val floatValue = 3.14f
            val doubleValue = 3.14
            val doubleValue = 3.14e10
          

Package / Import

Package

Datei: Variables.kt

            package de.rahn.kotlin.lang

            fun variables() {
            }

            fun main() = variables()
          

Import

Datei: Variables.kt

            package de.rahn.kotlin.lang

            import kotlin.math.PI as PI_KOTLIN
            import java.lang.Math.PI as PI_JAVA

            fun variables() {
              println("Kreiszahl: $PI_KOTLIN")
            }

            fun main() = variables()
          

Bedingte Anweisungen und Schleifen

if Anweisung

if Anweisung

Datei: ControlFlowIf.kt

            package de.rahn.kotlin.lang

            fun max(a: Int, b: Int): Int {
              var max: Int
              if (a > b) {
                max = a
              } else {
                max = b
              }
              return max
            }

            fun controlFlow() {
              println("max(4, 5) = ${max(4, 5)}")
            }

            fun main() = controlFlow()
          

if Anweisung

Datei: ControlFlowIf.kt

            package de.rahn.kotlin.lang

            fun max(a: Int, b: Int): Int {
              val max = if (a > b) {
                a
              } else {
                b
              }
              return max
            }

            fun controlFlow() {
              println("max(4, 5) = ${max(4, 5)}")
            }

            fun main() = controlFlow()
          

if Anweisung

Datei: ControlFlowIf.kt

            package de.rahn.kotlin.lang

            fun max(a: Int, b: Int): Int {
              return if (a > b) {
                a
              } else {
                b
              }
            }

            fun controlFlow() {
              println("max(4, 5) = ${max(4, 5)}")
            }

            fun main() = controlFlow()
          

if Anweisung

Datei: ControlFlowIf.kt

            package de.rahn.kotlin.lang

            fun max(a: Int, b: Int): Int = if (a > b) {
              a
            } else {
              b
            }

            fun controlFlow() {
              println("max(4, 5) = ${max(4, 5)}")
            }

            fun main() = controlFlow()
          

if Anweisung

Datei: ControlFlowIf.kt

            package de.rahn.kotlin.lang

            fun max(a: Int, b: Int) = if (a > b) {
              a
            } else {
              b
            }

            fun controlFlow() {
              println("max(4, 5) = ${max(4, 5)}")
            }

            fun main() = controlFlow()
          

Ternärer Operator

Ternärer Operator

Den ternären Operation gibt es unter Kotlin nicht!


            i > 0 ? "true" : "false"
          

Er wird durch die folgende Anweisung ersetzt.


              if (i > 0) "true" else "false"
            

Diese Anweisung ist ausführlicher,
aber klarer.

Smart Casts

Smart Casts

Datei: SmartCasts.kt

            package de.rahn.kotlin.lang

            import de.rahn.kotlin.lang.classes.Circle
            import de.rahn.kotlin.lang.classes.Shape

            fun smartCasts() {
                val shape1: Shape = Circle(radius = 1.0)
                if (shape1 is Circle) {
                    println(shape1.radius)
                }

                val shape2: Shape? = null
                if (shape2 is Shape) {
                    println(shape2.area())
                }
            }

            fun printStringLength(x: Any) {
                if (x !is String) {
                    return;
                }

                println(x.length)
            }

            fun main() = smartCasts()
          

when Anweisung

when Anweisung

When ersetzt die Switch von Java.

Datei: ControlFlowWhen.kt

            package de.rahn.kotlin.lang

            enum class Status {
              OK, ERROR
            }

            fun controlFlowWhen(y: Any) {
              val b = when (y) {
                is String -> true
                else -> false
              }

              val x = 42
              when (x) {
                1 -> println("x ist 1")
                2 -> println("x ist 2")
                3, 4 -> println("x ist 3 oder 4")
                in 5..10 -> println("x ist zwischen 5 und 10")
                else -> println("x ist irgend etwas anderes")
              }

              val status = Status.OK
              when (status) {
                Status.OK -> println("Super")
                Status.ERROR -> println("Nicht gut")
                else -> return
              }

              when {
                x < 42 -> println("-1")
                x == 0 -> println("0")
                x > 42 -> println("1")
                else -> throw IllegalArgumentException("Mist")
              }

              when (val z = max(4, 5)) {
                in 5..100 -> println(z - 5)
              }
            }

            fun main() = controlFlowWhen("")
          

for Schleifen

for Anweisung


            $ kotlinc-jvm
            Welcome to Kotlin version 1.4.0 (JRE 11.0.8+10)
            Type :help for help, :quit for quit
            >>> for (i in 1..3) println(i)
            1
            2
            3
            >>> for (i in 1..3 step 2) println(i)
            1
            3
            >>> for (i in 3 downTo 1) println(i)
            3
            2
            1
            >>> for (i in 3 downTo 1 step 2) println(i)
            3
            1
            >>> for (i in 1 until 3) println(i)
            1
            2
            >>> for (i in 1 until 3 step 2) println(i)
            1
            >>> val string = "ABC"
            >>> for (c in string) println(c)
            A
            B
            C
            >>> for (i in string.indices) println(string[i])
            A
            B
            C
            >>> for ((index, value) in string.withIndex()) {
            ...   println("Buchstabe $index ist $value")
            ... }
            Buchstabe 0 ist A
            Buchstabe 1 ist B
            Buchstabe 2 ist C
            >>> val array = arrayOf("Frank", "Martin", "Gerd", "Anita")
            >>> for (item in array) println(item)
            Frank
            Martin
            Gerd
            Anita
            >>> val map = mapOf("Köln" to "0221", "Bonn" to "0228")
            >>> for ((city, areaCode) in map) println("Vorwahl von $city ist $areaCode")
            Vorwahl von Köln ist 0221
            Vorwahl von Bonn ist 0228
            >>>
          

while Schleifen

while Anweisung

Datei: ControlFlowWhile.kt

            package de.rahn.kotlin.lang

            fun controlFlowWhile() {
              var x = 3
              println("Start $x")

              while (x > 0) {
                x--
                println(x)
              }

              println("Mitte $x")

              do {
                val y = ++x
                println(x)
              } while (y < 3)

              println("Ende $x")
            }

            fun main() = controlFlowWhile()
          

Break und Continue mit Labels

Break und Continue mit Labels

Datei: ControlFlowBreakContinue.kt

            package de.rahn.kotlin.lang

            fun controlFlowBreakContinue() {
              loop@ while (true) {
                for (x in 1..10_000) {
                  when (x) {
                    4711 -> break@loop
                    6666 -> continue@loop
                  }
                  print("$x ")
                }
              }
              println()
            }

            fun main() = controlFlowBreakContinue()
          

repeat Schleifen

repeat Schleife bzw. Funktion


            $ kotlinc-jvm
            Welcome to Kotlin version 1.4.10 (JRE 11.0.9.1+1)
            Type :help for help, :quit for quit
            >>> repeat(3) { println(it) }
            0
            1
            2
            >>>
          

Funktionen

Prozedurale Programmierung

Grundlagen Funktionen

Top-level functions

Die Top-level Funktionen können von überall aufgerufen werden

Datei: Functions.kt

            package de.rahn.kotlin.lang

            fun power(base: Double, exp: Int,): Double {
              var result = 1.0

              for (i in 1..exp) {
                result *= base
              }

              return result
            }

            fun functions() {
              println(power(2.0, 8,))
            }

            fun main() = functions()
          

Single-expression

Datei: FunctionsSingleExpression.kt

            package de.rahn.kotlin.lang

            fun square(x: Int) = x * x

            fun fibonacci(n: Int): Int = when (n) {
              0 -> 0
              1 -> 1
              else -> fibonacci(n - 1) + fibonacci(n - 2)
            }

            fun fakultaet(n: Int): Double = when (n) {
              0 -> 1.0
              else -> n * fakultaet(n - 1)
            }

            fun functionsSingleExpression() {
              println("Doppelt ${doppelt(10)}")
              println("Fibonacci ${fibonacci(10)}")
              println("Fakultät ${fakultaet(10)}")
            }

            fun main() = functionsSingleExpression()
          

Explicit-return

Datei: FunctionsExplicitReturn.kt

            package de.rahn.kotlin.lang

            import kotlin.math.abs

            fun sin(x: Double): Double {
              var result = 0.0

              for (n in 0..100) {
                val z = (power(-1.0, n) * power(x, 2 * n + 1)) / fakultaet(2 * n + 1)
                result += z
                println("n: $n -> result=$result (z=$z)")

                if (abs(z) < 0.000_000_000_001) {
                  break
                }
              }

              return result
            }

            fun functionsExplicitReturn() {
              println("sin(1.0) = ${sin(1.0)}")
            }

            fun main() = functionsExplicitReturn()
          

Unit-returning

Java: void

Datei: FunctionsUnitReturning.kt

            package de.rahn.kotlin.lang

            fun functionsUnitReturning(): Unit {
              println("Hello World!")
            }

            fun main() = functionsUnitReturning()
          

Unit-returning

Java: void

Datei: FunctionsUnitReturning.kt

            package de.rahn.kotlin.lang

            fun functionsUnitReturning() {
              println("Hello World!")
            }

            fun main() = functionsUnitReturning()
          

Nothing-returning

Datei: FunctionsNothingReturning.kt

            package de.rahn.kotlin.lang

            fun fail(reason: String): Nothing =
                throw IllegalStateException("An operation is not implemented: $reason");

            fun functionsNothingReturning(message: String): String {
              fail(message)

              return message;
            }

            fun main() {
              functionsNothingReturning("Bla Blubber")
            }
          

Generics

Datei: FunctionsGenerics.kt

            package de.rahn.kotlin.lang

            fun <T> genList(a: T): List<T> = listOf(a)

            fun functionsGenerics() {
              println(genList(1))
              println(genList("Test"))
            }

            fun main() = functionsGenerics()
          

Tail-recursive

Verwendet Tail-recursion/call oder Endrekursion

Datei: FunctionsTailRecursion.kt

            package de.rahn.kotlin.lang

            import kotlin.math.abs

            const val EPS = 1E-12

            tailrec fun sin(x: Double, n: Int = 0, result: Double = 0.0): Double {
              val m = 2 * n + 1
              val z = (power(-1.0, n) * power(x, m)) / fakultaet(m)
              val result2 = result + z
              println("n: $n -> result=$result2 (z=$z)")

              if (abs(z) < EPS) {
                return result2;
              }

              return sin(x, n + 1, result2)
            }

            fun functionsTailRecursion() {
              println("sin(1.0) = ${sin(1.0)}")
            }

            fun main() = functionsTailRecursion()
          

Argumente

Default und benannte Argumente

Datei: FunctionsDefaultNamedArgs.kt

            package de.rahn.kotlin.lang

            fun sum(sum: Int, i: Int, reihe: Int): Int {
              val vielfaches = i % reihe == 0
              if (vielfaches) {
                print("$i, ")
                return sum + i
              }
              return sum
            }

            fun x(reihe: Int, until: Int = 100): Int {
              var sum = 0
              for (i in 0..until) {
                sum = sum(sum, i, reihe)
              }
              println("Sum: $sum")
              return sum
            }

            fun functionsDefaultNamedArgs() {
              x(7)
              x(reihe = 7)
              x(3, until = 60)
            }

            fun main() = functionsDefaultNamedArgs()
          

Variable Anzahl von Argumenten

Datei: FunctionsVariableArgs.kt

            package de.rahn.kotlin.lang

            fun asList(vararg args: String): List<String> {
              val result = mutableListOf<String>()
              for (arg in args) {
                result.add(arg)
              }
              return result
            }

            fun functionsVariableArgs() {
              println(asList())

              println(asList("aa", "bb", "cc"))

              val liste = arrayOf("aa", "bb")
              println(asList(*liste, "cc"))
            }

            fun main() = functionsVariableArgs()
          

Operationsraum einer Funktion

Arten von Funktionen

Local Function

Datei: FunctionsLocal.kt

            package de.rahn.kotlin.lang

            fun functionsLocal() {
              var y = 42

              fun f(x: Int): Int {
                return x + y++
              }

              println(f(4711))
              println(y)
            }

            fun main() = functionsLocal()
          

Member Function

Datei: FunctionsMember.kt

            package de.rahn.kotlin.lang

            class FunctionsMember {
              fun function(x: Int) {
                println(x)
              }
            }

            fun functionsMember(){
              FunctionsMember().function(4711)
            }

            fun main() = functionsMember()
          

Mehr zu den Member Functions bei den Klassen

Member Function

Datei: FunctionsMember.kt

            package de.rahn.kotlin.lang

            class FunctionsMember {
              fun function(x: Int) {
                privateFunction(x)
              }

              private fun privateFunction(x: Int) {
                println(x)
              }
            }

            fun functionsMember(){
              FunctionsMember().function(4711)
            }

            fun main() = functionsMember()
          

Mehr zu den Member Functions bei den Klassen

Lambdas und Funktionen höherer Ordnung

Funktionale Programmierung

Lambda-Ausdruck bzw. Closure

Lambda-Ausdruck bzw. Closure

Datei: FunctionsLambdas.kt

            package de.rahn.kotlin.lang

            fun functionsLambdas() {
              val add: (Int, Int) -> Int = { a, b -> a + b }

              println(add(42, 4711))
            }

            fun main() = functionsLambdas()
          

Lambda-Ausdruck bzw. Closure

Datei: FunctionsLambdas.kt

            package de.rahn.kotlin.lang

            fun functionsLambdas() {
              val add = { a: Int, b: Int -> a + b }

              println(add(42, 4711))
            }

            fun main() = functionsLambdas()
          

Funktionen höherer Ordnung

Funktionen höherer Ordnung

Datei: FunctionsHigherOrder.kt

            package de.rahn.kotlin.lang

            fun higherOrderFunctionArgs(f: (a: Int, b: Int) -> Int) {
              println(f(42, 4711))
            }

            fun higherOrderFunctionReturn(): (Int, Int) -> Int {
              return { a: Int, b: Int -> a + b }
            }

            fun functionsHigherOrder() {
              higherOrderFunctionArgs(higherOrderFunctionReturn())

              higherOrderFunctionArgs({ a: Int, b: Int -> a + b })

              higherOrderFunctionArgs {
                a: Int, b: Int -> a + b
              }

              higherOrderFunctionArgs {
                a, b -> a + b
              }
            }

            fun main() = functionsHigherOrder()
          

Funktionen höherer Ordnung


            $ kotlinc-jvm
            Welcome to Kotlin version 1.4.10 (JRE 11.0.9.1+1)
            Type :help for help, :quit for quit
            >>> val array = arrayOf("Frank", "Martin", "Gerd")
            >>> array.forEach({ s: String -> println(s.reversed()) })
            knarF
            nitraM
            dreG
            >>> array.forEach() { s: String -> println(s.reversed()) }
            knarF
            nitraM
            dreG
            >>> array.forEach() { s -> println(s.reversed()) }
            knarF
            nitraM
            dreG
            >>> array.forEach() { println(it.reversed()) }
            knarF
            nitraM
            dreG
            >>> array.forEach { println(it.reversed()) }
            knarF
            nitraM
            dreG
            >>> array.forEach(::println)
            Frank
            Martin
            Gerd
            >>>
          

typealias mit Lambdas

Datei: FunctionsHigherOrder.kt

            package de.rahn.kotlin.lang

            typealias Lambda = (Int, Int) -> Int

            fun higherOrderFunctionArgs(f: Lambda) {
              println(f(42, 4711))
            }

            fun higherOrderFunctionReturn(): Lambda {
              return { a: Int, b: Int -> a + b }
            }

            fun functionsHigherOrder() {
              higherOrderFunctionArgs(higherOrderFunctionReturn())

              higherOrderFunctionArgs({ a: Int, b: Int -> a + b })

              higherOrderFunctionArgs {
                a: Int, b: Int -> a + b
              }

              higherOrderFunctionArgs {
                a, b -> a + b
              }
            }

            fun main() = functionsHigherOrder()
          

Anonyme Funktionen

Anonyme Funktionen

Datei: FunctionsAnonymousFunction.kt

            package de.rahn.kotlin.lang

            fun anonymousFunction() {
              val add = fun(a: Int, b: Int): Int { return a + b }
              println(add(1, 3))

              arrayOf("Frank", "Martin", "Gerd").forEach(
                  fun(element: String) { println(element) }
              )
            }

            fun main() = anonymousFunction()
          

Inline Funktionen

Warum Inline Funkionen?

  • Lambdas haben einen Overhead
    • Lambdas sind Objekte
    • Variablen und Argumente müssen gespeichert
  • Durch Inlining wird der Bytecode direkt an die Aufrufstelle gesetzt
  • Erhöht den Anteil des generierten Bytecodes

Inline Funkionen

In Kotlin …


            inline fun inlined(lambda: () -> Unit) {
              println("Starting ...")
              lambda()
              println("Finished!")
            }

            fun main() {
              inlined { println("Hello, World!") }
            }
          

Inline Funkionen

Im Bytecode …


            fun main() {
              println("Starting ...")
              println("Hello, World!")
              println("Finished!")
            }
          

Nicht Anwenden

  • Nicht bei großen Funktionen verwenden
  • Inlining geht bei Rekursionen nicht
  • Zuweisung des Lambdas an Variablen

Inline Funkionen

Datei: FunctionsInline.kt

            package de.rahn.kotlin.lang

            import java.util.concurrent.locks.Lock
            import java.util.concurrent.locks.ReentrantLock

            inline fun <T> lockTemplate(lock: Lock, body: () -> T): T {
              lock.lock()
              try {
                return body()
              } finally {
                lock.unlock()
              }
            }

            fun functionsInline() {
              val s: String = lockTemplate(ReentrantLock()) {
                "Synchronized call"
              }
              println(s)
            }

            fun main() = functionsInline()
          

Noinline Inline Funkionen

Datei: FunctionsInlineNoinline.kt

            package de.rahn.kotlin.lang

            import java.util.concurrent.locks.Lock
            import java.util.concurrent.locks.ReentrantLock

            inline fun <T> lockTemplate2(noinline lock: () -> Lock, body: () -> T): T {
              val lockObj = lock()
              lockObj.lock()
              try {
                return body()
              } finally {
                lockObj.unlock()
              }
            }

            fun functionsInline() {
              val s: String = lockTemplate2({ ReentrantLock() }) {
                "Synchronized call"
              }
              println(s)
            }

            fun main() = functionsInline()
          

Non-local returns Inline Funktionen

Datei: FunctionsInlineNonLocalReturns.kt

            package de.rahn.kotlin.lang

            inline fun inlined2(x: Int, lambda: (Int) -> String): String {
              return lambda(x)
            }

            fun nonLocalReturn(): Boolean {
              val b = inlined2(-1) {
                if (it > 0) {
                  return false
                }

                "Ok"
              }

              return b == "Ok"
            }

            fun main() = println(nonLocalReturn())
          

Non-local returns Inline Funktionen

Datei: FunctionsInlineNonLocalReturns.kt

            package de.rahn.kotlin.lang

            inline fun inlined2(x: Int, lambda: (Int) -> String): String {
              return lambda(x)
            }

            fun nonLocalReturn(): Boolean {
              val b = inlined2(5) {
                if (it > 0) {
                  return false
                }

                "Ok"
              }

              return b == "Ok"
            }

            fun main() = println(nonLocalReturn())
          

Crossinline Funktionen

Non-locale returns sind hier nicht erlaubt

Datei: FunctionsInlineCrossinline.kt

            package de.rahn.kotlin.lang

            interface Button {
              fun pushMe(): String
            }

            inline fun controller(crossinline body: () -> String): Button {
              return object : Button {
                override fun pushMe() = body()
              }
            }

            fun functionsInlineCrossinline() {
              val button = controller { "pushed" }

              println(button.pushMe())
            }

            fun main() = functionsInlineCrossinline()
          

Weitere Konzepte der Inline Funktionen

  • Geplant sind Unterstützung für break und continue

Klassen

Objektorientierte Programmierung

Grundlagen Klassen

Eine leere Klasse …

Datei: Person.kt

            package de.rahn.kotlin.lang.classes

            class Person

            fun person() {
              val person = Person()
              println(person)
            }

            fun main() = person()
          

… mit Body

Datei: Person.kt

            package de.rahn.kotlin.lang.classes

            class Person {
            }

            fun person() {
              val person = Person()
              println(person)
            }

            fun main() = person()
          

… mit einem primären Konstruktor

Datei: Person.kt

            package de.rahn.kotlin.lang.classes

            class Person public constructor(name: String) {
            }

            fun person() {
              val person = Person("Müller")
              println(person)
            }

            fun main() = person()
          

… ohne Modifier

Datei: Person.kt

            package de.rahn.kotlin.lang.classes

            class Person constructor(name: String) {
            }

            fun person() {
              val person = Person("Müller")
              println(person)
            }

            fun main() = person()
          

… kürzer (Normale Schreibweise)

Datei: Person.kt

            package de.rahn.kotlin.lang.classes

            class Person(name: String) {
            }

            fun person() {
              val person = Person("Müller")
              println(person)
            }

            fun main() = person()
          

… mit einem Property (Attribut, Field, …)

Datei: Person.kt

            package de.rahn.kotlin.lang.classes

            class Person(name: String) {
              val lastName = name
            }

            fun person() {
              val person = Person("Müller")
              println(person.lastName)
            }

            fun main() = person()
          

… müssen immer initialisiert werden

Datei: Person.kt

            package de.rahn.kotlin.lang.classes

            class Person(name: String) {
              val lastName = name
              var age = -1
            }

            fun person() {
              val person = Person("Müller")
              println("${person.lastName} (${person.age})")
            }

            fun main() = person()
          

… setzen eines Properties

Datei: Person.kt

            package de.rahn.kotlin.lang.classes

            class Person(name: String) {
              val lastName = name
              var age = -1
            }

            fun person() {
              val person = Person("Müller")
              person.age = 10
              println("${person.lastName} (${person.age})")
            }

            fun main() = person()
          

… mit sekundärem Konstruktor

Datei: Person.kt

            package de.rahn.kotlin.lang.classes

            class Person(name: String) {
              val lastName = name
              var age = -1

              constructor(name: String, age: Int) : this(name) {
                this.age = age
              }
            }

            fun person() {
              val person = Person("Müller", 20)
              println("${person.lastName} (${person.age})")
            }

            fun main() = person()
          

… mit Initializer-blocks

Datei: Person.kt

            package de.rahn.kotlin.lang.classes

            class Person(name: String) {
              init {
                println("Init block No. 1: name=$name")
              }

              val lastName = name

              init {
                println("Init block No. 2: lastName=$lastName")
              }

              var age = 0

              init {
                age = -1
                println("Init block No. 3: age=$age")
              }

              constructor(name: String, age: Int) : this(name) {
                println("Secondary Constructor")
                this.age = age
              }

              init {
                println("Init block No. 4: age=$age")
              }
            }

            fun person() {
              val person = Person("Müller", 20)
              println("Function person: ${person.lastName} (${person.age})")
            }

            fun main() = person()
          

… mit Initializer-blocks

Die Ausgabe in der Konsole

Init block No. 1: name=Müller
Init block No. 2: lastName=Müller
Init block No. 3: age=-1
Init block No. 4: age=-1
Secondary Constructor
Function person: Müller (20)

… mit Property Definition im Konstruktor

Datei: Person2.kt

            package de.rahn.kotlin.lang.classes

            class Person2(val lastName: String,) {
              var age = -1
            }

            fun person2() {
              val person = Person2("Müller")
              person.age = 20
              println("${person.lastName} (${person.age})")
            }

            fun main() = person2()
          

… ohne primären Konstruktor

Datei: Person3.kt

            package de.rahn.kotlin.lang.classes

            class Person3 {
              val lastName: String
              var age: Int

              constructor(lastName: String, age: Int) {
                this.lastName = lastName
                this.age = age
              }

              constructor() {
                lastName = "Mustermann"
                age = 30
              }
            }

            fun person3() {
              var person = Person3()
              println("${person.lastName} (${person.age})")

              person = Person3("Müller", 20)
              println("${person.lastName} (${person.age})")
            }

            fun main() = person3()
          

… mit einem Setter

Datei: Person2.kt

            package de.rahn.kotlin.lang.classes

            class Person2(val lastName: String,) {
              var age = -1
                set(value) {
                  if (value >= 18) {
                    age = value
                  }
                }
            }

            fun person2() {
              val person = Person2("Müller")
              person.age = 20
              println("${person.lastName} (${person.age})")
            }

            fun main() = person2()
          
Exception in thread "main" java.lang.StackOverflowError
	at de.rahn.kotlin.lang.classes.Person2.setAge(Person2.kt:7)

… mit einem Setter

Datei: Person2.kt

            package de.rahn.kotlin.lang.classes

            class Person2(val lastName: String,) {
              var age = -1
                set(value) {
                  if (value >= 18) {
                    this.age = value
                  }
                }
            }

            fun person2() {
              val person = Person2("Müller")
              person.age = 20
              println("${person.lastName} (${person.age})")
            }

            fun main() = person2()
          

… mit einem Setter

Datei: Person2.kt

            package de.rahn.kotlin.lang.classes

            class Person2(val lastName: String,) {
              var age = -1
                set(value) {
                  if (value >= 18) {
                    field = value
                  }
                }
            }

            fun person2() {
              val person = Person2("Müller")
              person.age = 20
              println("${person.lastName} (${person.age})")
            }

            fun main() = person2()
          

… mit einem Setter

Datei: Person2.kt

            package de.rahn.kotlin.lang.classes

            class Person2(val lastName: String, age: Int) {
              var age = -1
                set(value) {
                  if (value >= 18) {
                    field = value
                  }
                }

              init {
                this.age = age
              }
            }

            fun person2() {
              val person = Person2("Müller", 12)
              println("${person.lastName} (${person.age})")
            }

            fun main() = person2()
          

… mit einem Getter

Datei: Person2.kt

            package de.rahn.kotlin.lang.classes

            class Person2(val lastName: String,) {
              var age = -1
                get() = field
                set(value) {
                  if (value >= 18) {
                    field = value
                  }
                }
            }

            fun person2() {
              val person = Person2("Müller")
              person.age = 20
              println("${person.lastName} (${person.age})")
            }

            fun main() = person2()
          

… Sichtbarkeit verändert (Modifiers)

Datei: Person2.kt

            package de.rahn.kotlin.lang.classes

            class Person2(val lastName: String,) {
              var age = -1
                get() = field
                private set(value) {
                  if (value >= 18) {
                    field = value
                  }
                }
            }

            fun person2() {
              val person = Person2("Müller")
              println("${person.lastName} (${person.age})")
            }

            fun main() = person2()
          

… Sichtbarkeit verändert (Modifiers)

Datei: Person2.kt

            package de.rahn.kotlin.lang.classes

            class Person2(val lastName: String,) {
              var age = -1
                private set

              private var salary = 0
            }
          

… Sichtbarkeit verändert (Modifiers)

Datei: Person2.kt

            package de.rahn.kotlin.lang.classes

            class Person2(val lastName: String,) {
              var age = -1
                internal set

              private var salary = 0
            }
          

… mit Inline-Property

Datei: Person2.kt

            package de.rahn.kotlin.lang.classes

            class Person2(val lastName: String,) {
              var age = -1
                inline set

              inline var salary = 0
            }
          

… mit Computed-Property

Datei: Person2.kt

            package de.rahn.kotlin.lang.classes

            class Person2(val lastName: String) {
              var age = -1
                get() = field
                internal set(value) {
                  if (value >= 18) {
                    field = value
                  }
                }

              val isValidAge: Boolean
                get() = age >= 18
            }

            fun person2() {
              val person = Person2("Müller")
              if (!person.isValidAge) {
                person.age = 20
              }
              println("${person.lastName} (${person.age})")
            }

            fun main() = person2()
          

… mit Annotated-Property

Datei: Person2.kt

            package de.rahn.kotlin.lang.classes

            import org.springframework.beans.factory.annotation.Autowired

            class Person2(val lastName: String) {
              var age = -1
                get() = field
                internal set(value) {
                  if (value >= 18) {
                    field = value
                  }
                }

              val isValidAge: Boolean
                get() = age >= 18

              var dependencyInjection: Any? = null
                @Autowired set
            }

            fun person2() {
              val person = Person2("Müller")
              if (!person.isValidAge) {
                person.age = 20
              }
              println("${person.lastName} (${person.age})")
            }

            fun main() = person2()
          

… mit Lateinit-Property

Datei: Person4.kt

            package de.rahn.kotlin.lang.classes

            class Person4(val lastName: String) {
              private lateinit var status: String

              val getStatus: String
                get() {
                  if (!::status.isInitialized) {
                    status = "Ok"
                  }

                  return status
                }
            }

            fun person4() {
              val person = Person4("Müller")
              println("${person.lastName} (${person.getStatus})")
            }

            fun main() = person4()
          

Member-Function

Die Member Functions wurden bei dem Operationsraum einer Funktion schon grundsätzlich beschrieben

Infix

Datei: FunctionsMemberInfix.kt

            package de.rahn.kotlin.lang

            class FunctionsMemberInfix {
              infix fun greetings(message: String) {
                println(message)
              }
            }

            fun functionsMemberInfix() {
              val o = FunctionsMemberInfix()

              o.greetings("Hello World!")
              o greetings "Hello World!"
            }

            fun main() = functionsMemberInfix()
          

Extension

Datei: FunctionsMemberExtension.kt

            package de.rahn.kotlin.lang

            fun Int.mod(x: Int) = this % x

            fun Int.toString() = "Mist"

            fun functionsMemberExtension() {
              println(17.mod(3))
              println(18.toString())
            }

            fun main() = functionsMemberExtension()
          
2
18

Extension

Datei: FunctionsMemberExtension.kt

            package de.rahn.kotlin.lang

            infix fun Int.mod(x: Int) = this % x

            fun Int.toString() = "Mist"

            fun functionsMemberExtension() {
              println(17 mod 3)
              println(18.toString())
            }

            fun main() = functionsMemberExtension()
          
2
18

Extension als Member Function

Datei: FunctionsMemberExtensionMember.kt

            package de.rahn.kotlin.lang

            class FunctionsMemberExtensionMember {
              fun Int.print() {
                println(this@FunctionsMemberExtensionMember.toString())
                println(toString())
              }

              fun doIt(x: Int) {
                x.print()
              }
            }

            fun functionsMemberExtensionMember(){
              FunctionsMemberExtensionMember().doIt(4711)
            }

            fun main() = functionsMemberExtensionMember()
          
de.rahn.kotlin.lang.FunctionsMemberExtensionMember@2f7c7260
4711

Scope Functions

Funktion Objektzugriff Returnwert
obj.let {…} it Lambda
Returnwert
obj.run {…} this
with(obj) {…}
obj.apply {…} obj
obj.also {…} it

Scope Functions

Funktion Objektzugriff Returnwert
run {…} - Lambda
Returnwert
obj.takeIf {…} it obj or null
obj.takeUnless {…}

Scope Function: let {…}

Datei: FunctionsScopeLet.kt

            package de.rahn.kotlin.lang

            fun functionsScopeLet() {
              val b = "test".let {
                it.isEmpty()
              }
              println("b: $b")

              val myString: String? = "Hello World!"
              myString?.let {
                println("Länge myString: ${it.length}")
                it.reversed()
              }.let {
                println("it: $it")
              }
            }

            fun main() = functionsScopeLet()
          

Scope Function: run {…}

Datei: FunctionsScopeRun.kt

            package de.rahn.kotlin.lang

            fun functionsScopeRun() {
              val b = "test".run {
                isEmpty()
              }
              println("b: $b")

              val myString: String? = "Hello World!"
              myString?.run {
                println("Länge myString: $length")
                reversed()
              }.run {
                println("this: $this")
              }

              val zahl = run {
                4711
              }
              println("zahl: $zahl")

              run {
                val zahl = 100
                println("$zahl: $b")
              }
              println("$zahl: $b")
            }

            fun main() = functionsScopeRun()
          

Scope Function: with {…}

Datei: FunctionsScopeWith.kt

            package de.rahn.kotlin.lang

            fun functionsScopeWith() {
              class User {
                var name = ""
                private var age = -1
              }

              val name = with(User()) {
                name = "Frank Rahn"

                println("user = $name")
                name
              }
              println("user = $name")
            }

            fun main() = functionsScopeWith()
          

Scope Function: apply {…}

Datei: FunctionsScopeApply.kt

            package de.rahn.kotlin.lang

            fun functionsScopeApply() {
              class User {
                var name = ""
              }

              val user = User().apply {
                name = "Frank Rahn"
              }
              println("user = ${user.name}")
            }

            fun main() = functionsScopeApply()
          

Scope Function: apply {…}

Datei: User.kt

            package de.rahn.kotlin.lang.classes

            import org.slf4j.LoggerFactory

            class User(name: String) {
              private val LOGGER = LoggerFactory.getLogger(javaClass)

              var name = name.apply { LOGGER.info(this) }
            }

            fun user() {
              val user = User("Frank Rahn").apply {
                name = "Martin Rahn"
              }
              println(user.name)
            }

            fun main() = user()
          

Scope Function: also {…}

Datei: FunctionsScopeAlso.kt

            package de.rahn.kotlin.lang

            fun functionsScopeAlso() {
              class User {
                var name = ""
              }

              val user = User().also {
                it.name = "Frank Rahn"
              }
              println("user = ${user.name}")
            }

            fun main() = functionsScopeAlso()
          

Scope Function: takeIf {…}

Datei: FunctionsScopeTakeIf.kt

            package de.rahn.kotlin.lang

            fun functionsScopeTakeIf() {
              class User(val name: String)

              val user = User("Frank Rahn").takeIf {
                it.name.length == 7
              }
              println("user = $user")
            }

            fun main() = functionsScopeTakeIf()
          

Scope Function: takeIf {…}

Datei: FunctionsScopeTakeUnless.kt

            package de.rahn.kotlin.lang

            fun functionsScopeTakeIf() {
              class User(val name: String)

              val user = User("Frank Rahn").takeIf {
                it.name.length == 7
              }
              println("user = $user")
            }

            fun main() = functionsScopeTakeIf()
          

Vererbung und Interfaces

Objektorientierte Programmierung

Vererbung

Die Klasse Hund soll ein Säugetier sein

Datei: Hund.kt, Saeugetier.kt

            package de.rahn.kotlin.lang.classes

            class Saeugetier(val art: String = "Mammalia") {
                val saeugtNachwuchs: Boolean
                    get() = true
            }

            class Hund(val art: String = "Canidae")
          

Die Klasse Hund soll ein Säugetier sein

Datei: Hund.kt, Saeugetier.kt

            package de.rahn.kotlin.lang.classes

            open class Saeugetier(val art: String = "Mammalia") {
                val saeugtNachwuchs: Boolean
                    get() = true
            }

            class Hund(val art: String = "Canidae")
          

Die Klasse Hund ist ein Säugetier

Datei: Hund.kt, Saeugetier.kt

            package de.rahn.kotlin.lang.classes

            open class Saeugetier(val art: String = "Mammalia") {
                val saeugtNachwuchs: Boolean
                    get() = true
            }

            class Hund(art: String = "Canidae") : Saeugetier(art)
          

Ein Säugetier ist ein Wirbeltier bzw. Chordatier

Datei: Hund.kt, Saeugetier.kt, Wirbeltier.kt, Chordatier.kt

            package de.rahn.kotlin.lang.classes

            abstract class Chordatier(val art: String = "Chordata") {
                val hatHerz: Boolean
                    get() = true
            }

            open class Wirbeltier(art: String = "Vertebrata")
                : Chordatier(art) {
                val hatWirbelsaeule: Boolean
                    get() = true
            }

            open class Saeugetier(art: String = "Mammalia")
                : Wirbeltier(art) {
                val saeugtNachwuchs: Boolean
                    get() = true
            }

            class Hund(art: String = "Canidae") : Saeugetier(art)
          

Überschreiben und abstrakte Member Funktion

Datei: Hund.kt, Saeugetier.kt, Wirbeltier.kt, Chordatier.kt

            package de.rahn.kotlin.lang.classes

            abstract class Chordatier(val art: String = "Chordata") {
                val hatHerz: Boolean
                    get() = true

                open fun sterben() {
                    println("Röchel... Tot")
                }

                abstract fun essen()
            }

            open class Wirbeltier(art: String = "Vertebrata")
                : Chordatier(art) {
                val hatWirbelsaeule: Boolean
                    get() = true

                override fun essen() {
                    TODO("Not yet implemented")
                }
            }

            open class Saeugetier(art: String = "Mammalia")
                : Wirbeltier(art) {
                val saeugtNachwuchs: Boolean
                    get() = true
            }

            class Hund(art: String = "Canidae") : Saeugetier(art) {
                override fun sterben() {
                    println("Jaulen... Tot")
                }
            }
          

Interfaces

Definition

Datei: Essen.kt, Sterben.kt

            package de.rahn.kotlin.lang.classes

            interface Essen {
                fun essen()
            }

            interface Sterben {
                fun sterben() {
                    println("Röchel... Tot")
                }
            }
          

Implementierung


            package de.rahn.kotlin.lang.classes

            abstract class Chordatier(val art: String = "Chordata")
                : Sterben, Essen {
                val hatHerz: Boolean
                    get() = true
            }

            open class Wirbeltier(art: String = "Vertebrata")
                : Chordatier(art) {
                val hatWirbelsaeule: Boolean
                    get() = true

                override fun essen() {
                    TODO("Not yet implemented")
                }
            }

            class Hund(art: String = "Canidae") : Saeugetier(art) {
                override fun sterben() {
                    println("Jaulen... Tot")
                }
            }
          

Vererbung von Interfaces und
Auflösen von Override Konflikten

Datei: Essen.kt, Sterben.kt, Info.kt

            package de.rahn.kotlin.lang.classes

            interface Info {
                fun infos(): Array<String>
            }

            interface Essen : Info {
                fun essen()

                override fun infos(): Array<String> {
                    return arrayOf("Muss essen")
                }
            }

            interface Sterben : Info {
                fun sterben() {
                    println("Röchel... Tot")
                }

                override fun infos(): Array<String> {
                    return arrayOf("Kann sterben")
                }
            }

            abstract class Chordatier(val art: String = "Chordata")
                : Sterben, Essen {
                val hatHerz: Boolean
                    get() = true

                override fun infos(): Array<String> {
                    return super<Sterben>.infos() +
                            super<Essen>.infos() +
                            "Hat ein Herz"
                }
            }

            open class Wirbeltier(art: String = "Vertebrata")
                : Chordatier(art) {
                val hatWirbelsaeule: Boolean
                    get() = true

                override fun essen() {
                    TODO("Not yet implemented")
                }

                override fun infos(): Array<String> {
                    return super.infos() +
                            "Hat eine Wirbelsäule"
                }
            }

            open class Saeugetier(art: String = "Mammalia")
                : Wirbeltier(art) {
                val saeugtNachwuchs: Boolean
                    get() = true

                override fun infos(): Array<String> {
                    return super.infos() +
                            "Säugt sein Nachwuchs"
                }
            }
          

Die Infos für die Klasse Hund ausgeben

Datei: Tier.kt

            package de.rahn.kotlin.lang.classes

            fun tier() {
                val hund = Hund()

                println("Informationen über das Tier Hund:")
                hund.infos().forEach {
                    info -> println("- $info")
                }
            }

            fun main() = tier()
          

Die Ausgabe

Informationen über das Tier Hund:
- Kann sterben
- Muss essen
- Hat ein Herz
- Hat eine Wirbelsäule
- Säugt sein Nachwuchs

Objekte

Objektorientierte Programmierung

Grundlagen Objekte

Wir brauchen gerade nur ein Objekt

Datei: ObjectsAdHoc.kt

            package de.rahn.kotlin.lang

            fun objectAdHoc1(): Any {
              val i = object {
                val name = "Rahn"
                val firstName = "Frank"
              }

              println("${i.firstName} ${i.name}")

              return i
            }

            fun objectAdHoc() {
              val a = objectAdHoc1()
              println(a)
            }

            fun main() = objectAdHoc()
          

Wir brauchen gerade nur ein Objekt

Datei: ObjectsAdHoc.kt

            package de.rahn.kotlin.lang

            fun objectAdHoc1(): Any {
              val i = object {
                val name = "Rahn"
                val firstName = "Frank"

                fun print() {
                  println("$firstName $name")
                }
              }

              println("${i.firstName} ${i.name}")
              i.print()

              return i
            }

            fun objectAdHoc() {
              val a = objectAdHoc1()
              println(a)
            }

            fun main() = objectAdHoc()
          

In einer Klasse viel sinnvoller

Datei: Person5.kt

            package de.rahn.kotlin.lang.classes

            class Person5(val name: String) {
              private fun internPerson() = object {
                val name = this@Person5.name
              }

              fun name(): String {
                return internPerson().name
              }
            }

            fun person5() {
              val p = Person5("Frank Rahn")

              println("Person=${p.name()}")
            }

            fun main() = person5()
          

Objekte von Interfaces oder Klassen

Datei: ObjectsInterface.kt

            package de.rahn.kotlin.lang

            interface Named {
              fun name(): String
            }

            fun newNamed(name: String): Named {
              return object : Named {
                override fun name(): String {
                  return name
                }
              }
            }

            fun objectsInterface() {
              val named = newNamed("Frank Rahn")
              println(named.name())
            }

            fun main() = objectsInterface()
          

Singleton

Datei: ObjectsSingleton.kt

            package de.rahn.kotlin.lang

            object ConfigurationSingleton {
              private val start = System.currentTimeMillis()
              val logLevel = "debug"

              fun duration(): Long {
                return System.currentTimeMillis() - start
              }
            }

            fun objectsSingleton() {
              println(ConfigurationSingleton.duration())
              println(ConfigurationSingleton.logLevel)
              Thread.sleep(1000)
              println(ConfigurationSingleton.duration())
            }

            fun main() = objectsSingleton()
          

Companion Object

Companion Object

Datei: ObjectsCompanionObject.kt

            package de.rahn.kotlin.lang

            class ObjectsCompanionObject {
              companion object {}
            }

            fun objectsCompanionObject() {
              println(ObjectsCompanionObject.Companion)
            }

            fun main() = objectsCompanionObject()
          

Companion Object

Datei: ObjectsCompanionObject.kt

            package de.rahn.kotlin.lang

            class ObjectsCompanionObject {
              companion object {}
            }

            fun objectsCompanionObject() {
              println(ObjectsCompanionObject)
              println(ObjectsCompanionObject.Companion)
            }

            fun main() = objectsCompanionObject()
          

Companion Object

Datei: ObjectsCompanionObject.kt

            package de.rahn.kotlin.lang

            class ObjectsCompanionObject {
              companion object Factory {}
            }

            fun objectsCompanionObject() {
              println(ObjectsCompanionObject)
              println(ObjectsCompanionObject.Factory)
            }

            fun main() = objectsCompanionObject()
          

Companion Object

Datei: ObjectsCompanionObject.kt

            package de.rahn.kotlin.lang

            class ObjectsCompanionObject {
              companion object Factory {
                fun create(): ObjectsCompanionObject = ObjectsCompanionObject()
              }
            }

            fun objectsCompanionObject() {
              println(ObjectsCompanionObject)
              println(ObjectsCompanionObject.Factory)

              val instance = ObjectsCompanionObject.Factory.create()
              println(instance)
            }

            fun main() = objectsCompanionObject()
          

Companion Object

Datei: ObjectsCompanionObject.kt

            package de.rahn.kotlin.lang

            class ObjectsCompanionObject {
              companion object Factory {
                fun create(): ObjectsCompanionObject = ObjectsCompanionObject()
              }
            }

            fun objectsCompanionObject() {
              println(ObjectsCompanionObject)
              println(ObjectsCompanionObject.Factory)

              val instance = ObjectsCompanionObject.create()
              println(instance)
            }

            fun main() = objectsCompanionObject()
          

Companion Object

Datei: ObjectsCompanionObject.kt

            package de.rahn.kotlin.lang

            interface Factory<T> {
              fun create(): T
            }

            class ObjectsCompanionObject {
              companion object : Factory<ObjectsCompanionObject> {
                override fun create(): ObjectsCompanionObject = ObjectsCompanionObject()
              }
            }

            fun objectsCompanionObject() {
              val obj: Factory<ObjectsCompanionObject> = ObjectsCompanionObject
              println(obj)
            }

            fun main() = objectsCompanionObject()
          

Companion Object

Datei: ObjectsCompanionObject.kt

            package de.rahn.kotlin.lang

            interface Factory<T> {
              fun create(): T
            }

            class ObjectsCompanionObject {
              companion object : Factory<ObjectsCompanionObject> {
                override fun create(): ObjectsCompanionObject = ObjectsCompanionObject()
              }

              object Constants {
                val defaultInstanz = create()
              }
            }

            fun objectsCompanionObject() {
              val obj: Factory<ObjectsCompanionObject> = ObjectsCompanionObject
              println(obj)

              println(ObjectsCompanionObject.Constants.defaultInstanz)
            }

            fun main() = objectsCompanionObject()
          

Baustelle …!

Klassen

  • Aliasnamen für Typen typealias
  • Varianten für innere Klassen
  • Delegation
  • Umgang mit lazy
  • Inline Getter und Setter
  • Enums und when
  • Basistypen oder einfache Typen
  • Strings und reguläre Ausdrücke
  • Nullbare Typen und angepasste Syntax
  • Collections und Arrays
  • Iterationen
  • Exceptionhandling

Weitere Konzepte

  • Funktionstypen
    • Coroutines (Asynchrone Programmierung)
    • Operator Overloading
  • DSLs mit Kotlin
  • Interoperabilität mit Java

Fortgeschrittene Konzepte

  • Überladen von Operatoren
  • Testbarkeit?
  • Kotlin Lambdas mit Receiver
  • Generics in Kotlin
    • Unterschiedliche Fälle von Varianz
    • Projektionen
    • Reified Generics (Inline Funktions)
  • Annotationen
  • Reflection

Vielen Dank für Ihre Aufmerksamkeit!

Lizenzen

Creative Commons Lizenzvertrag (CC BY-ND 4.0)

Dieses Werk ist unter der Creative-Commons-Lizenz vom Typ Namensnennung - Keine Bearbeitungen 4.0 International lizenziert.

Um eine Kopie dieser Lizenz einzusehen, besuchen Sie https://creativecommons.org/licenses/by-nd/4.0/deed.de oder schreiben Sie einen Brief an Creative Commons, 444 Castro Street, Suite 900, Mountain View, California, 94041, USA.

Backlog