Kotlin dla Androida: podstawy składni i możliwości

Autor: IT Sectr Opublikowano: 2026-02-10 Czas czytania: 8 min

Kotlin — statycznie typowany język programowania od JetBrains, działający na JVM i oficjalnie wspierany przez Google do tworzenia aplikacji na Androida od 2017 roku. Kotlin jest w pełni kompatybilny z Javą, ma zwięzłą składnię i wbudowane null-bezpieczeństwo. Kotlin Documentation — kompletny przewodnik po języku i standardowej bibliotece.

Najważniejsze

  • Kotlin — statycznie typowany język JVM od JetBrains ze zwięzłą składnią i null-bezpieczeństwem
  • Null safety — kompilator rozróżnia typy nullable (String?) i non-null (String), eliminując NullPointerException
  • Data classes — automatyczne generowanie equals, hashCode, toString, copy i componentN
  • Extension functions — dodawanie metod do istniejących klas bez dziedziczenia przez statyczne wywołania
  • Coroutines — programowanie asynchroniczne w stylu sekwencyjnym przez suspend-funkcje bez blokowania wątków

Czym jest Kotlin?

Kotlin — statycznie typowany język programowania stworzony przez firmę JetBrains (twórcę IntelliJ IDEA) i wydany w 2016 roku na licencji Apache 2.0. Kotlin kompiluje się do kodu bajtowego JVM, JavaScript i kodu natywnego (przez Kotlin/Native). Głównym obszarem zastosowania jest tworzenie aplikacji na Androida, aplikacji serwerowych i projektów wieloplatformowych.

Google ogłosiło Kotlin oficjalnym językiem tworzenia aplikacji na Androida na Google I/O 2017. Według danych Google (Android Developer Blog, 2026), ponad 85% nowych projektów w Google Play używa Kotlina. Język jest również aktywnie wykorzystywany w programowaniu serwerowym (Spring Boot, Ktor) i w projektach wieloplatformowych (Kotlin Multiplatform Mobile).

Kotlin jest w pełni kompatybilny z Javą — można wywoływać kod Javy z Kotlina i odwrotnie w ramach jednego projektu. Narzędzia do budowania (Gradle, Maven) obsługują oba języki, co umożliwia stopniową migrację z Javy na Kotlin bez przestojów w rozwoju.

Dlaczego Kotlin jest popularniejszy od Javy dla Androida

Główne powody: zwięzłość — Kotlin wymaga średnio o 40% mniej linii kodu niż Java do rozwiązania tego samego zadania. Null- bezpieczeństwo — kompilator zabrania używania typów nullable bez sprawdzenia. Możliwości funkcyjne — funkcje wyższego rzędu, lambdy, extension functions i coroutines sprawiają, że kod jest bardziej wyrazisty i bezpieczniejszy.

Podstawy składni

Podstawowa składnia Kotlina łączy zwięzłość z jawnością. Zmienne deklaruje się przez val (immutable) i var (mutable). Kompilator używa type inference, ale jawne określenie typu jest obsługiwane. Funkcje deklaruje się słowem kluczowym fun.

kotlin
package com.example.intro

// Stałe i zmienne
val appName: String = "KotlinApp"  // niezmienna
var version = 1.0  // zmienna, typ wywnioskowany

// Funkcja z expression body
fun sum(a: Int, b: Int) = a + b

// String templates
fun greet(name: String) = "Witaj, $name! Wersja ${appName}_$version"

// Default and named arguments
fun createUser(
    name: String,
    age: Int = 18,
    email: String? = null
)

When-wyrażenie zastępuje switch w Javie i jest bardziej elastyczne: obsługuje sprawdzanie typów, zakresy, warunki i gałęzie bez break. Kompilator sprawdza wyczerpujący zakres dla enum i sealed-klas. Smart casts automatycznie rzutują typy po sprawdzeniu is, co eliminuje jawne rzutowania.

kotlin
fun analyzeValue(value: Any) = when (value) {
    is String -> "Łańcuch o długości ${value.length}"  // smart cast
    is Int -> "Liczba całkowita: $value"
    in 1..10 -> "Liczba w zakresie 1-10"
    else -> "Nieznany typ"
}

Null- bezpieczeństwo i operatory elvisa

Null- bezpieczeństwo — kluczowa cecha Kotlina, eliminująca NullPointerException na poziomie kompilacji. W Kotlinie typy domyślnie nie mogą być nullem. Aby zezwolić na null, dodaj ? do typu: String?. Kompilator wymaga jawnego sprawdzenia każdej nullable wartości.

