Skip to content

Instantly share code, notes, and snippets.

@dmitry-osin
Created April 16, 2025 17:40
Show Gist options
  • Save dmitry-osin/7317f65efab1b91b8c707be9e556c9f0 to your computer and use it in GitHub Desktop.
Save dmitry-osin/7317f65efab1b91b8c707be9e556c9f0 to your computer and use it in GitHub Desktop.
Полная шпаргалка по Kotlin

Полная шпаргалка по Kotlin

1. Основы и типы данных

Базовые типы

  • Числовые: Byte, Short, Int, Long, Float, Double
  • Символьные: Char
  • Логические: Boolean
  • Строки: String
val intValue: Int = 10
val longValue = 10L
val floatValue = 10.0f
val doubleValue = 10.0
val charValue = 'A'
val boolValue = true
val stringValue = "Hello, Kotlin!"

Переменные и константы

  • val - неизменяемая переменная (константа)
  • var - изменяемая переменная
val immutable = 100 // нельзя изменить
var mutable = 200   // можно изменить
mutable = 300       // OK

Nullability (нуллабельность)

  • Типы по умолчанию не могут содержать null
  • Для разрешения null используется оператор ?
var nonNullable: String = "value" // не может быть null
var nullable: String? = null      // может быть null

// Безопасный вызов
val length = nullable?.length      // null если nullable == null

// Элвис-оператор
val lengthOrDefault = nullable?.length ?: 0

// Оператор !!
val forceLength = nullable!!.length // NullPointerException если nullable == null

2. Модульность и структура проекта

Пакеты и импорты

package com.example.myapp

import kotlin.math.* // импорт всех функций из пакета
import com.example.utils.Helper // импорт конкретного класса
import com.example.utils.Helper as UtilHelper // импорт с переименованием

Видимость и модификаторы доступа

  • public (по умолчанию) - доступно везде
  • private - доступно только внутри файла/класса
  • protected - как private, но доступно в подклассах
  • internal - доступно внутри модуля
internal class InternalClass
private fun privateFunction() = "Only visible in this file"

3. Операторы и выражения

Арифметические операторы

  • +, -, *, /, %

Операторы сравнения

  • ==, !=, >, <, >=, <=
  • ===, !== (сравнение по ссылке)

Логические операторы

  • &&, ||, !

Побитовые операторы

  • shl, shr, ushr, and, or, xor, inv
val a = 10
val b = 3
val result = a and b // побитовое И

Операторы приведения типов

  • as - небезопасное приведение
  • as? - безопасное приведение
  • is - проверка типа
val obj: Any = "String"
if (obj is String) {
    // Smart cast - внутри этого блока obj автоматически приводится к String
    println(obj.length)
}

val safeString = obj as? String // null, если obj не String
val unsafeString = obj as String // ClassCastException, если obj не String

Операторы перегрузки

data class Vector(val x: Int, val y: Int) {
    // Перегрузка оператора +
    operator fun plus(other: Vector) = Vector(x + other.x, y + other.y)
    
    // Перегрузка оператора *
    operator fun times(scalar: Int) = Vector(x * scalar, y * scalar)
    
    // Перегрузка оператора []
    operator fun get(index: Int): Int {
        return when(index) {
            0 -> x
            1 -> y
            else -> throw IndexOutOfBoundsException()
        }
    }
}

// Использование
val v1 = Vector(1, 2)
val v2 = Vector(3, 4)
val sum = v1 + v2 // Vector(4, 6)
val scaled = v1 * 3 // Vector(3, 6)
val xCoord = v1[0] // 1

4. Управление потоком выполнения

Условные выражения

// if как выражение
val max = if (a > b) a else b

// when (аналог switch)
when (x) {
    1 -> print("x == 1")
    2 -> print("x == 2")
    else -> print("x is neither 1 nor 2")
}

// when без аргумента
when {
    x > 0 -> print("x is positive")
    x < 0 -> print("x is negative")
    else -> print("x is 0")
}

Циклы

// for
for (i in 1..10) { /* ... */ }
for (i in 1 until 10) { /* ... */ }
for (i in 10 downTo 1 step 2) { /* ... */ }

