Kotlin Patterns

affaan-m/ECC/docs/tr/skills/kotlin-patterns

作者 affaan-mef648e01899ba3e8dc6371642deaaf64b4477775無授權條款275K 個星標收錄於 2026年10月9日更新於 2026年10月9日儲存庫4 天前更新

Coroutine'ler, null safety ve DSL builder'lar ile sağlam, verimli ve sürdürülebilir Kotlin uygulamaları oluşturmak için idiomatic Kotlin kalıpları, en iyi uygulamalar ve konvansiyonlar.

AI 產生的概覽

提供慣用 Kotlin 模式與最佳實務,涵蓋空值安全、不可變性、協程、DSL 與 Gradle Kotlin DSL。

功能
此技能在七個面向提供慣用 Kotlin 慣例與最佳實務:空值安全、不可變性、密封類別與介面、協程與 Flow、擴充函式、型別安全 DSL 建構器,以及 Gradle Kotlin DSL。內容以附註解的程式碼範例呈現,涵蓋作用域函式、資料類別與值類別、使用 Result 的錯誤處理、require/check,以及應避免的反模式。它產出的是參考指引與程式碼片段,而非可執行的成品。
適用情境
適用於撰寫新的 Kotlin 程式碼、審查或重構現有 Kotlin 程式碼、設計 Kotlin 模組或函式庫,以及設定 Gradle Kotlin DSL 建置時。對象是希望將慣用慣例套用於 Kotlin 工作的開發者。
執行需求
不需要任何指令碼或工具,僅為純說明文件。範例涉及 Kotlin、協程、Flow、Gradle Kotlin DSL 以及 Ktor、Exposed、Koin、Kotest、MockK 等函式庫,但閱讀這些指引無需安裝任何項目。

Kotlin Geliştirme Kalıpları

Sağlam, verimli ve sürdürülebilir uygulamalar oluşturmak için idiomatic Kotlin kalıpları ve en iyi uygulamalar.

Ne Zaman Kullanılır

  • Yeni Kotlin kodu yazarken
  • Kotlin kodunu incelerken
  • Mevcut Kotlin kodunu refactor ederken
  • Kotlin modülleri veya kütüphaneleri tasarlarken
  • Gradle Kotlin DSL build'lerini yapılandırırken

Nasıl Çalışır

Bu skill yedi temel alanda idiomatic Kotlin konvansiyonlarını uygular: tip sistemi ve safe-call operatörleri kullanarak null safety, val ve data class'larda copy() ile immutability, exhaustive tip hiyerarşileri için sealed class'lar ve interface'ler, coroutine'ler ve Flow ile yapılandırılmış eşzamanlılık, inheritance olmadan davranış eklemek için extension fonksiyonlar, @DslMarker ve lambda receiver'lar kullanarak tip güvenli DSL builder'lar, ve build yapılandırması için Gradle Kotlin DSL.

Örnekler

Elvis operatörü ile null safety:

kotlin
fun getUserEmail(userId: String): String {    val user = userRepository.findById(userId)    return user?.email ?: "[email protected]"}

Exhaustive sonuçlar için sealed class:

kotlin
sealed class Result<out T> {    data class Success<T>(val data: T) : Result<T>()    data class Failure(val error: AppError) : Result<Nothing>()    data object Loading : Result<Nothing>()}

async/await ile yapılandırılmış eşzamanlılık:

kotlin
suspend fun fetchUserWithPosts(userId: String): UserProfile =    coroutineScope {        val user = async { userService.getUser(userId) }        val posts = async { postService.getUserPosts(userId) }        UserProfile(user = user.await(), posts = posts.await())    }

Temel İlkeler

1. Null Safety

Kotlin'in tip sistemi nullable ve non-nullable tipleri ayırır. Tam olarak kullanın.

kotlin
// İyi: Varsayılan olarak non-nullable tipler kullanfun getUser(id: String): User {    return userRepository.findById(id)        ?: throw UserNotFoundException("User $id not found")}
// İyi: Safe call'lar ve Elvis operatörüfun getUserEmail(userId: String): String {    val user = userRepository.findById(userId)    return user?.email ?: "[email protected]"}
// Kötü: Nullable tipleri zorla açmafun getUserEmail(userId: String): String {    val user = userRepository.findById(userId)    return user!!.email // null ise NPE fırlatır}

2. Varsayılan Olarak Immutability