kotlin
// Typy nullable i non-null
val nonNull: String = "Zawsze nie null"
val nullable: String? = null  // dozwolone

// Safe call — wykonuje się tylko jeśli nie jest nullem
val length: Int? = nullable?.length

// Elvis operator — wartość domyślna
val text: String = nullable ?: "Default text"

// Let — wykonanie bloku z non-null wartością
nullable?.let { value ->
    println("Wartość: $value")
}

Safe call operator (?.) zwraca null, jeśli obiekt przed operatorem jest nullem, i wywołuje metodę/właściwość w przeciwnym razie. Elvis operator (?:) dostarcza wartość domyślną, jeśli lewa strona jest nullem. Not-null assertion (!!) rzuca NullPointerException, jeśli wartość jest nullem — używaj tylko gdy jesteś w 100% pewien, że wartość istnieje.

Typy platformowe (platform types) — typy Javy z wywoływanego kodu Javy, których Kotlin nie może oznaczyć jako nullable lub non-null. Typ wyświetla się jako String! (z wykrzyknikiem). Deweloper sam odpowiada za null- bezpieczeństwo podczas pracy z kodem Javy.

Data-klasy i destrukturyzacja

Data-klasy w Kotlinie automatycznie generują equals(), hashCode(), toString(), copy() i componentN(). Eliminuje to boilerplate modeli Javy (POJO) i czyni kod czystszym. Deklaracja data class zajmuje jedną linię zamiast 20-30 w Javie.

kotlin
data class User(
    val id: Long,
    val name: String,
    val email: String,
    val age: Int? = null
)

// Użycie
val user = User(1, "Anna", "anna@example.com")
val updatedUser = user.copy(age = 25)

// Destrukturyzacja
val (id, name) = user
println("Użytkownik #$id: $name")

Destrukturyzacja pozwala rozłożyć data class na zmienne w jednej linii. Jest to wygodne przy pracy z parami, trójkami i innymi wartościami złożonymi. Destrukturyzacja jest obsługiwana dla data-klas, standardowych kolekcji (List, Map) i dowolnych klas z operator fun componentN().

Funkcje rozszerzające

Extension functions — mechanizm Kotlina do dodawania nowych metod do istniejących klas bez dziedziczenia. Rozszerzenia kompilują się do statycznych metod z parametrem receiver, więc dziedziczenie nie jest wymagane, a wirtualność nie jest obsługiwana.

kotlin
// Extension function dla String
fun String.isEmail(): Boolean {
    return this.contains("@") && this.contains(".")
}

// Extension property
val String.isPhoneNumber: Boolean
    get() = this.matches(Regex("^\\+?[\\d-]{10,15}$"))

// Generic extension dla kolekcji
fun List<Int>.sumOfEvens(): Int {
    return this.filter { it % 2 == 0 }.sum()
}

// Użycie
println("test@mail.com".isEmail())  // true

Rozszerzenia są szeroko stosowane w Android SDK i bibliotekach. Na przykład Activity extensions w Android KTX to extension functions dla Activity, Fragment, View i innych klas. Rozszerzenia mogą być deklarowane jako funkcje top-level w pliku lub jako składowe klasy (member extensions).

Coroutines do programowania asynchronicznego

Coroutines — to mechanizm programowania asynchronicznego w Kotlinie, pozwalający pisać nieblokujący kod w stylu sekwencyjnym. Coroutine wstrzymuje wykonanie na suspend-funkcji bez blokowania wątku i wznawia działanie po zakończeniu operacji. To alternatywa dla łańcuchów callbacków RxJava i AsyncTask.

kotlin
import kotlinx.coroutines.*

// Suspend-funkcja — może się wstrzymywać
suspend fun fetchUserData(userId: Int): User {
    // delay — suspend-funkcja, nie blokuje wątku
    delay(500)
    return User(userId, "User $userId", "user@example.com")
}

// Uruchomienie w coroutine
fun loadData() {
    CoroutineScope(Dispatchers.Main).launch {
        val user = fetchUserData(1)  // wstrzymanie tutaj
        updateUI(user)  // kontynuacja na głównym wątku
    }
}

Dispatchers określają pulę wątków dla coroutine: Dispatchers.Main (wątek UI), Dispatchers.IO (operacje sieciowe/dyskowe), Dispatchers.Default (zadania CPU-intensywne). Structured concurrency gwarantuje, że coroutine nie pozostanie aktywna po zakończeniu scope — zapobiega to wyciekom pamięci.