// while и do-while
while (condition) { /* ... */ }
do { /* ... */ } while (condition)

Pattern Matching (сопоставление с образцом)

when (obj) {
    is Int -> println("Int: $obj")
    is String -> println("String: $obj")
    is List<*> -> println("List with ${obj.size} elements")
    else -> println("Unknown")
}

5. Функции

Объявление функций

fun sum(a: Int, b: Int): Int {
    return a + b
}

// Функция-выражение
fun sum(a: Int, b: Int) = a + b

// Функция без возвращаемого значения
fun printSum(a: Int, b: Int): Unit {
    println("$a + $b = ${a + b}")
}

Параметры по умолчанию

fun greet(name: String = "Guest") = println("Hello, $name!")

Именованные аргументы

fun createUser(name: String, age: Int, isAdmin: Boolean) { /* ... */ }
createUser(name = "Alice", age = 30, isAdmin = false)

Функции с переменным числом аргументов (varargs)

fun printAll(vararg messages: String) {
    for (m in messages) println(m)
}
printAll("Hello", "World", "!")

Infix функции

Позволяют вызывать функции в инфиксной нотации (без точки и скобок)

infix fun Int.plus(other: Int) = this + other
val result = 1 plus 2 // вместо 1.plus(2)

Методы расширения

Позволяют добавлять функциональность к существующим классам

fun String.addExclamation() = "$this!"
println("Hello".addExclamation()) // "Hello!"

6. Лямбда-выражения и функции высшего порядка

Лямбда-выражения

val sum = { a: Int, b: Int -> a + b }
val result = sum(1, 2) // 3

// С выводом типов
val numbers = listOf(1, 2, 3)
numbers.filter { it > 1 }

Функции высшего порядка

fun operation(a: Int, b: Int, op: (Int, Int) -> Int): Int {
    return op(a, b)
}

val result = operation(1, 2) { a, b -> a + b }

Лямбды как параметры функций (подробно)

Синтаксис объявления функциональных типов

// Функция, принимающая два Int и возвращающая Int
val func1: (Int, Int) -> Int = { a, b -> a + b }

// Функция, принимающая String и ничего не возвращающая (Unit)
val func2: (String) -> Unit = { println(it) }

// Функция без параметров, возвращающая String
val func3: () -> String = { "Hello" }

// Функция с nullable возвращаемым типом
val func4: (Int) -> Int? = { if (it > 0) it else null }

// Nullable функциональный тип
val func5: ((Int) -> Int)? = null

Передача лямбд в функции

// Последний параметр - лямбда
fun processNumbers(list: List<Int>, processor: (Int) -> Int): List<Int> {
    return list.map(processor)
}

// Вызов с лямбдой в скобках
val result1 = processNumbers(listOf(1, 2, 3), { it * 2 })

// Вызов с лямбдой за скобками (trailing lambda syntax)
val result2 = processNumbers(listOf(1, 2, 3)) { it * 2 }

Лямбды с приемником (receiver)

// Тип функции с приемником String
val appendExclamation: String.() -> String = { "$this!" }

// Использование
val result = "Hello".appendExclamation() // "Hello!"

// Функция, принимающая лямбду с приемником
fun buildString(builder: StringBuilder.() -> Unit): String {
    val sb = StringBuilder()
    sb.builder() // вызов лямбды с приемником
    return sb.toString()
}

// Использование
val result = buildString {
    append("Hello")
    append(", ")
    append("World!")
}

Ссылки на функции и конструкторы

// Ссылка на функцию
fun isEven(n: Int) = n % 2 == 0
val numbers = listOf(1, 2, 3, 4)
val evenNumbers = numbers.filter(::isEven)

// Ссылка на метод объекта
val str = "Hello"
val isNotEmpty = str::isNotEmpty
println(isNotEmpty()) // true

// Ссылка на метод класса
val isEmptyMethod = String::isEmpty
println(isEmptyMethod("")) // true

// Ссылка на конструктор
data class Person(val name: String)
val createPerson = ::Person
val person = createPerson("Alice")