var yerine val tercih edin, mutable koleksiyonlar yerine immutable olanları.

kotlin
// İyi: Immutable veridata class User(    val id: String,    val name: String,    val email: String,)
// İyi: copy() ile dönüştürmefun updateEmail(user: User, newEmail: String): User =    user.copy(email = newEmail)
// İyi: Immutable koleksiyonlarval users: List<User> = listOf(user1, user2)val filtered = users.filter { it.email.isNotBlank() }
// Kötü: Mutable statevar currentUser: User? = null // Mutable global state'ten kaçınval mutableUsers = mutableListOf<User>() // Gerçekten gerekmedikçe kaçın

3. Expression Body'ler ve Tek İfadeli Fonksiyonlar

Kısa, okunabilir fonksiyonlar için expression body'ler kullanın.

kotlin
// İyi: Expression bodyfun isAdult(age: Int): Boolean = age >= 18
fun formatFullName(first: String, last: String): String =    "$first $last".trim()
fun User.displayName(): String =    name.ifBlank { email.substringBefore('@') }
// İyi: Expression olarak whenfun statusMessage(code: Int): String = when (code) {    200 -> "OK"    404 -> "Not Found"    500 -> "Internal Server Error"    else -> "Unknown status: $code"}
// Kötü: Gereksiz block bodyfun isAdult(age: Int): Boolean {    return age >= 18}

4. Value Objeler İçin Data Class'lar

Öncelikle veri tutan tipler için data class'lar kullanın.

kotlin
// İyi: copy, equals, hashCode, toString ile data classdata class CreateUserRequest(    val name: String,    val email: String,    val role: Role = Role.USER,)
// İyi: Tip güvenliği için value class (runtime'da sıfır maliyet)@JvmInlinevalue class UserId(val value: String) {    init {        require(value.isNotBlank()) { "UserId cannot be blank" }    }}
@JvmInlinevalue class Email(val value: String) {    init {        require('@' in value) { "Invalid email: $value" }    }}
fun getUser(id: UserId): User = userRepository.findById(id)

Sealed Class'lar ve Interface'ler

Kısıtlı Hiyerarşileri Modelleme

kotlin
// İyi: Exhaustive when için sealed classsealed class Result<out T> {    data class Success<T>(val data: T) : Result<T>()    data class Failure(val error: AppError) : Result<Nothing>()    data object Loading : Result<Nothing>()}
fun <T> Result<T>.getOrNull(): T? = when (this) {    is Result.Success -> data    is Result.Failure -> null    is Result.Loading -> null}
fun <T> Result<T>.getOrThrow(): T = when (this) {    is Result.Success -> data    is Result.Failure -> throw error.toException()    is Result.Loading -> throw IllegalStateException("Still loading")}

API Yanıtları İçin Sealed Interface'ler

kotlin
sealed interface ApiError {    val message: String
    data class NotFound(override val message: String) : ApiError    data class Unauthorized(override val message: String) : ApiError    data class Validation(        override val message: String,        val field: String,    ) : ApiError    data class Internal(        override val message: String,        val cause: Throwable? = null,    ) : ApiError}
fun ApiError.toStatusCode(): Int = when (this) {    is ApiError.NotFound -> 404    is ApiError.Unauthorized -> 401    is ApiError.Validation -> 422    is ApiError.Internal -> 500}

Scope Fonksiyonlar

Her Birini Ne Zaman Kullanmalı

kotlin
// let: Nullable'ı veya scope edilmiş sonucu dönüştürval length: Int? = name?.let { it.trim().length }
// apply: Bir nesneyi yapılandır (nesneyi döndürür)val user = User().apply {    name = "Alice"    email = "[email protected]"}
// also: Yan etkiler (nesneyi döndürür)val user = createUser(request).also { logger.info("Created user: ${it.id}") }
// run: Receiver ile block çalıştır (sonucu döndürür)val result = connection.run {    prepareStatement(sql)    executeQuery()}
// with: run'ın extension olmayan formuval csv = with(StringBuilder()) {    appendLine("name,email")    users.forEach { appendLine("${it.name},${it.email}") }    toString()}

Extension Fonksiyonlar

Inheritance Olmadan Fonksiyonalite Ekleme