kotlin
// Równoległe uruchamianie przez async/await
suspend fun loadDashboard(): Dashboard = coroutineScope {
    val user = async { fetchUserData(1) }
    val orders = async { fetchOrders(1) }
    val stats = async { fetchStats() }
    
    Dashboard(user.await(), orders.await(), stats.await())
}

Kotlin kontra Java: porównanie

Wybór między Kotlinem a Javą dla nowego projektu na Androida — fundamentalna decyzja architektoniczna. Kotlin oferuje bardziej nowoczesną składnię i wbudowane mechanizmy bezpieczeństwa, Java — szerszą pulę programistów i dojrzałe biblioteki.

CechaKotlinJava
Null- bezpieczeństwoWbudowane (nullable/non-null)Brak (adnotacje @Nullable)
Ilość kodu−40% względem JavyBoilerplate (getters/setters)
Data-klasydata class (jedna linia)POJO z Lombok lub ręcznie
AsynchronicznośćCoroutines (suspend/await)CompletableFuture, RxJava
Extension functionsWbudowaneTylko przez klasy narzędziowe
Smart castsPo sprawdzeniu isJawne rzutowanie (Type) obj
Kompatybilność wsteczna100% z Javą

Wydajność Kotlina i Javy jest porównywalna — oba kompilują się do kodu bajtowego JVM. Kotlin czasami dodaje mikro-narzut na coroutines i inlining, ale jest to nieznaczne dla aplikacji mobilnych. Google i JetBrains aktywnie inwestują w Kotlina: Kotlin Multiplatform, Kotlin/Wasm i poprawę wydajności kompilatora K2.

Często zadawane pytania

Czym Kotlin różni się od Javy?

Kotlin jest krótszy od Javy o 40% — mniej boilerplate'u. Kotlin dodaje null- bezpieczeństwo, data-klasy, extension functions, coroutines, smart casts, when-wyrażenia. Pełna kompatybilność z Javą: oba języki działają na JVM i mogą być używane w jednym projekcie bez konfliktów.

Jak działa null- bezpieczeństwo w Kotlinie?

Typy domyślnie są non-null. Dla nullable używamy ?: String?. Kompilator zabrania bezpośredniego odwoływania się do nullable wartości. Safe call (?.) zwraca null przy null receiver. Elvis operator (?:) ustawia wartość domyślną. !! — wymuszone wyciągnięcie z możliwym wyjątkiem.

Czym są coroutines w Kotlinie?

Coroutines — lekkie wątki, pozwalające pisać asyn chroniczny kod sekwencyjnie. suspend-funkcje wstrzymują się bez blokowania wątku. launch i async uruchamiają coroutines w CoroutineScope. Dispatchers.IO dla zapytań sieciowych, Dispatchers.Main dla aktualizacji UI.

Czym są data-klasy w Kotlinie?

data class automatycznie generuje equals(), hashCode(), toString(), copy() i componentN(). Przykład: data class User(val name: String, val age: Int). Destrukturyzacja przez val (name, age) = user. Odpowiednik record w Javie 14+, ale z dodatkową metodą copy().

Jak działają funkcje rozszerzające (extension functions)?

Extension functions dodają metody do istniejących klas: fun String.isEmail(): Boolean. Kompilator zamienia je na statyczne wywołania z parametrem receiver. Dziedziczenie nie jest wymagane. Rozszerzenia są szeroko używane w Android KTX: view.showToast(), activity.viewModels().

Podsumowanie

  • Kotlin — statycznie typowany język JVM od JetBrains, oficjalny język Androida od 2017 roku
  • Null safety — typy nullable/non-null, safe call (?.), elvis (??), let-bloki do bezpiecznej pracy z nullable
  • Data classes — automatyczne generowanie equals, hashCode, toString, copy i destrukturyzacja
  • Extension functions — dodawanie metod do dowolnych klas bez dziedziczenia, kompilowane do statycznych wywołań
  • Coroutines — asynchroniczny kod w stylu sekwencyjnym z suspend-funkcjami, launch/async i Dispatchers
  • Porównanie z Javą — −40% kodu, null- bezpieczeństwo, smart casts, when-wyrażenia i 100% kompatybilność z Javą
  • Kotlin Multiplatform — Kotlin jest używany nie tylko dla Androida, ale także dla iOS (KMM) i serwerów (Ktor, Spring)

Opracujemy aplikację mobilną pod klucz

IT Sectr tworzy aplikacje na iOS i Androida dla startupów i firm od 2017 roku. Doradzimy Ci i zaproponujemy najlepsze rozwiązanie.

Omów projekt

Przeczytaj również