Замыкания (closures)

fun makeCounter(): () -> Int {
    var count = 0
    return { count++ } // лямбда захватывает переменную count
}

val counter = makeCounter()
println(counter()) // 0
println(counter()) // 1

Inline-функции с лямбдами

// Inline-функция устраняет накладные расходы на создание объекта-функции
inline fun measureTime(block: () -> Unit): Long {
    val start = System.currentTimeMillis()
    block()
    return System.currentTimeMillis() - start
}

val time = measureTime {
    // код, время выполнения которого нужно измерить
}

Crossinline и noinline

// crossinline запрещает нелокальные возвраты в лямбде
inline fun processWithCallback(crossinline callback: () -> Unit) {
    runOnUiThread { callback() }
}

// noinline отключает inline для конкретного параметра
inline fun process(inlined: () -> Unit, noinline notInlined: () -> Unit) {
    inlined()
    runOnBackground(notInlined) // передача функции дальше
}

Расширенный формат лямбд

// Лямбда с приемником (this)
val sum = fun Int.(other: Int): Int {
    return this + other
}
1.sum(2) // 3

// Лямбда с несколькими строками
val process = { x: Int ->
    val y = x * 2
    val z = y + 1
    z
}

7. Классы и объекты

Объявление класса

class Person(val firstName: String, var age: Int) {
    // Первичный конструктор выше
    
    // Вторичный конструктор
    constructor(firstName: String) : this(firstName, 0)
    
    // Метод
    fun greet() = "Hello, I'm $firstName"
    
    // Свойство
    val isAdult: Boolean
        get() = age >= 18
}

Наследование

open class Animal(val name: String) {
    open fun makeSound() = "???"
}

class Dog(name: String) : Animal(name) {
    override fun makeSound() = "Woof!"
}

Интерфейсы

interface Clickable {
    fun click()
    fun showOff() = println("I'm clickable!") // метод с реализацией по умолчанию
}

class Button : Clickable {
    override fun click() = println("Button clicked")
}

Абстрактные классы

abstract class Shape {
    abstract fun area(): Double
}

class Circle(val radius: Double) : Shape() {
    override fun area() = Math.PI * radius * radius
}

Композиция

class Car(val engine: Engine, val wheels: List<Wheel>)

Композиция через делегирование

Kotlin предоставляет встроенную поддержку шаблона "Композиция через делегирование", который позволяет реализовать интерфейсы, делегируя их методы другому объекту.

interface Base {
    fun print()
    fun sayHello()
}

// Класс, реализующий интерфейс
class BaseImpl : Base {
    override fun print() = println("BaseImpl: print")
    override fun sayHello() = println("BaseImpl: hello")
}

// Класс, делегирующий реализацию интерфейса другому объекту
class Derived(b: Base) : Base by b {
    // Можно переопределить некоторые методы
    override fun print() = println("Derived: print")
}

fun main() {
    val base = BaseImpl()
    val derived = Derived(base)
    
    derived.print()    // "Derived: print" - переопределенный метод
    derived.sayHello() // "BaseImpl: hello" - делегированный метод
}

Делегирование нескольким интерфейсам

interface Clickable {
    fun click()
}

interface Focusable {
    fun focus()
}

class Button(
    clickHandler: Clickable,
    focusHandler: Focusable
) : Clickable by clickHandler, Focusable by focusHandler

Делегирование с переопределением

interface Worker {
    fun work()
    fun takeBreak()
}

class DefaultWorker : Worker {
    override fun work() = println("Working...")
    override fun takeBreak() = println("Taking a break")
}

class LazyWorker(worker: Worker) : Worker by worker {
    override fun work() = println("Pretending to work")
    // takeBreak() делегируется worker
}

Делегирование конструктору

class MyView : View {
    constructor(ctx: Context) : super(ctx)
    constructor(ctx: Context, attrs: AttributeSet) : super(ctx, attrs)
}

Объекты-синглтоны

object Singleton {
    val property = "I'm a singleton"
    fun doSomething() = println("Doing something")
}

Объекты-компаньоны

