Kotlin Cheatsheet¶
Kotlin - Moderne Programmiersprache für Android und Beyond
Kotlin ist eine moderne, präzise und sichere Programmiersprache, die auf dem JVM läuft und vollständig mit Java interoperabel ist. Es ist Googles bevorzugte Sprache für Android-Entwicklung und wird auch für Server-Seite, Web und Multiplattform-Entwicklung verwendet. < p>
Inhaltsverzeichnis¶
- [Installation](#installation
- Basic Syntax
- Variablen und Konstanten
- Datentypen
- [Control Flow](#control-flow_
- Funktionen
- Klassen und Objekte
- (#inheritance_)
- (#interfaces)
- Datenklassen
- (#sealed-classes_)
- (Generika)(#generics)
- Kollektionen
- [Null Safety](LINK_13__
- Erweiterungsfunktionen
- (#higher-order-functions)
- [Coroutines](LINK_16__
- [Android Development](#android-development
- Beste Praktiken
Installation¶
Android Studio Setup¶
# Download Android Studio from developer.android.com
# Kotlin is included by default
# Create new Kotlin project
# File > New > New Project > Select Kotlin
# Verify Kotlin version in build.gradle
kotlin_version = '1.8.20'
```_
### IntelliJ IDEA Setup
```bash
# Download IntelliJ IDEA
# Kotlin plugin is bundled
# Create new Kotlin project
# File > New > Project > Kotlin
# Command line compilation
kotlinc hello.kt -include-runtime -d hello.jar
java -jar hello.jar
```_
### Konfiguration der Befehlszeile
```bash
# Install Kotlin compiler
# macOS with Homebrew
brew install kotlin
# Linux/Windows - download from kotlinlang.org
# Extract and add to PATH
# Verify installation
kotlin -version
kotlinc -version
# REPL (Read-Eval-Print Loop)
kotlinc-jvm
# Compile and run
kotlinc hello.kt -include-runtime -d hello.jar
java -jar hello.jar
# Direct execution
kotlin hello.kt
```_
## Grundprinzip
### Hallo Welt
```kotlin
// Simple main function
fun main() {
println("Hello, World!")
}
// Main with arguments
fun main(args: Array<String>) {
println("Hello, ${args.getOrNull(0) ?: "World"}!")
}
// Top-level function
fun greet(name: String) {
println("Hello, $name!")
}
fun main() {
greet("Kotlin")
}
// Comments
// This is a single-line comment
/*
* This is a multi-line comment
* that spans multiple lines
*/
/**
* This is a documentation comment
* @param name The name to greet
* @return A greeting string
*/
fun createGreeting(name: String): String {
return "Hello, $name!"
}
```_
### Paket und Importe
```kotlin
// Package declaration
package com.example.myapp
// Imports
import kotlin.math.*
import java.util.Date
import android.content.Context
import com.example.utils.Helper as UtilHelper
// Import all from package
import kotlin.collections.*
// Import specific function
import kotlin.math.sqrt
class MyClass {
fun useImports() {
val result = sqrt(16.0)
val date = Date()
val helper = UtilHelper()
}
}
```_
## Variablen und Konstanten
### Variable Erklärung
```kotlin
// Mutable variables (var)
var name = "John" // Type inferred as String
var age: Int = 25 // Explicit type
var height = 5.9 // Type inferred as Double
// Immutable variables (val)
val pi = 3.14159 // Type inferred as Double
val maxUsers: Int = 100 // Explicit type
val appName = "MyApp" // Type inferred as String
// Late initialization
lateinit var database: Database
val lazyValue: String by lazy {
"Computed only when accessed"
}
// Nullable variables
var nullableName: String? = null
var nonNullName: String = "John"
// Multiple variable declaration
val (x, y, z) = Triple(1, 2, 3)
val (first, second) = Pair("Hello", "World")
```_
### Typ Inference und Explicit Types
```kotlin
// Type inference
val number = 42 // Int
val decimal = 3.14 // Double
val text = "Hello" // String
val flag = true // Boolean
// Explicit types
val explicitInt: Int = 42
val explicitDouble: Double = 3.14
val explicitString: String = "Hello"
val explicitBoolean: Boolean = true
// Collections with type inference
val numbers = listOf(1, 2, 3, 4, 5) // List<Int>
val names = mutableListOf("Alice", "Bob") // MutableList<String>
val ages = mapOf("Alice" to 30, "Bob" to 25) // Map<String, Int>
// Explicit collection types
val explicitList: List<String> = listOf("a", "b", "c")
val explicitMap: Map<String, Int> = mapOf("key" to 1)
```_
## Datentypen
### Grundtypen
```kotlin
// Numbers
val byte: Byte = 127
val short: Short = 32767
val int: Int = 2147483647
val long: Long = 9223372036854775807L
val float: Float = 3.14f
val double: Double = 3.141592653589793
// Characters and Strings
val char: Char = 'A'
val string: String = "Hello, Kotlin!"
// Booleans
val isTrue: Boolean = true
val isFalse: Boolean = false
// Arrays
val intArray: IntArray = intArrayOf(1, 2, 3, 4, 5)
val stringArray: Array<String> = arrayOf("a", "b", "c")
val nullableArray: Array<String?> = arrayOfNulls(5)
// Type conversion
val intValue = 42
val longValue = intValue.toLong()
val doubleValue = intValue.toDouble()
val stringValue = intValue.toString()
// Number literals
val binary = 0b1010 // Binary
val hex = 0xFF // Hexadecimal
val scientific = 1.23e10 // Scientific notation
```_
### String Operations
```kotlin
// String templates
val name = "Alice"
val age = 30
val message = "My name is $name and I'm $age years old"
val calculation = "2 + 3 = ${2 + 3}"
// Multi-line strings
val poem = """
Roses are red,
Violets are blue,
Kotlin is awesome,
And so are you!
""".trimIndent()
// Raw strings
val regex = """[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}"""
// String operations
val text = "Hello, Kotlin!"
println(text.length) // 14
println(text.uppercase()) // HELLO, KOTLIN!
println(text.lowercase()) // hello, kotlin!
println(text.substring(0, 5)) // Hello
println(text.contains("Kotlin")) // true
println(text.startsWith("Hello")) // true
println(text.endsWith("!")) // true
println(text.replace("Kotlin", "World")) // Hello, World!
// String comparison
val str1 = "hello"
val str2 = "HELLO"
println(str1 == str2) // false
println(str1.equals(str2, ignoreCase = true)) // true
```_
### Sammlungen Überblick
```kotlin
// Lists
val readOnlyList = listOf("apple", "banana", "cherry")
val mutableList = mutableListOf("apple", "banana")
mutableList.add("cherry")
// Sets
val readOnlySet = setOf(1, 2, 3, 3, 4) // {1, 2, 3, 4}
val mutableSet = mutableSetOf(1, 2, 3)
mutableSet.add(4)
// Maps
val readOnlyMap = mapOf("a" to 1, "b" to 2, "c" to 3)
val mutableMap = mutableMapOf("a" to 1, "b" to 2)
mutableMap["c"] = 3
// Ranges
val range1 = 1..10 // 1 to 10 (inclusive)
val range2 = 1 until 10 // 1 to 9 (exclusive)
val range3 = 10 downTo 1 // 10 to 1 (descending)
val range4 = 1..10 step 2 // 1, 3, 5, 7, 9
// Checking membership
println(5 in range1) // true
println('x' in 'a'..'z') // true
```_
## Steuerstrom
### Bedingte Aussagen
```kotlin
// if expression
val max = if (a > b) a else b
// if-else chain
val result = if (score >= 90) {
"A"
} else if (score >= 80) {
"B"
} else if (score >= 70) {
"C"
} else {
"F"
}
// when expression (similar to switch)
val dayOfWeek = when (day) {
1 -> "Monday"
2 -> "Tuesday"
3 -> "Wednesday"
4 -> "Thursday"
5 -> "Friday"
6, 7 -> "Weekend"
else -> "Invalid day"
}
// when with ranges
val grade = when (score) {
in 90..100 -> "A"
in 80..89 -> "B"
in 70..79 -> "C"
in 60..69 -> "D"
else -> "F"
}
// when with type checking
fun describe(obj: Any): String = when (obj) {
1 -> "One"
"Hello" -> "Greeting"
is Long -> "Long"
!is String -> "Not a string"
else -> "Unknown"
}
// when without argument
val temperature = 25
val description = when {
temperature < 0 -> "Freezing"
temperature < 20 -> "Cold"
temperature < 30 -> "Warm"
else -> "Hot"
}
```_
### Loops
```kotlin
// for loop with range
for (i in 1..5) {
println(i)
}
// for loop with until
for (i in 1 until 5) {
println(i) // 1, 2, 3, 4
}
// for loop with step
for (i in 1..10 step 2) {
println(i) // 1, 3, 5, 7, 9
}
// for loop with downTo
for (i in 10 downTo 1 step 2) {
println(i) // 10, 8, 6, 4, 2
}
// for loop with collections
val fruits = listOf("apple", "banana", "cherry")
for (fruit in fruits) {
println(fruit)
}
// for loop with indices
for (i in fruits.indices) {
println("$i: ${fruits[i]}")
}
// for loop with withIndex
for ((index, value) in fruits.withIndex()) {
println("$index: $value")
}
// while loop
var count = 0
while (count < 5) {
println("Count: $count")
count++
}
// do-while loop
var number = 0
do {
println("Number: $number")
number++
} while (number < 3)
// Loop control
for (i in 1..10) {
if (i == 3) continue // Skip iteration
if (i == 8) break // Exit loop
println(i)
}
// Labeled breaks and continues
outer@ for (i in 1..3) {
inner@ for (j in 1..3) {
if (i == 2 && j == 2) break@outer
println("$i, $j")
}
}
```_
## Funktionen
### Grundlegende Funktionen
```kotlin
// Simple function
fun greet() {
println("Hello!")
}
// Function with parameters
fun greet(name: String) {
println("Hello, $name!")
}
// Function with return type
fun add(a: Int, b: Int): Int {
return a + b
}
// Single-expression function
fun multiply(a: Int, b: Int): Int = a * b
// Function with default parameters
fun greet(name: String, greeting: String = "Hello") {
println("$greeting, $name!")
}
// Function with named arguments
fun createUser(name: String, age: Int, email: String) {
// Implementation
}
// Calling with named arguments
createUser(name = "Alice", email = "alice@example.com", age = 30)
// Vararg parameters
fun sum(vararg numbers: Int): Int {
return numbers.sum()
}
val result = sum(1, 2, 3, 4, 5)
// Spreading arrays
val array = intArrayOf(1, 2, 3)
val total = sum(*array)
```_
### Funktionstypen und höherwertige Funktionen
```kotlin
// Function type
val operation: (Int, Int) -> Int = { a, b -> a + b }
// Higher-order function
fun calculate(a: Int, b: Int, operation: (Int, Int) -> Int): Int {
return operation(a, b)
}
val result = calculate(5, 3) { x, y -> x * y }
// Function returning function
fun getOperation(type: String): (Int, Int) -> Int {
return when (type) {
"add" -> { a, b -> a + b }
"multiply" -> { a, b -> a * b }
else -> { a, b -> 0 }
}
}
val addFunction = getOperation("add")
val sum = addFunction(5, 3)
// Lambda expressions
val numbers = listOf(1, 2, 3, 4, 5)
val doubled = numbers.map { it * 2 }
val evens = numbers.filter { it % 2 == 0 }
val sum = numbers.reduce { acc, n -> acc + n }
// Lambda with multiple parameters
val pairs = listOf(Pair(1, 2), Pair(3, 4), Pair(5, 6))
val sums = pairs.map { (first, second) -> first + second }
// Trailing lambda syntax
numbers.forEach { number ->
println(number)
}
// it parameter (single parameter lambda)
numbers.forEach {
println(it)
}
```_
### Inline Funktionen
```kotlin
// Inline function
inline fun measureTime(block: () -> Unit): Long {
val start = System.currentTimeMillis()
block()
val end = System.currentTimeMillis()
return end - start
}
// Usage
val time = measureTime {
// Some operation
Thread.sleep(1000)
}
// noinline parameter
inline fun processData(
data: List<String>,
noinline logger: (String) -> Unit,
processor: (String) -> String
) {
data.forEach { item ->
logger("Processing: $item")
processor(item)
}
}
// crossinline parameter
inline fun runAsync(crossinline block: () -> Unit) {
Thread {
block()
}.start()
}
```_
## Klassen und Objekte
### Grundklassen
```kotlin
// Simple class
class Person {
var name: String = ""
var age: Int = 0
fun introduce() {
println("Hi, I'm $name and I'm $age years old")
}
}
// Class with primary constructor
class Person(val name: String, var age: Int) {
fun introduce() {
println("Hi, I'm $name and I'm $age years old")
}
}
// Class with init block
class Person(name: String, age: Int) {
val name: String
var age: Int
init {
this.name = name.uppercase()
this.age = if (age >= 0) age else 0
println("Person created: ${this.name}")
}
}
// Secondary constructors
class Person(val name: String) {
var age: Int = 0
var email: String = ""
constructor(name: String, age: Int) : this(name) {
this.age = age
}
constructor(name: String, age: Int, email: String) : this(name, age) {
this.email = email
}
}
// Usage
val person1 = Person("Alice")
val person2 = Person("Bob", 30)
val person3 = Person("Charlie", 25, "charlie@example.com")
```_
### Eigenschaften
```kotlin
class Rectangle(val width: Double, val height: Double) {
// Computed property
val area: Double
get() = width * height
// Property with custom getter and setter
var isSquare: Boolean
get() = width == height
set(value) {
if (value) {
// Make it a square by setting height to width
// Note: This is just an example, height is val so this won't work
println("Cannot make rectangle a square - height is immutable")
}
}
// Property with backing field
var color: String = "white"
set(value) {
field = value.lowercase()
}
// Late-initialized property
lateinit var description: String
fun initializeDescription() {
description = "A $color rectangle with area $area"
}
}
// Property delegation
class User {
var name: String by Delegates.observable("") { prop, old, new ->
println("$old -> $new")
}
val lazyValue: String by lazy {
println("Computed!")
"Hello"
}
}
```_
### Sichtbarkeit Modifier
```kotlin
// Visibility modifiers
class Example {
private val privateProperty = "Only visible within this class"
protected val protectedProperty = "Visible in this class and subclasses"
internal val internalProperty = "Visible within the same module"
public val publicProperty = "Visible everywhere" // public is default
private fun privateFunction() { }
protected fun protectedFunction() { }
internal fun internalFunction() { }
fun publicFunction() { } // public is default
}
// Top-level declarations
private fun topLevelPrivate() { } // Visible within the same file
internal fun topLevelInternal() { } // Visible within the same module
fun topLevelPublic() { } // Visible everywhere
```_
### Objekterklärungen und Ausdrücke
```kotlin
// Object declaration (Singleton)
object DatabaseManager {
fun connect() {
println("Connecting to database...")
}
fun disconnect() {
println("Disconnecting from database...")
}
}
// Usage
DatabaseManager.connect()
// Object expression (Anonymous object)
val clickListener = object : View.OnClickListener {
override fun onClick(v: View?) {
println("Button clicked!")
}
}
// Object expression with multiple interfaces
val handler = object : Runnable, Serializable {
override fun run() {
println("Running...")
}
}
// Companion object
class MyClass {
companion object {
const val CONSTANT = "Hello"
fun create(): MyClass {
return MyClass()
}
}
}
// Usage
val instance = MyClass.create()
println(MyClass.CONSTANT)
```_
## Erbschaft
### Grund Erbe
```kotlin
// Base class (open for inheritance)
open class Animal(val name: String) {
open fun makeSound() {
println("$name makes a sound")
}
open val species: String = "Unknown"
}
// Derived class
class Dog(name: String) : Animal(name) {
override fun makeSound() {
println("$name barks")
}
override val species: String = "Canis lupus"
fun fetch() {
println("$name fetches the ball")
}
}
class Cat(name: String, val breed: String) : Animal(name) {
override fun makeSound() {
println("$name meows")
}
override val species: String = "Felis catus"
fun purr() {
println("$name purrs")
}
}
// Usage
val dog = Dog("Buddy")
val cat = Cat("Whiskers", "Persian")
dog.makeSound() // Buddy barks
cat.makeSound() // Whiskers meows
```_
### Abstrakte Klassen
```kotlin
// Abstract class
abstract class Shape {
abstract val area: Double
abstract val perimeter: Double
abstract fun draw()
// Concrete method
fun describe() {
println("This shape has area $area and perimeter $perimeter")
}
}
class Circle(val radius: Double) : Shape() {
override val area: Double
get() = Math.PI * radius * radius
override val perimeter: Double
get() = 2 * Math.PI * radius
override fun draw() {
println("Drawing a circle with radius $radius")
}
}
class Rectangle(val width: Double, val height: Double) : Shape() {
override val area: Double
get() = width * height
override val perimeter: Double
get() = 2 * (width + height)
override fun draw() {
println("Drawing a rectangle ${width}x${height}")
}
}
```_
### Calling Superclass Implementierung
```kotlin
open class Vehicle(val brand: String) {
open fun start() {
println("$brand vehicle is starting...")
}
open fun stop() {
println("$brand vehicle is stopping...")
}
}
class Car(brand: String, val model: String) : Vehicle(brand) {
override fun start() {
super.start() // Call superclass implementation
println("$brand $model engine is running")
}
override fun stop() {
println("$brand $model is parking")
super.stop() // Call superclass implementation
}
}
// Usage
val car = Car("Toyota", "Camry")
car.start()
// Output:
// Toyota vehicle is starting...
// Toyota Camry engine is running
```_
## Schnittstellen
### Grundlegende Schnittstellen
```kotlin
// Interface definition
interface Drawable {
fun draw()
fun getArea(): Double
}
interface Clickable {
fun click()
fun showTooltip() = println("Tooltip") // Default implementation
}
// Implementing interfaces
class Button : Drawable, Clickable {
override fun draw() {
println("Drawing a button")
}
override fun getArea(): Double {
return 100.0 // Example area
}
override fun click() {
println("Button clicked!")
}
// showTooltip() is inherited from Clickable with default implementation
}
// Interface with properties
interface Named {
val name: String
val displayName: String
get() = name.uppercase() // Property with default getter
}
class User(override val name: String) : Named {
// displayName is automatically available
}
```_
### Schnittstellenkonflikte
```kotlin
interface A {
fun foo() {
println("A")
}
fun bar()
}
interface B {
fun foo() {
println("B")
}
fun bar() {
println("bar from B")
}
}
class C : A, B {
override fun foo() {
super<A>.foo() // Call A's implementation
super<B>.foo() // Call B's implementation
}
override fun bar() {
super<B>.bar() // Call B's implementation
}
}
```_
### Funktionsschnittstellen (SAM)
```kotlin
// Functional interface
fun interface StringProcessor {
fun process(input: String): String
}
// Usage with lambda
val processor = StringProcessor { input ->
input.uppercase()
}
// Or as a function parameter
fun processText(text: String, processor: StringProcessor): String {
return processor.process(text)
}
val result = processText("hello") { it.uppercase() }
// Built-in functional interfaces
val runnable = Runnable {
println("Running...")
}
val comparator = Comparator<String> { a, b ->
a.length.compareTo(b.length)
}
```_
## Datenklassen
### Basisdatenklassen
```kotlin
// Data class
data class User(val name: String, val age: Int, val email: String)
// Automatically generated methods:
// - equals() and hashCode()
// - toString()
// - copy()
// - componentN() functions for destructuring
val user1 = User("Alice", 30, "alice@example.com")
val user2 = User("Alice", 30, "alice@example.com")
println(user1 == user2) // true (structural equality)
println(user1) // User(name=Alice, age=30, email=alice@example.com)
// Copy with modifications
val user3 = user1.copy(age = 31)
println(user3) // User(name=Alice, age=31, email=alice@example.com)
// Destructuring
val (name, age, email) = user1
println("Name: $name, Age: $age, Email: $email")
```_
### Datenklasse mit benutzerdefiniertem Verhalten
```kotlin
data class Point(val x: Double, val y: Double) {
// Additional methods
fun distanceFromOrigin(): Double {
return kotlin.math.sqrt(x * x + y * y)
}
operator fun plus(other: Point): Point {
return Point(x + other.x, y + other.y)
}
}
val point1 = Point(3.0, 4.0)
val point2 = Point(1.0, 2.0)
println(point1.distanceFromOrigin()) // 5.0
val sum = point1 + point2
println(sum) // Point(x=4.0, y=6.0)
// Data class with validation
data class Email(val address: String) {
init {
require(address.contains("@")) { "Invalid email address" }
}
}
// Data class with computed properties
data class Rectangle(val width: Double, val height: Double) {
val area: Double
get() = width * height
val perimeter: Double
get() = 2 * (width + height)
}
```_
### Datenklassenerhebungen
```kotlin
data class Product(val id: Int, val name: String, val price: Double)
val products = listOf(
Product(1, "Laptop", 999.99),
Product(2, "Mouse", 29.99),
Product(3, "Keyboard", 79.99)
)
// Using data classes in collections
val expensiveProducts = products.filter { it.price > 50.0 }
val productNames = products.map { it.name }
val totalPrice = products.sumOf { it.price }
// Grouping
val productsByPriceRange = products.groupBy { product ->
when {
product.price < 50 -> "Cheap"
product.price < 100 -> "Medium"
else -> "Expensive"
}
}
// Finding
val laptop = products.find { it.name == "Laptop" }
val hasExpensiveItem = products.any { it.price > 500 }
```_
## Versiegelte Klassen
### Grundgesiegelte Klassen
```kotlin
// Sealed class for representing states
sealed class Result<out T> {
data class Success<T>(val data: T) : Result<T>()
data class Error(val exception: Throwable) : Result<Nothing>()
object Loading : Result<Nothing>()
}
// Usage with when expression
fun handleResult(result: Result<String>) {
when (result) {
is Result.Success -> println("Data: ${result.data}")
is Result.Error -> println("Error: ${result.exception.message}")
is Result.Loading -> println("Loading...")
// No else clause needed - compiler knows all cases are covered
}
}
// Example usage
val successResult = Result.Success("Hello, World!")
val errorResult = Result.Error(Exception("Network error"))
val loadingResult = Result.Loading
handleResult(successResult)
handleResult(errorResult)
handleResult(loadingResult)
```_
### Versiegelte Klassen für Navigation
```kotlin
sealed class Screen(val route: String) {
object Home : Screen("home")
object Profile : Screen("profile")
data class UserDetail(val userId: String) : Screen("user/$userId")
data class ProductDetail(val productId: String) : Screen("product/$productId")
}
fun navigate(screen: Screen) {
when (screen) {
is Screen.Home -> println("Navigating to home")
is Screen.Profile -> println("Navigating to profile")
is Screen.UserDetail -> println("Navigating to user ${screen.userId}")
is Screen.ProductDetail -> println("Navigating to product ${screen.productId}")
}
}
// Usage
navigate(Screen.Home)
navigate(Screen.UserDetail("123"))
navigate(Screen.ProductDetail("abc"))
```_
### Versiegelte Schnittstellen
```kotlin
sealed interface NetworkResult
data class Success(val data: String) : NetworkResult
data class Error(val code: Int, val message: String) : NetworkResult
object Loading : NetworkResult
fun processNetworkResult(result: NetworkResult) {
when (result) {
is Success -> println("Success: ${result.data}")
is Error -> println("Error ${result.code}: ${result.message}")
is Loading -> println("Loading...")
}
}
```_
## Generics
### Basic Generics
```kotlin
// Generic class
class Box<T>(val value: T) {
fun get(): T = value
fun <U> transform(transformer: (T) -> U): Box<U> {
return Box(transformer(value))
}
}
val intBox = Box(42)
val stringBox = Box("Hello")
val doubledBox = intBox.transform { it * 2 }
val upperBox = stringBox.transform { it.uppercase() }
// Generic function
fun <T> swap(a: T, b: T): Pair<T, T> {
return Pair(b, a)
}
val swapped = swap("hello", "world")
val swappedNumbers = swap(1, 2)
// Multiple type parameters
class Pair<A, B>(val first: A, val second: B) {
fun <C> mapFirst(transform: (A) -> C): Pair<C, B> {
return Pair(transform(first), second)
}
fun <C> mapSecond(transform: (B) -> C): Pair<A, C> {
return Pair(first, transform(second))
}
}
```_
### Typ Constraints
```kotlin
// Upper bound constraint
fun <T : Number> sum(a: T, b: T): Double {
return a.toDouble() + b.toDouble()
}
val intSum = sum(1, 2)
val doubleSum = sum(1.5, 2.5)
// val stringSum = sum("a", "b") // Compilation error
// Multiple constraints
interface Drawable {
fun draw()
}
interface Clickable {
fun click()
}
fun <T> handleUI(element: T) where T : Drawable, T : Clickable {
element.draw()
element.click()
}
// Constraint with class and interface
open class View
interface OnClickListener
fun <T> setupView(view: T) where T : View, T : OnClickListener {
// T must extend View and implement OnClickListener
}
```_
### Variante
```kotlin
// Covariance (out)
interface Producer<out T> {
fun produce(): T
}
class StringProducer : Producer<String> {
override fun produce(): String = "Hello"
}
// Can assign Producer<String> to Producer<Any>
val stringProducer: Producer<String> = StringProducer()
val anyProducer: Producer<Any> = stringProducer
// Contravariance (in)
interface Consumer<in T> {
fun consume(item: T)
}
class AnyConsumer : Consumer<Any> {
override fun consume(item: Any) {
println("Consuming: $item")
}
}
// Can assign Consumer<Any> to Consumer<String>
val anyConsumer: Consumer<Any> = AnyConsumer()
val stringConsumer: Consumer<String> = anyConsumer
// Invariance (default)
class MutableBox<T>(var value: T) {
fun get(): T = value
fun set(value: T) {
this.value = value
}
}
// Star projection
fun printList(list: List<*>) {
for (item in list) {
println(item)
}
}
```_
### Reified Type Parameter
```kotlin
// Reified type parameters (only in inline functions)
inline fun <reified T> isInstance(value: Any): Boolean {
return value is T
}
val result1 = isInstance<String>("hello") // true
val result2 = isInstance<Int>("hello") // false
// Reified with class access
inline fun <reified T> createInstance(): T? {
return try {
T::class.java.getDeclaredConstructor().newInstance()
} catch (e: Exception) {
null
}
}
// Reified with JSON parsing (example)
inline fun <reified T> parseJson(json: String): T {
// Implementation would use T::class.java
TODO("Implementation depends on JSON library")
}
```_
## Sammlungen
### Listen
```kotlin
// Immutable list
val readOnlyList = listOf("apple", "banana", "cherry")
val emptyList = emptyList<String>()
// Mutable list
val mutableList = mutableListOf("apple", "banana")
mutableList.add("cherry")
mutableList.addAll(listOf("date", "elderberry"))
mutableList.remove("banana")
mutableList.removeAt(0)
// List operations
val numbers = listOf(1, 2, 3, 4, 5)
val doubled = numbers.map { it * 2 }
val evens = numbers.filter { it % 2 == 0 }
val sum = numbers.sum()
val max = numbers.maxOrNull()
val sorted = numbers.sortedDescending()
// List access
val first = numbers.first()
val last = numbers.last()
val secondElement = numbers[1]
val safeAccess = numbers.getOrNull(10) // null if index out of bounds
// List slicing
val sublist = numbers.subList(1, 4) // [2, 3, 4]
val take = numbers.take(3) // [1, 2, 3]
val drop = numbers.drop(2) // [3, 4, 5]
// List transformation
val fruits = listOf("apple", "banana", "cherry")
val lengths = fruits.map { it.length }
val uppercase = fruits.map { it.uppercase() }
val indexed = fruits.mapIndexed { index, fruit -> "$index: $fruit" }
// Flattening
val nestedLists = listOf(listOf(1, 2), listOf(3, 4), listOf(5, 6))
val flattened = nestedLists.flatten() // [1, 2, 3, 4, 5, 6]
val words = listOf("hello", "world")
val characters = words.flatMap { it.toList() } // [h, e, l, l, o, w, o, r, l, d]
```_
### Sets
```kotlin
// Immutable set
val readOnlySet = setOf(1, 2, 3, 3, 4) // {1, 2, 3, 4}
val emptySet = emptySet<Int>()
// Mutable set
val mutableSet = mutableSetOf(1, 2, 3)
mutableSet.add(4)
mutableSet.addAll(setOf(5, 6))
mutableSet.remove(2)
// Set operations
val set1 = setOf(1, 2, 3, 4)
val set2 = setOf(3, 4, 5, 6)
val union = set1 union set2 // {1, 2, 3, 4, 5, 6}
val intersection = set1 intersect set2 // {3, 4}
val difference = set1 subtract set2 // {1, 2}
// Set membership
val contains = 3 in set1 // true
val containsAll = set1.containsAll(setOf(1, 2)) // true
// Converting between collections
val listToSet = listOf(1, 2, 2, 3).toSet() // {1, 2, 3}
val setToList = setOf(1, 2, 3).toList() // [1, 2, 3]
```_
### Karten
```kotlin
// Immutable map
val readOnlyMap = mapOf("a" to 1, "b" to 2, "c" to 3)
val emptyMap = emptyMap<String, Int>()
// Mutable map
val mutableMap = mutableMapOf("a" to 1, "b" to 2)
mutableMap["c"] = 3
mutableMap.put("d", 4)
mutableMap.putAll(mapOf("e" to 5, "f" to 6))
mutableMap.remove("b")
// Map access
val value = readOnlyMap["a"] // 1 (nullable)
val safeValue = readOnlyMap.getValue("a") // 1 (throws if not found)
val defaultValue = readOnlyMap.getOrDefault("z", 0) // 0
val computedValue = mutableMap.getOrPut("g") { 7 }
// Map operations
val ages = mapOf("Alice" to 30, "Bob" to 25, "Charlie" to 35)
val names = ages.keys
val ageValues = ages.values
val entries = ages.entries
// Map transformation
val upperNames = ages.mapKeys { it.key.uppercase() }
val ageInMonths = ages.mapValues { it.value * 12 }
val filtered = ages.filter { it.value >= 30 }
// Map iteration
for ((name, age) in ages) {
println("$name is $age years old")
}
ages.forEach { (name, age) ->
println("$name: $age")
}
```_
### Operationen
```kotlin
val numbers = listOf(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)
// Filtering
val evens = numbers.filter { it % 2 == 0 }
val odds = numbers.filterNot { it % 2 == 0 }
val nonNulls = listOf(1, null, 2, null, 3).filterNotNull()
// Mapping
val doubled = numbers.map { it * 2 }
val strings = numbers.map { "Number: $it" }
// Reducing
val sum = numbers.reduce { acc, n -> acc + n }
val product = numbers.fold(1) { acc, n -> acc * n }
// Grouping
val words = listOf("apple", "banana", "cherry", "apricot", "blueberry")
val groupedByFirstLetter = words.groupBy { it.first() }
val groupedByLength = words.groupBy { it.length }
// Partitioning
val (evens2, odds2) = numbers.partition { it % 2 == 0 }
// Finding
val firstEven = numbers.find { it % 2 == 0 }
val lastOdd = numbers.findLast { it % 2 == 1 }
// Checking conditions
val allPositive = numbers.all { it > 0 }
val anyEven = numbers.any { it % 2 == 0 }
val noneNegative = numbers.none { it < 0 }
// Sorting
val sorted = numbers.sorted()
val sortedDesc = numbers.sortedDescending()
val sortedByLength = words.sortedBy { it.length }
val sortedByLengthDesc = words.sortedByDescending { it.length }
// Distinct
val duplicates = listOf(1, 2, 2, 3, 3, 3, 4)
val unique = duplicates.distinct()
val uniqueByLength = words.distinctBy { it.length }
// Zipping
val letters = listOf("a", "b", "c")
val zipped = numbers.zip(letters) // [(1, a), (2, b), (3, c)]
val zippedWithTransform = numbers.zip(letters) { num, letter -> "$num$letter" }
```_
## Null Sicherheit
### Nullfähige Typen
```kotlin
// Nullable vs non-nullable types
var nonNullString: String = "Hello"
var nullableString: String? = null
// nonNullString = null // Compilation error
nullableString = "World"
nullableString = null // OK
// Safe call operator
val length = nullableString?.length
val uppercase = nullableString?.uppercase()
// Chaining safe calls
class Person(val name: String?)
class Company(val ceo: Person?)
val company: Company? = Company(Person("John"))
val ceoNameLength = company?.ceo?.name?.length
// Elvis operator
val name = nullableString ?: "Default Name"
val length2 = nullableString?.length ?: 0
// Not-null assertion operator (use with caution)
val definitelyNotNull = nullableString!!
val length3 = nullableString!!.length
// Safe cast
val stringValue: Any = "Hello"
val safeString = stringValue as? String // null if cast fails
val unsafeString = stringValue as String // throws exception if cast fails
```_
### Null Checks
```kotlin
fun processString(str: String?) {
// Explicit null check
if (str != null) {
println(str.length) // Smart cast to non-null
}
// Safe call with let
str?.let { nonNullStr ->
println("Processing: $nonNullStr")
println("Length: ${nonNullStr.length}")
}
// Elvis operator with return
val length = str?.length ?: return
println("String length: $length")
// Elvis operator with throw
val upperCase = str?.uppercase() ?: throw IllegalArgumentException("String cannot be null")
}
// Multiple null checks
fun processPersonInfo(person: Person?) {
person?.let { p ->
p.name?.let { name ->
println("Person name: $name")
}
}
// Or using safe calls
person?.name?.let { name ->
println("Person name: $name")
}
}
```_
### Sammlungen und Null-Sicherheit
```kotlin
// Nullable collections vs collections of nullables
val nullableList: List<String>? = null
val listOfNullables: List<String?> = listOf("hello", null, "world")
val nullableListOfNullables: List<String?>? = null
// Safe operations on nullable collections
nullableList?.forEach { item ->
println(item)
}
val size = nullableList?.size ?: 0
// Filtering out nulls
val nonNullItems = listOfNullables.filterNotNull()
println(nonNullItems) // [hello, world]
// Map with null safety
val lengths = listOfNullables.mapNotNull { it?.length }
println(lengths) // [5, 5]
// Safe indexing
val firstItem = nullableList?.getOrNull(0)
val safeAccess = listOfNullables.getOrNull(10) // null
```_
### Plattformtypen
```kotlin
// When interacting with Java code, types are platform types (T!)
// These can be treated as nullable or non-nullable
// Java method: public String getName() { return name; }
// In Kotlin, this becomes: fun getName(): String!
// You can treat it as nullable
val javaName = javaObject.getName()
val safeName = javaName?.uppercase()
// Or as non-nullable (your responsibility to ensure it's not null)
val definitelyName: String = javaObject.getName()
val upperName = definitelyName.uppercase()
// Best practice: explicitly declare nullability
val explicitlyNullable: String? = javaObject.getName()
val explicitlyNonNull: String = javaObject.getName() ?: ""
```_
## Erweiterungsfunktionen
### Basis-Erweiterungsfunktionen
```kotlin
// Extension function for String
fun String.isPalindrome(): Boolean {
val cleaned = this.lowercase().replace(Regex("[^a-z0-9]"), "")
return cleaned == cleaned.reversed()
}
// Usage
val text = "A man a plan a canal Panama"
println(text.isPalindrome()) // true
// Extension function with parameters
fun String.truncate(maxLength: Int, suffix: String = "..."): String {
return if (this.length <= maxLength) {
this
} else {
this.take(maxLength - suffix.length) + suffix
}
}
val longText = "This is a very long text that needs to be truncated"
println(longText.truncate(20)) // This is a very lo...
// Extension function for collections
fun <T> List<T>.secondOrNull(): T? {
return if (this.size >= 2) this[1] else null
}
val numbers = listOf(1, 2, 3, 4, 5)
println(numbers.secondOrNull()) // 2
val emptyList = emptyList<Int>()
println(emptyList.secondOrNull()) // null
```_
### Erweiterungseigenschaften
```kotlin
// Extension property for String
val String.lastIndex: Int
get() = this.length - 1
val text = "Hello"
println(text.lastIndex) // 4
// Extension property for collections
val <T> List<T>.penultimate: T?
get() = if (this.size >= 2) this[this.size - 2] else null
val fruits = listOf("apple", "banana", "cherry")
println(fruits.penultimate) // banana
// Extension property with backing field (not allowed)
// var String.customProperty: String = "" // Compilation error
// But you can use other mechanisms
private val stringExtras = mutableMapOf<String, String>()
var String.extra: String
get() = stringExtras[this] ?: ""
set(value) {
stringExtras[this] = value
}
```_
### Erweiterungsfunktionen für kundenspezifische Klassen
```kotlin
data class Point(val x: Double, val y: Double)
// Extension function for custom class
fun Point.distanceTo(other: Point): Double {
val dx = this.x - other.x
val dy = this.y - other.y
return kotlin.math.sqrt(dx * dx + dy * dy)
}
// Extension operator
operator fun Point.plus(other: Point): Point {
return Point(this.x + other.x, this.y + other.y)
}
operator fun Point.times(scalar: Double): Point {
return Point(this.x * scalar, this.y * scalar)
}
// Usage
val point1 = Point(1.0, 2.0)
val point2 = Point(4.0, 6.0)
println(point1.distanceTo(point2)) // 5.0
val sum = point1 + point2
val scaled = point1 * 2.0
// Extension function with receiver type parameter
fun <T> T.applyIf(condition: Boolean, block: T.() -> T): T {
return if (condition) this.block() else this
}
val result = "hello"
.applyIf(true) { uppercase() }
.applyIf(false) { reversed() }
println(result) // HELLO
```_
### Scope Funktionen als Erweiterungen
```kotlin
// Custom scope functions
inline fun <T> T.alsoIf(condition: Boolean, block: (T) -> Unit): T {
if (condition) block(this)
return this
}
inline fun <T, R> T.letIf(condition: Boolean, block: (T) -> R): R? {
return if (condition) block(this) else null
}
// Usage
val number = 42
.alsoIf(true) { println("Number is $it") }
.alsoIf(false) { println("This won't print") }
val result = "hello"
.letIf(true) { it.uppercase() }
?.let { "Result: $it" }
// Extension for nullable types
fun <T> T?.ifNotNull(block: (T) -> Unit) {
if (this != null) block(this)
}
val nullableString: String? = "hello"
nullableString.ifNotNull { println("String: $it") }
```_
## Höhere Funktionen
### Funktionstypen
```kotlin
// Function type declarations
val add: (Int, Int) -> Int = { a, b -> a + b }
val greet: (String) -> Unit = { name -> println("Hello, $name!") }
val isEven: (Int) -> Boolean = { it % 2 == 0 }
// Function type with receiver
val stringBuilder: StringBuilder.() -> Unit = {
append("Hello, ")
append("World!")
}
val sb = StringBuilder()
sb.stringBuilder()
println(sb.toString()) // Hello, World!
// Nullable function types
val nullableFunction: ((Int) -> String)? = null
val result = nullableFunction?.invoke(42)
// Function type with multiple parameters
val calculator: (Int, Int, (Int, Int) -> Int) -> Int = { a, b, operation ->
operation(a, b)
}
val sum = calculator(5, 3) { x, y -> x + y }
val product = calculator(5, 3) { x, y -> x * y }
```_
### Beispiele für höhere Funktionen
```kotlin
// Function that takes a function as parameter
fun processNumbers(numbers: List<Int>, processor: (Int) -> Int): List<Int> {
return numbers.map(processor)
}
val numbers = listOf(1, 2, 3, 4, 5)
val doubled = processNumbers(numbers) { it * 2 }
val squared = processNumbers(numbers) { it * it }
// Function that returns a function
fun createMultiplier(factor: Int): (Int) -> Int {
return { number -> number * factor }
}
val doubler = createMultiplier(2)
val tripler = createMultiplier(3)
println(doubler(5)) // 10
println(tripler(5)) // 15
// Function with multiple function parameters
fun combineOperations(
a: Int,
b: Int,
operation1: (Int, Int) -> Int,
operation2: (Int) -> Int
): Int {
val intermediate = operation1(a, b)
return operation2(intermediate)
}
val result = combineOperations(3, 4, { x, y -> x + y }, { it * 2 })
println(result) // 14 (3 + 4 = 7, then 7 * 2 = 14)
```_
### Eingebaute höherwertige Funktionen
```kotlin
val numbers = listOf(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)
// map - transform each element
val doubled = numbers.map { it * 2 }
val strings = numbers.map { "Number: $it" }
// filter - select elements based on condition
val evens = numbers.filter { it % 2 == 0 }
val greaterThanFive = numbers.filter { it > 5 }
// reduce - combine elements into single value
val sum = numbers.reduce { acc, n -> acc + n }
val max = numbers.reduce { acc, n -> if (n > acc) n else acc }
// fold - like reduce but with initial value
val product = numbers.fold(1) { acc, n -> acc * n }
val concatenated = numbers.fold("") { acc, n -> acc + n }
// forEach - perform action on each element
numbers.forEach { println(it) }
// any, all, none - check conditions
val hasEven = numbers.any { it % 2 == 0 }
val allPositive = numbers.all { it > 0 }
val noNegative = numbers.none { it < 0 }
// find - find first element matching condition
val firstEven = numbers.find { it % 2 == 0 }
val firstGreaterThanTen = numbers.find { it > 10 } // null
// partition - split into two lists based on condition
val (evens2, odds) = numbers.partition { it % 2 == 0 }
// groupBy - group elements by key
val words = listOf("apple", "banana", "cherry", "apricot")
val groupedByFirstLetter = words.groupBy { it.first() }
```_
### Anwendungsbereich
```kotlin
// let - execute block and return result
val name: String? = "John"
val result = name?.let { nonNullName ->
"Hello, $nonNullName!"
} ?: "Hello, Guest!"
// run - execute block on object and return result
val message = StringBuilder().run {
append("Hello, ")
append("World!")
toString()
}
// with - execute block on object and return result
val greeting = with(StringBuilder()) {
append("Hello, ")
append("World!")
toString()
}
// apply - execute block on object and return object
val person = Person().apply {
name = "John"
age = 30
}
// also - execute block with object and return object
val numbers2 = mutableListOf(1, 2, 3).also { list ->
println("List size: ${list.size}")
list.add(4)
}
// takeIf - return object if condition is true, null otherwise
val positiveNumber = (-5).takeIf { it > 0 } // null
val evenNumber = 4.takeIf { it % 2 == 0 } // 4
// takeUnless - return object if condition is false, null otherwise
val notZero = 5.takeUnless { it == 0 } // 5
val notEmpty = "".takeUnless { it.isEmpty() } // null
```_
## Coroutinen
### Basic Coroutinen
```kotlin
import kotlinx.coroutines.*
// Basic coroutine
fun main() = runBlocking {
println("Start")
delay(1000) // Non-blocking delay
println("End")
}
// Launch coroutine
fun main() = runBlocking {
launch {
delay(1000)
println("World!")
}
println("Hello,")
}
// Async coroutine
fun main() = runBlocking {
val deferred = async {
delay(1000)
"Hello, World!"
}
println(deferred.await())
}
// Multiple coroutines
fun main() = runBlocking {
val job1 = launch {
repeat(5) { i ->
println("Job1: $i")
delay(500)
}
}
val job2 = launch {
repeat(3) { i ->
println("Job2: $i")
delay(800)
}
}
joinAll(job1, job2)
println("All jobs completed")
}
```_
### Suspendieren Funktionen
```kotlin
// Suspend function
suspend fun fetchUserData(userId: String): User {
delay(1000) // Simulate network call
return User(userId, "John Doe")
}
suspend fun fetchUserPosts(userId: String): List<Post> {
delay(800) // Simulate network call
return listOf(Post("Post 1"), Post("Post 2"))
}
// Using suspend functions
fun main() = runBlocking {
val userId = "123"
// Sequential execution
val user = fetchUserData(userId)
val posts = fetchUserPosts(userId)
println("User: $user, Posts: $posts")
// Concurrent execution
val userDeferred = async { fetchUserData(userId) }
val postsDeferred = async { fetchUserPosts(userId) }
val userResult = userDeferred.await()
val postsResult = postsDeferred.await()
println("User: $userResult, Posts: $postsResult")
}
// Suspend function with error handling
suspend fun fetchDataWithRetry(url: String, maxRetries: Int = 3): String {
repeat(maxRetries) { attempt ->
try {
return performNetworkCall(url)
} catch (e: Exception) {
if (attempt == maxRetries - 1) throw e
delay(1000 * (attempt + 1)) // Exponential backoff
}
}
throw IllegalStateException("Should not reach here")
}
suspend fun performNetworkCall(url: String): String {
delay(500) // Simulate network call
if (Math.random() < 0.7) throw Exception("Network error")
return "Data from $url"
}
```_
### Coroutine Kontexte und Dispatcher
```kotlin
import kotlinx.coroutines.*
fun main() = runBlocking {
// Default dispatcher (optimized for CPU-intensive work)
launch(Dispatchers.Default) {
println("Default: ${Thread.currentThread().name}")
}
// IO dispatcher (optimized for IO operations)
launch(Dispatchers.IO) {
println("IO: ${Thread.currentThread().name}")
}
// Main dispatcher (for UI updates, Android/JavaFX)
// launch(Dispatchers.Main) {
// println("Main: ${Thread.currentThread().name}")
// }
// Unconfined dispatcher
launch(Dispatchers.Unconfined) {
println("Unconfined: ${Thread.currentThread().name}")
}
delay(100)
}
// Custom dispatcher
fun main() = runBlocking {
val customDispatcher = newSingleThreadContext("CustomThread")
launch(customDispatcher) {
println("Custom: ${Thread.currentThread().name}")
}
customDispatcher.close()
}
// Switching contexts
suspend fun processData() {
withContext(Dispatchers.IO) {
// Perform IO operation
println("IO operation on: ${Thread.currentThread().name}")
}
withContext(Dispatchers.Default) {
// Perform CPU-intensive operation
println("CPU operation on: ${Thread.currentThread().name}")
}
}
```_
### Coroutine Stornierung und Timeouts
```kotlin
// Cancellation
fun main() = runBlocking {
val job = launch {
repeat(1000) { i ->
println("Job: I'm sleeping $i ...")
delay(500)
}
}
delay(1300) // Let it run for a bit
println("Cancelling job...")
job.cancel() // Cancel the job
job.join() // Wait for cancellation to complete
println("Job cancelled")
}
// Cooperative cancellation
suspend fun cooperativeTask() {
repeat(1000) { i ->
if (!isActive) return // Check if coroutine is still active
println("Working $i")
// Simulate work without delay
Thread.sleep(100)
}
}
// Timeout
fun main() = runBlocking {
try {
withTimeout(1300) {
repeat(1000) { i ->
println("I'm sleeping $i ...")
delay(500)
}
}
} catch (e: TimeoutCancellationException) {
println("Timed out!")
}
}
// Timeout with null result
fun main() = runBlocking {
val result = withTimeoutOrNull(1300) {
repeat(1000) { i ->
println("I'm sleeping $i ...")
delay(500)
}
"Done"
}
println("Result: $result") // null if timed out
}
```_
### Kanäle und Strömung
```kotlin
import kotlinx.coroutines.channels.*
import kotlinx.coroutines.flow.*
// Channels
fun main() = runBlocking {
val channel = Channel<Int>()
launch {
for (x in 1..5) {
channel.send(x * x)
}
channel.close()
}
for (y in channel) {
println(y)
}
}
// Producer-consumer with channel
fun CoroutineScope.produceSquares(): ReceiveChannel<Int> = produce {
for (x in 1..5) {
send(x * x)
}
}
fun main() = runBlocking {
val squares = produceSquares()
squares.consumeEach { println(it) }
}
// Flow
fun simpleFlow(): Flow<Int> = flow {
for (i in 1..3) {
delay(100)
emit(i)
}
}
fun main() = runBlocking {
simpleFlow().collect { value ->
println(value)
}
}
// Flow transformations
fun main() = runBlocking {
(1..5).asFlow()
.filter { it % 2 == 0 }
.map { it * it }
.collect { println(it) }
}
// Flow with exception handling
fun main() = runBlocking {
flow {
for (i in 1..3) {
println("Emitting $i")
emit(i)
if (i == 2) throw RuntimeException("Error at $i")
}
}
.catch { e -> emit(-1) } // Handle exception
.collect { println("Collected $it") }
}
```_
## Android-Entwicklung
### Aktivitäten Grundlagen
```kotlin
import android.os.Bundle
import androidx.appcompat.app.AppCompatActivity
import androidx.activity.viewModels
class MainActivity : AppCompatActivity() {
private val viewModel: MainViewModel by viewModels()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
setupUI()
observeViewModel()
}
private fun setupUI() {
// UI setup code
}
private fun observeViewModel() {
viewModel.userData.observe(this) { user ->
// Update UI with user data
}
}
override fun onStart() {
super.onStart()
// Activity is becoming visible
}
override fun onResume() {
super.onResume()
// Activity is in foreground
}
override fun onPause() {
super.onPause()
// Activity is partially obscured
}
override fun onStop() {
super.onStop()
// Activity is no longer visible
}
override fun onDestroy() {
super.onDestroy()
// Activity is being destroyed
}
}
```_
### Bindings anzeigen
```kotlin
import android.os.Bundle
import androidx.appcompat.app.AppCompatActivity
import com.example.databinding.ActivityMainBinding
class MainActivity : AppCompatActivity() {
private lateinit var binding: ActivityMainBinding
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityMainBinding.inflate(layoutInflater)
setContentView(binding.root)
setupClickListeners()
}
private fun setupClickListeners() {
binding.submitButton.setOnClickListener {
val text = binding.editText.text.toString()
binding.textView.text = "Hello, $text!"
}
binding.clearButton.setOnClickListener {
binding.editText.text.clear()
binding.textView.text = ""
}
}
}
```_
### ViewModel und LiveData
```kotlin
import androidx.lifecycle.ViewModel
import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.viewModelScope
import kotlinx.coroutines.launch
class MainViewModel : ViewModel() {
private val _userData = MutableLiveData<User>()
val userData: LiveData<User> = _userData
private val _loading = MutableLiveData<Boolean>()
val loading: LiveData<Boolean> = _loading
private val _error = MutableLiveData<String>()
val error: LiveData<String> = _error
fun loadUser(userId: String) {
viewModelScope.launch {
_loading.value = true
try {
val user = userRepository.getUser(userId)
_userData.value = user
} catch (e: Exception) {
_error.value = e.message
} finally {
_loading.value = false
}
}
}
fun updateUser(user: User) {
viewModelScope.launch {
try {
userRepository.updateUser(user)
_userData.value = user
} catch (e: Exception) {
_error.value = e.message
}
}
}
}
```_
### Recycling Details anzeigen
```kotlin
import android.view.LayoutInflater
import android.view.ViewGroup
import androidx.recyclerview.widget.DiffUtil
import androidx.recyclerview.widget.ListAdapter
import androidx.recyclerview.widget.RecyclerView
import com.example.databinding.ItemUserBinding
class UserAdapter(
private val onUserClick: (User) -> Unit
) : ListAdapter<User, UserAdapter.UserViewHolder>(UserDiffCallback()) {
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): UserViewHolder {
val binding = ItemUserBinding.inflate(
LayoutInflater.from(parent.context),
parent,
false
)
return UserViewHolder(binding)
}
override fun onBindViewHolder(holder: UserViewHolder, position: Int) {
holder.bind(getItem(position))
}
inner class UserViewHolder(
private val binding: ItemUserBinding
) : RecyclerView.ViewHolder(binding.root) {
fun bind(user: User) {
binding.nameTextView.text = user.name
binding.emailTextView.text = user.email
binding.ageTextView.text = user.age.toString()
binding.root.setOnClickListener {
onUserClick(user)
}
}
}
class UserDiffCallback : DiffUtil.ItemCallback<User>() {
override fun areItemsTheSame(oldItem: User, newItem: User): Boolean {
return oldItem.id == newItem.id
}
override fun areContentsTheSame(oldItem: User, newItem: User): Boolean {
return oldItem == newItem
}
}
}
Repository Muster¶
```kotlin import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.withContext
class UserRepository( private val apiService: ApiService, private val userDao: UserDao ) {
suspend fun getUser(userId: String): User = withContext(Dispatchers.IO) {
try {
val user = apiService.getUser(userId)
userDao.insertUser(user)
user
} catch (e: Exception) {
// Fallback to cached data
userDao.getUser(userId) ?: throw e
}
}
suspend fun getUsers(): List<User> = withContext(Dispatchers.IO) {
try {
val users = apiService.getUsers()
userDao.insertUsers(users)
users
} catch (e: Exception) {
userDao.getAllUsers()
}
}
suspend fun updateUser(user: User): User = withContext(Dispatchers.IO) {
val updatedUser = apiService.updateUser(user)
userDao.updateUser(updatedUser)
updatedUser
}
suspend fun deleteUser(userId: String) = withContext(Dispatchers.IO) {
apiService.deleteUser(userId)
userDao.deleteUser(userId)
}
} ```_
Best Practices¶
Code Style¶
```kotlin // Use meaningful names class UserManager { // Good fun getUserById(id: String): User // Good fun isValidEmail(email: String): Boolean // Good }
class UM { // Bad fun get(i: String): User // Bad fun check(e: String): Boolean // Bad }
// Use type inference when possible val name = "John" // Good val name: String = "John" // Unnecessary
// Use data classes for simple data holders data class User(val id: String, val name: String, val email: String)
// Use sealed classes for restricted hierarchies
sealed class Result
// Use extension functions for utility methods fun String.isValidEmail(): Boolean { return android.util.Patterns.EMAIL_ADDRESS.matcher(this).matches() }
// Use scope functions appropriately val user = User("1", "John", "john@example.com").apply { // Configure user }
user?.let { nonNullUser -> // Process non-null user } ```_
Null Sicherheit Best Practices¶
```kotlin // Prefer safe calls over explicit null checks // Good val length = name?.length
// Less preferred val length = if (name != null) name.length else null
// Use Elvis operator for default values val displayName = user.name ?: "Anonymous"
// Use let for null-safe operations user?.let { nonNullUser -> processUser(nonNullUser) }
// Avoid not-null assertion operator unless absolutely necessary val definitelyNotNull = value!! // Use sparingly
// Use lateinit for properties that will be initialized later class MyActivity : Activity() { private lateinit var binding: ActivityMainBinding
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityMainBinding.inflate(layoutInflater)
}
} ```_
Performance Best Practices¶
```kotlin // Use lazy initialization for expensive operations class DataManager { private val expensiveResource by lazy { createExpensiveResource() }
private fun createExpensiveResource(): ExpensiveResource {
// Expensive initialization
return ExpensiveResource()
}
}
// Use inline functions for higher-order functions
inline fun
// Use data classes for better performance with collections data class Point(val x: Int, val y: Int)
val points = setOf(Point(1, 2), Point(3, 4), Point(1, 2)) // Automatic equals() and hashCode() implementation
// Use appropriate collection types val uniqueItems = setOf(1, 2, 3) // For unique items val orderedItems = listOf(1, 2, 3) // For ordered items val keyValuePairs = mapOf("a" to 1) // For key-value pairs
// Use sequences for large collections with multiple operations val result = (1..1000000) .asSequence() .filter { it % 2 == 0 } .map { it * 2 } .take(10) .toList() ```_
Coroutines Best Practices¶
```kotlin // Use appropriate dispatchers class UserRepository { suspend fun getUser(id: String): User = withContext(Dispatchers.IO) { // IO operation apiService.getUser(id) }
suspend fun processUserData(data: List<User>): List<ProcessedUser> =
withContext(Dispatchers.Default) {
// CPU-intensive operation
data.map { processUser(it) }
}
}
// Handle exceptions properly suspend fun fetchDataSafely(): Result { return try { val data = apiService.fetchData() Result.Success(data) } catch (e: Exception) { Result.Error(e) } }
// Use structured concurrency class DataLoader { suspend fun loadAllData(): CombinedData = coroutineScope { val userData = async { loadUserData() } val settingsData = async { loadSettingsData() } val preferencesData = async { loadPreferencesData() }
CombinedData(
users = userData.await(),
settings = settingsData.await(),
preferences = preferencesData.await()
)
}
}
// Cancel coroutines when no longer needed class MyViewModel : ViewModel() { private val job = SupervisorJob() private val scope = CoroutineScope(Dispatchers.Main + job)
override fun onCleared() {
super.onCleared()
job.cancel()
}
} ```_
--
Zusammenfassung¶
Kotlin ist eine moderne, präzise und sichere Programmiersprache, die erhebliche Vorteile für Android-Entwicklung und darüber hinaus bietet. Zu den wichtigsten Merkmalen gehören:
- Null Safety: Eingebaute Null-Sicherheit verhindert NullPointerException zum Kompilieren
- Krise: Reduziert Kesselplattencode deutlich gegenüber Java
- Interoperabilität: 100% interoperabel mit Java, so dass schrittweise Migration möglich ist
- **Coroutines*: Eingebaute Unterstützung für asynchrone Programmierung mit Koroutinen
- **Type Inference*: Smart Type Inference reduziert explizite Typenerklärungen
- **Extension Functions*: Funktionalität in bestehende Klassen ohne Erbschaft hinzufügen
- Datenklassen: Automatische Erzeugung von gleich(), hashCode(), toString() und copy()
- **Sealed Classes*: Eingeschränkte Klassenhierarchien für bessere Typsicherheit
- Smart Casts: Automatischer Typguss nach Nullprüfungen oder Typprüfungen
- **Funktionelle Programmierung*: Erstklassige Unterstützung für funktionale Programmierkonzepte
Kotlin kombiniert objektorientierte und funktionale Programmierfunktionen, so dass es eine ausgezeichnete Wahl für moderne Android-Entwicklung, serverseitige Entwicklung und multiplatform Projekte.
<= <= <= <================================================================================= Funktion copyToClipboard() {\cHFFFF} const commands = document.querySelectorAll('code'); alle Befehle = ''; Befehle. Für jede(cmd) => alle Befehle += cmd.textContent + '\n'); navigator.clipboard.writeText (allCommands); Alarm ('Alle Befehle, die in die Zwischenablage kopiert werden!'); }
Funktion generierenPDF() { Fenster.print(); }