kotlin
// İyi: Domain'e özgü extension'larfun String.toSlug(): String =    lowercase()        .replace(Regex("[^a-z0-9\\s-]"), "")        .replace(Regex("\\s+"), "-")        .trim('-')
fun Instant.toLocalDate(zone: ZoneId = ZoneId.systemDefault()): LocalDate =    atZone(zone).toLocalDate()
// İyi: Koleksiyon extension'larıfun <T> List<T>.second(): T = this[1]
fun <T> List<T>.secondOrNull(): T? = getOrNull(1)
// İyi: Scope edilmiş extension'lar (global namespace'i kirletmez)class UserService {    private fun User.isActive(): Boolean =        status == Status.ACTIVE && lastLogin.isAfter(Instant.now().minus(30, ChronoUnit.DAYS))
    fun getActiveUsers(): List<User> = userRepository.findAll().filter { it.isActive() }}

Coroutine'ler

Yapılandırılmış Eşzamanlılık

kotlin
// İyi: coroutineScope ile yapılandırılmış eşzamanlılıksuspend fun fetchUserWithPosts(userId: String): UserProfile =    coroutineScope {        val userDeferred = async { userService.getUser(userId) }        val postsDeferred = async { postService.getUserPosts(userId) }
        UserProfile(            user = userDeferred.await(),            posts = postsDeferred.await(),        )    }
// İyi: child'lar bağımsız başarısız olabildiğinde supervisorScopesuspend fun fetchDashboard(userId: String): Dashboard =    supervisorScope {        val user = async { userService.getUser(userId) }        val notifications = async { notificationService.getRecent(userId) }        val recommendations = async { recommendationService.getFor(userId) }
        Dashboard(            user = user.await(),            notifications = try {                notifications.await()            } catch (e: CancellationException) {                throw e            } catch (e: Exception) {                emptyList()            },            recommendations = try {                recommendations.await()            } catch (e: CancellationException) {                throw e            } catch (e: Exception) {                emptyList()            },        )    }

Reactive Stream'ler İçin Flow

kotlin
// İyi: Uygun hata işleme ile cold flowfun observeUsers(): Flow<List<User>> = flow {    while (currentCoroutineContext().isActive) {        val users = userRepository.findAll()        emit(users)        delay(5.seconds)    }}.catch { e ->    logger.error("Error observing users", e)    emit(emptyList())}
// İyi: Flow operatörlerifun searchUsers(query: Flow<String>): Flow<List<User>> =    query        .debounce(300.milliseconds)        .distinctUntilChanged()        .filter { it.length >= 2 }        .mapLatest { q -> userRepository.search(q) }        .catch { emit(emptyList()) }

DSL Builder'lar

Tip Güvenli Builder'lar

kotlin
// İyi: @DslMarker ile DSL@DslMarkerannotation class HtmlDsl
@HtmlDslclass HTML {    private val children = mutableListOf<Element>()
    fun head(init: Head.() -> Unit) {        children += Head().apply(init)    }
    fun body(init: Body.() -> Unit) {        children += Body().apply(init)    }
    override fun toString(): String = children.joinToString("\n")}
fun html(init: HTML.() -> Unit): HTML = HTML().apply(init)
// Kullanımval page = html {    head { title("My Page") }    body {        h1("Welcome")        p("Hello, World!")    }}

Gradle Kotlin DSL

build.gradle.kts Yapılandırması