class MyClass {
    companion object {
        fun create(): MyClass = MyClass()
    }
}

val instance = MyClass.create()

Data классы

data class User(val name: String, val age: Int)

// Автоматически генерируются:
// equals(), hashCode(), toString(), copy(), component1(), component2(), ...

Sealed классы и интерфейсы

Ограничивают иерархию наследования

sealed class Result {
    data class Success(val data: String) : Result()
    data class Error(val message: String) : Result()
    object Loading : Result()
}

fun handleResult(result: Result) = when(result) {
    is Result.Success -> println("Success: ${result.data}")
    is Result.Error -> println("Error: ${result.message}")
    is Result.Loading -> println("Loading...")
    // Не нужен else, компилятор знает все подклассы
}

8. Свойства и делегаты

Свойства

class Person {
    var name: String = ""
        get() = field.uppercase()
        set(value) {
            field = value.trim()
        }
}

Делегирование свойств

import kotlin.properties.Delegates

class User {
    var name: String by Delegates.observable("") { 
        prop, old, new -> println("$old -> $new") 
    }
    
    val lazyValue: String by lazy {
        println("Computed!")
        "Hello"
    }
}

KProperty

import kotlin.reflect.KProperty

class Delegate {
    operator fun getValue(thisRef: Any?, property: KProperty<*>): String {
        return "$thisRef, thank you for delegating '${property.name}' to me!"
    }
    
    operator fun setValue(thisRef: Any?, property: KProperty<*>, value: String) {
        println("$value has been assigned to '${property.name}' in $thisRef.")
    }
}

class Example {
    var p: String by Delegate()
}

9. Дженерики (Обобщения)

Базовое использование

class Box<T>(val value: T)
val intBox = Box(1)
val stringBox = Box("Hello")

Вариативность

  • Инвариантность - по умолчанию: Box<String> не является подтипом или супертипом Box<Any>
  • Ковариантность (out) - Box<String> является подтипом Box<Any>
  • Контравариантность (in) - Box<Any> является подтипом Box<String>
// Ковариантность (out) - можно только возвращать T, но не принимать
class Producer<out T>(private val value: T) {
    fun get(): T = value
}

// Контравариантность (in) - можно только принимать T, но не возвращать
class Consumer<in T> {
    fun consume(value: T) { /* ... */ }
}

Ограничения типов

fun <T : Comparable<T>> sort(list: List<T>) { /* ... */ }

Reified типы

Доступ к информации о типе во время выполнения в inline-функциях

inline fun <reified T> isA(value: Any) = value is T

fun main() {
    println(isA<String>("abc")) // true
    println(isA<Int>("abc"))    // false
}

10. Коллекции

Основные типы коллекций

  • List - упорядоченная коллекция
  • Set - неупорядоченная коллекция уникальных элементов
  • Map - набор пар ключ-значение
// Неизменяемые коллекции
val list = listOf(1, 2, 3)
val set = setOf(1, 2, 3)
val map = mapOf("a" to 1, "b" to 2)

// Изменяемые коллекции
val mutableList = mutableListOf(1, 2, 3)
val mutableSet = mutableSetOf(1, 2, 3)
val mutableMap = mutableMapOf("a" to 1, "b" to 2)

Операции с коллекциями

// Фильтрация
val filtered = list.filter { it > 1 }

// Преобразование
val doubled = list.map { it * 2 }

// Сортировка
val sorted = list.sorted()

// Группировка
val grouped = list.groupBy { it % 2 }

// Агрегация
val sum = list.sum()
val reduced = list.reduce { acc, i -> acc + i }
val folded = list.fold(0) { acc, i -> acc + i }

// Поиск
val found = list.find { it > 2 }
val any = list.any { it > 2 }
val all = list.all { it > 0 }

Последовательности

Ленивые коллекции, операции выполняются только при необходимости

val sequence = sequenceOf(1, 2, 3, 4, 5)
    .filter { it > 2 }
    .map { it * 2 }
    .toList() // только здесь выполняются операции

11. Деструктуризация

// Для data классов
data class Person(val name: String, val age: Int)
val person = Person("Alice", 30)
val (name, age) = person

// Для пар и троек
val pair = Pair("Alice", 30)
val (name, age) = pair

// В циклах
for ((key, value) in mapOf("a" to 1, "b" to 2)) {
    println("$key -> $value")
}

12. Scope функции

let

val length = str?.let {
    // it - это str
    it.length
}

run

val length = str?.run {
    // this - это str
    length
}

with

val result = with(str) {
    // this - это str
    length
}

apply

val person = Person().apply {
    // this - это Person
    name = "Alice"
    age = 30
}

also

val person = Person("Alice", 30).also {
    // it - это Person
    println("Created person: ${it.name}")
}

13. DSL (Domain Specific Language)

Kotlin отлично подходит для создания предметно-ориентированных языков:

// Пример DSL для создания HTML
fun html(init: HTML.() -> Unit): HTML {
    val html = HTML()
    html.init()
    return html
}

class HTML {
    fun head(init: Head.() -> Unit) { /*...*/ }
    fun body(init: Body.() -> Unit) { /*...*/ }
}

// Использование
html {
    head {
        title("DSL Demo")
    }
    body {
        h1("Hello, Kotlin DSL!")
        p("This is a paragraph")
    }
}

14. Типобезопасные строители (Type-safe builders)

class Person {
    var name = ""
    var age = 0
    var address = Address()
    
    fun address(init: Address.() -> Unit) {
        address.init()
    }
}

class Address {
    var street = ""
    var city = ""
    var zipCode = ""
}

fun person(init: Person.() -> Unit): Person {
    val person = Person()
    person.init()
    return person
}

// Использование
val john = person {
    name = "John"
    age = 25
    address {
        street = "Main Street"
        city = "New York"
        zipCode = "10001"
    }
}

15. Асинхронность и конкуррентность

Корутины

import kotlinx.coroutines.*

fun main() = runBlocking {
    launch {
        delay(1000L)
        println("World!")
    }
    println("Hello,")
}

Контекст корутин и диспетчеры

launch(Dispatchers.Default) {
    // Выполняется в пуле потоков по умолчанию
}

launch(Dispatchers.IO) {
    // Оптимизировано для операций ввода/вывода
}

launch(Dispatchers.Main) {
    // Выполняется в главном потоке (для UI)
}

Структурированная конкуррентность

coroutineScope {
    val job1 = launch { /* ... */ }
    val job2 = launch { /* ... */ }
    // Ждет завершения всех корутин
}

Обработка ошибок в корутинах

val handler = CoroutineExceptionHandler { _, exception ->
    println("Caught $exception")
}

val job = GlobalScope.launch(handler) {
    throw AssertionError("Error in coroutine")
}
job.join()

SupervisorJob

val supervisor = SupervisorJob()
val scope = CoroutineScope(supervisor + Dispatchers.Default)

scope.launch {
    // Ошибка здесь не отменит другие дочерние корутины
}

Каналы (Channels)

val channel = Channel<Int>()
launch {
    for (i in 1..5) {
        channel.send(i)
    }
    channel.close()
}

for (value in channel) {
    println(value)
}

Flow API

Асинхронные потоки данных

fun simple(): Flow<Int> = flow {
    for (i in 1..3) {
        delay(100)
        emit(i)
    }
}

suspend fun main() {
    simple().collect { value ->
        println(value)
    }
}

Операторы Flow

val flow = flow {
    for (i in 1..5) emit(i)
}

flow
    .filter { it > 2 }
    .map { it * 2 }
    .collect { println(it) }

StateFlow и SharedFlow

val _stateFlow = MutableStateFlow(0)
val stateFlow = _stateFlow.asStateFlow()

_stateFlow.value = 1 // Обновление значения

16. Взаимодействие с Java (Interop)

Аннотации для улучшения взаимодействия

  • @JvmStatic - для статических методов
  • @JvmField - для полей без геттеров/сеттеров
  • @JvmOverloads - для генерации перегруженных методов
  • @Throws - для объявления исключений
class KotlinClass {
    companion object {
        @JvmStatic fun staticMethod() { /* ... */ }
    }
    