kotlin
// En son versiyonları kontrol et: https://kotlinlang.org/docs/releases.htmlplugins {    kotlin("jvm") version "2.3.10"    kotlin("plugin.serialization") version "2.3.10"    id("io.ktor.plugin") version "3.4.0"    id("org.jetbrains.kotlinx.kover") version "0.9.7"    id("io.gitlab.arturbosch.detekt") version "1.23.8"}
group = "com.example"version = "1.0.0"
kotlin {    jvmToolchain(21)}
dependencies {    // Ktor    implementation("io.ktor:ktor-server-core:3.4.0")    implementation("io.ktor:ktor-server-netty:3.4.0")    implementation("io.ktor:ktor-server-content-negotiation:3.4.0")    implementation("io.ktor:ktor-serialization-kotlinx-json:3.4.0")
    // Exposed    implementation("org.jetbrains.exposed:exposed-core:1.0.0")    implementation("org.jetbrains.exposed:exposed-dao:1.0.0")    implementation("org.jetbrains.exposed:exposed-jdbc:1.0.0")    implementation("org.jetbrains.exposed:exposed-kotlin-datetime:1.0.0")
    // Koin    implementation("io.insert-koin:koin-ktor:4.2.0")
    // Coroutines    implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.10.2")
    // Test    testImplementation("io.kotest:kotest-runner-junit5:6.1.4")    testImplementation("io.kotest:kotest-assertions-core:6.1.4")    testImplementation("io.kotest:kotest-property:6.1.4")    testImplementation("io.mockk:mockk:1.14.9")    testImplementation("io.ktor:ktor-server-test-host:3.4.0")    testImplementation("org.jetbrains.kotlinx:kotlinx-coroutines-test:1.10.2")}
tasks.withType<Test> {    useJUnitPlatform()}
detekt {    config.setFrom(files("config/detekt/detekt.yml"))    buildUponDefaultConfig = true}

Hata İşleme Kalıpları

Domain Operasyonları İçin Result Tipi

kotlin
// İyi: Kotlin'in Result'ını veya özel sealed class kullansuspend fun createUser(request: CreateUserRequest): Result<User> = runCatching {    require(request.name.isNotBlank()) { "Name cannot be blank" }    require('@' in request.email) { "Invalid email format" }
    val user = User(        id = UserId(UUID.randomUUID().toString()),        name = request.name,        email = Email(request.email),    )    userRepository.save(user)    user}
// İyi: Result'ları zincirleval displayName = createUser(request)    .map { it.name }    .getOrElse { "Unknown" }

require, check, error

kotlin
// İyi: Net mesajlarla ön koşullarfun withdraw(account: Account, amount: Money): Account {    require(amount.value > 0) { "Amount must be positive: $amount" }    check(account.balance >= amount) { "Insufficient balance: ${account.balance} < $amount" }
    return account.copy(balance = account.balance - amount)}

Hızlı Referans: Kotlin İdiyomları

İdiyomAçıklama
val over varImmutable değişkenleri tercih et
data classequals/hashCode/copy ile value objeler için
sealed class/interfaceKısıtlı tip hiyerarşileri için
value classSıfır maliyetli tip güvenli sarmalayıcılar için
Expression whenExhaustive pattern matching
Safe call ?.Null-safe member erişimi
Elvis ?:Nullable'lar için varsayılan değer
let/apply/also/run/withTemiz kod için scope fonksiyonlar
Extension fonksiyonlarInheritance olmadan davranış ekle
copy()Data class'larda immutable güncellemeler
require/checkÖn koşul assertion'ları
Coroutine async/awaitYapılandırılmış concurrent execution
FlowCold reactive stream'ler
sequenceLazy evaluation
Delegation byInheritance olmadan implementasyonu yeniden kullan

Kaçınılması Gereken Anti-Kalıplar

kotlin
// Kötü: Nullable tipleri zorla açmaval name = user!!.name
// Kötü: Java'dan platform tipi sızıntısıfun getLength(s: String) = s.length // Güvenlifun getLength(s: String?) = s?.length ?: 0 // Java'dan null'ları işle
// Kötü: Mutable data class'lardata class MutableUser(var name: String, var email: String)
// Kötü: Kontrol akışı için exception kullanmatry {    val user = findUser(id)} catch (e: NotFoundException) {    // Beklenen durumlar için exception kullanma}
// İyi: Nullable dönüş veya Result kullanval user: User? = findUserOrNull(id)
// Kötü: Coroutine scope'u görmezden gelmeGlobalScope.launch { /* GlobalScope'tan kaçın */ }
// İyi: Yapılandırılmış eşzamanlılık kullancoroutineScope {    launch { /* Uygun şekilde scope edilmiş */ }}
// Kötü: Derin iç içe scope fonksiyonlaruser?.let { u ->    u.address?.let { a ->        a.city?.let { c -> process(c) }    }}
// İyi: Doğrudan null-safe zinciruser?.address?.city?.let { process(it) }

Hatırla: Kotlin kodu kısa ama okunabilir olmalı. Güvenlik için tip sisteminden yararlanın, immutability tercih edin ve eşzamanlılık için coroutine'ler kullanın. Şüpheye düştüğünüzde, derleyicinin size yardım etmesine izin verin.

來源與署名

來源:affaan-m/ECC位於docs/tr/skills/kotlin-patterns提交ef648e0

授權條款: 無授權條款

內容歸原作者所有。SourceWeft 從公開儲存庫中收錄這些內容。

檢舉或申請下架