    @JvmField
    val directField = "value"
    
    @JvmOverloads
    fun method(param1: String, param2: Int = 0) { /* ... */ }
    
    @Throws(IOException::class)
    fun riskyMethod() { /* ... */ }
}

Вызов Java-кода из Kotlin

// Платформенные типы (могут быть null)
val javaString: String? = JavaClass.returnsString()

// SAM-конверсия
JavaClass.setListener { println("Clicked!") }

Вызов Kotlin-кода из Java

// Вызов функций верхнего уровня
String result = MyFileKt.topLevelFunction();

// Вызов методов объекта-синглтона
String data = MySingleton.INSTANCE.getData();

// Вызов методов объекта-компаньона с @JvmStatic
MyClass.staticMethod();

17. Аннотации и рефлексия

// Объявление аннотации
annotation class Inject

// Использование аннотации
@Inject
class MyService

// Рефлексия
val kClass = MyService::class
val annotations = kClass.annotations
val properties = kClass.memberProperties

18. Встроенные аннотации

@Deprecated("Use newMethod instead", ReplaceWith("newMethod()"))
fun oldMethod() { /*...*/ }

@OptIn(ExperimentalCoroutinesApi::class)
fun experimentalFunction() { /*...*/ }

@RequiresOptIn("This API is experimental")
annotation class ExperimentalAPI

@ExperimentalAPI
fun dangerousFunction() { /*...*/ }

19. Контракты (Contracts)

import kotlin.contracts.*

fun String?.isNullOrEmpty(): Boolean {
    contract {
        returns(false) implies (this@isNullOrEmpty != null)
    }
    return this == null || this.isEmpty()
}

fun main() {
    val name: String? = "John"
    if (!name.isNullOrEmpty()) {
        // Компилятор знает, что name не null
        println(name.length)
    }
}

20. Контекстные приемники (Context Receivers)

Новая экспериментальная функция в Kotlin 1.6.20+:

// Объявление
context(Logger, Transaction)
fun saveUser(user: User) {
    log("Saving user: ${user.name}") // доступ к методу log из Logger
    commit() // доступ к методу commit из Transaction
}

// Использование
with(logger) {
    with(transaction) {
        saveUser(user)
    }
}

Продолжение полной шпаргалки по Kotlin

21. Многоплатформенная разработка (Kotlin Multiplatform)

// Общий код
expect fun getPlatformName(): String

// Платформенно-специфичная реализация для JVM
actual fun getPlatformName(): String = "JVM"

// Платформенно-специфичная реализация для JS
actual fun getPlatformName(): String = "JavaScript"

Общие компоненты для разных платформ

// Общий код
expect class DateFormatter() {
    fun format(date: Date): String
}

// Реализация для JVM
actual class DateFormatter {
    private val formatter = SimpleDateFormat("yyyy-MM-dd")
    
    actual fun format(date: Date): String {
        return formatter.format(date)
    }
}

// Реализация для JS
actual class DateFormatter {
    actual fun format(date: Date): String {
        return "${date.getFullYear()}-${date.getMonth()+1}-${date.getDate()}"
    }
}

22. Kotlin/Native и взаимодействие с C

import kotlinx.cinterop.*
import platform.posix.*

fun main() {
    memScoped {
        val cString = "Hello from Kotlin/Native!".cstr.ptr
        printf("C string: %s\n", cString)
    }
}

Вызов нативных функций

import kotlinx.cinterop.*
import platform.posix.*

fun main() {
    val time = time(null)
    val localTime = localtime(cValuesOf(time))?.pointed
    
    if (localTime != null) {
        println("Год: ${localTime.tm_year + 1900}")
        println("Месяц: ${localTime.tm_mon + 1}")
        println("День: ${localTime.tm_mday}")
    }
}

Работа с памятью

import kotlinx.cinterop.*

fun main() {
    memScoped {
        val buffer = allocArray<ByteVar>(1024)
        buffer[0] = 42
        println("Значение: ${buffer[0]}")
    } // Память освобождается автоматически
}

23. Kotlin/JS и взаимодействие с JavaScript

external fun alert(message: String)

fun main() {
    alert("Hello from Kotlin/JS!")
    
    val obj = js("{ name: 'John', age: 30 }")
    console.log(obj.name)
}

Использование JavaScript библиотек

@JsModule("lodash")
@JsNonModule
external object _ {
    fun chunk(array: Array<Int>, size: Int): Array<Array<Int>>
}

fun main() {
    val result = _.chunk(arrayOf(1, 2, 3, 4), 2)
    console.log(result)
}

Создание React-компонентов

external interface ReactProps {
    var name: String
}

val Welcome = functionalComponent<ReactProps> { props ->
    div {
        +"Hello, ${props.name}"
    }
}

fun main() {
    render(document.getElementById("root")) {
        Welcome {
            name = "Kotlin"
        }
    }
}

24. Kotlin Symbol Processing (KSP)

KSP - это альтернатива KAPT для обработки аннотаций, более эффективная и быстрая.

// Пример аннотации для KSP
@Target(AnnotationTarget.CLASS)
annotation class GenerateFactory

// Использование
@GenerateFactory
class MyService

Создание процессора аннотаций

// В модуле процессора
class MySymbolProcessor : SymbolProcessor {
    override fun process(resolver: Resolver): List<KSAnnotated> {
        val symbols = resolver.getSymbolsWithAnnotation("com.example.GenerateFactory")
        
        symbols.forEach { symbol ->
            if (symbol is KSClassDeclaration) {
                // Генерация кода для аннотированного класса
            }
        }
        
        return emptyList()
    }
}

25. Kotlin для Android

Jetpack Compose

@Composable
fun Greeting(name: String) {
    Text(text = "Hello $name!")
}

@Preview
@Composable
fun PreviewGreeting() {
    Greeting("Android")
}

Compose модификаторы

@Composable
fun StyledButton(text: String, onClick: () -> Unit) {
    Button(
        onClick = onClick,
        modifier = Modifier
            .padding(16.dp)
            .fillMaxWidth()
            .height(56.dp),
        colors = ButtonDefaults.buttonColors(
            backgroundColor = MaterialTheme.colors.primary
        )
    ) {
        Text(text = text)
    }
}

View Binding

class MainActivity : AppCompatActivity() {
    private lateinit var binding: ActivityMainBinding
    
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        binding = ActivityMainBinding.inflate(layoutInflater)
        setContentView(binding.root)
        
        binding.button.setOnClickListener {
            binding.textView.text = "Button clicked!"
        }
    }
}

ViewModel и LiveData

class UserViewModel : ViewModel() {
    private val _user = MutableLiveData<User>()
    val user: LiveData<User> = _user
    
    fun loadUser(userId: String) {
        viewModelScope.launch {
            _user.value = repository.getUser(userId)
        }
    }
}

// Использование в Activity/Fragment
viewModel.user.observe(viewLifecycleOwner) { user ->
    binding.userName.text = user.name
}

26. Kotlin для серверной разработки

Ktor (фреймворк для веб-приложений)

fun Application.module() {
    routing {
        get("/") {
            call.respondText("Hello, Ktor!")
        }
        
        get("/users/{id}") {
            val id = call.parameters["id"]
            call.respond(userService.getUser(id))
        }
    }
}

Exposed (ORM для Kotlin)

object Users : Table() {
    val id = integer("id").autoIncrement().primaryKey()
    val name = varchar("name", 50)
    val email = varchar("email", 100)
}

transaction {
    Users.insert {
        it[name] = "John"
        it[email] = "[email protected]"
    }
}

Spring Boot с Kotlin

@RestController
class UserController(private val userService: UserService) {
    
    @GetMapping("/users")
    fun getUsers(): List<User> = userService.findAll()
    
    @PostMapping("/users")
    fun createUser(@RequestBody user: User): User = userService.save(user)
}

27. Оптимизации производительности

Inline классы

@JvmInline
value class Password(val value: String)

fun validatePassword(password: Password) { /* ... */ }

// Использование
val password = Password("secret")
validatePassword(password)

Value классы (Kotlin 1.5+)

value class Point(val x: Int, val y: Int) {
    fun distanceTo(other: Point): Double {
        val dx = x - other.x
        val dy = y - other.y
        return kotlin.math.sqrt((dx * dx + dy * dy).toDouble())
    }
}

Оптимизация коллекций

// Использование асинхронных коллекций
val list = buildList {
    add(1)
    add(2)
    addAll(listOf(3, 4, 5))
}

// Использование последовательностей для больших наборов данных
val result = sequence {
    for (i in 1..1000000) {
        yield(i)
    }
}
.filter { it % 2 == 0 }
.map { it * 2 }
.take(10)
.toList()

28. Тестирование в Kotlin

JUnit тесты

class CalculatorTest {
    @Test
    fun `2 plus 2 should equal 4`() {
        val calculator = Calculator()
        assertEquals(4, calculator.add(2, 2))
    }
    
    @Test
    fun `division by zero should throw exception`() {
        val calculator = Calculator()
        assertThrows<ArithmeticException> {
            calculator.divide(1, 0)
        }
    }
}

Mockk (библиотека для мокирования)

@Test
fun `should call repository when service method is called`() {
    // Создание мока
    val repository = mockk<UserRepository>()
    
    // Настройка поведения
    every { repository.findById(any()) } returns User("1", "John")
    
    // Создание тестируемого объекта с моком
    val service = UserService(repository)
    
    // Вызов тестируемого метода
    val user = service.getUserById("1")
    
    // Проверки
    assertEquals("John", user.name)
    verify(exactly = 1) { repository.findById("1") }
}

Корутины в тестах

@Test
fun `test coroutine function`() = runTest {
    val result = withContext(Dispatchers.Default) {
        delay(1000) // Виртуальное время в тестах
        "Result"
    }
    
    assertEquals("Result", result)
}

29. Расширенные возможности языка

Встроенные делегаты свойств

// Ленивая инициализация
val lazyValue: String by lazy {
    println("Computed!")
    "Hello"
}

// Наблюдаемые свойства
var name: String by Delegates.observable("initial") { prop, old, new ->
    println("$old -> $new")
}

// Хранение свойств в Map
class User(val map: Map<String, Any?>) {
    val name: String by map
    val age: Int by map
}

val user = User(mapOf(
    "name" to "John",
    "age" to 25
))

Инлайн-классы с несколькими полями (Kotlin 1.8+)

@JvmInline
value class Name(
    val first: String,
    val last: String
) {
    fun fullName() = "$first $last"
}

// Использование
val name = Name("John", "Doe")
println(name.fullName()) // "John Doe"

Функциональные интерфейсы

fun interface Predicate<T> {
    fun test(value: T): Boolean
}

// Использование - автоматическое преобразование лямбды
val isEven = Predicate<Int> { it % 2 == 0 }
println(isEven.test(4)) // true

30. Новые возможности Kotlin 1.9 и выше

Kotlin K2 компилятор

// Включение K2 компилятора в gradle.properties
kotlin.experimental.tryK2=true

Улучшенный вывод типов

// Вывод типов для возвращаемых значений
fun createMap() = buildMap { // Тип выводится как Map<String, Int>
    put("one", 1)
    put("two", 2)
}

Новые функции стандартной библиотеки

// Функция zip для Map
val map1 = mapOf("a" to 1, "b" to 2)
val map2 = mapOf("a" to "A", "b" to "B")
val zipped = map1.zip(map2) { (k1, v1), (k2, v2) -> 
    k1 to "$v1-$v2"
}
// Результат: [("a" to "1-A"), ("b" to "2-B")]

// Функция chunked с трансформацией
val numbers = listOf(1, 2, 3, 4, 5)
val sumOfChunks = numbers.chunked(2) { it.sum() }
// Результат: [3, 7, 5]

Эта полная шпаргалка охватывает основные и продвинутые возможности языка Kotlin, включая работу с различными платформами, оптимизации, тестирование и новейшие функции. Она будет полезна как для начинающих, так и для опытных разработчиков Kotlin.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment