0Pricing
Kotlin Academy · Lekcja

Sprzątanie za pomocą finally i NonCancellable

Zwalniaj zasoby w anulowanych korutynach za pomocą finally i withContext(NonCancellable).

Sprzątanie za pomocą finally i NonCancellable to bezpłatna lekcja Kotlin Academy na CoddyKit. To lekcja 3 z 4. Możesz przeczytać całą lekcję poniżej za darmo — a potem ćwiczyć ją interaktywnie w przeglądarce z wbudowanym edytorem kodu i tutorem AI dostępnym 24/7. To część ścieżki edukacyjnej Kotlin Academy, a Twój postęp synchronizuje się między webem a aplikacją CoddyKit. Kurs Kotlin Academy zawiera 4 lekcji w sumie.

Anulowanie i finally

Po anulowaniu korutyny punkty zawieszenia zgłaszają CancellationException. Kod w blokach finally jest zawsze wykonywany — jednak sam blok finally działa w anulowanym kontekście korutyny.

import kotlinx.coroutines.*
fun main() = runBlocking {
    val job = launch {
        try {
            delay(1000)
        } finally {
            println("finally: cleaning up")
        }
    }
    delay(50)
    job.cancel()
    job.join()
}

Problem: zawieszanie w finally

Jeśli spróbujesz wywołać delay lub wykonać inne zawieszenie wewnątrz bloku finally anulowanej korutyny, wywołanie natychmiast zgłosi wyjątek, ponieważ kontekst jest już anulowany.

import kotlinx.coroutines.*
fun main() = runBlocking {
    val job = launch {
        try {
            delay(1000)
        } finally {
            // delay(100) // throws CancellationException here!
            println("Sync cleanup OK; async cleanup needs NonCancellable")
        }
    }
    delay(50); job.cancel(); job.join()
}

withContext(NonCancellable)

Wywołania zawieszające w bloku finally należy opakować w withContext(NonCancellable), aby wykonać je w kontekście, którego nie można anulować, nawet po anulowaniu rodzica.

import kotlinx.coroutines.*
fun main() = runBlocking {
    val job = launch {
        try {
            delay(1000)
        } finally {
            withContext(NonCancellable) {
                delay(100)  // OK: runs despite cancellation
                println("Async cleanup complete")
            }
        }
    }
    delay(50); job.cancel(); job.join()
}

Kiedy używać NonCancellable

Używaj NonCancellable do zamykania połączeń z bazą danych, opróżniania logów, wysyłania zdarzeń analitycznych oraz wszelkich asynchronicznych operacji porządkowych, które muszą zostać ukończone niezależnie od anulowania.

import kotlinx.coroutines.*
suspend fun closeConnection() {
    println("Closing DB connection...")
    delay(50) // simulate async close
    println("Connection closed")
}
fun main() = runBlocking {
    val job = launch {
        try { delay(1000) }
        finally { withContext(NonCancellable) { closeConnection() } }
    }
    delay(50); job.cancel(); job.join()
}

NonCancellable nie jest zakresem

NonCancellable jest obiektem typu Job, który można przekazać do withContext. Nie używaj go bezpośrednio jako zakresu korutyny — stosuj go wyłącznie podczas porządkowania zasobów w bloku finally.

import kotlinx.coroutines.*
fun main() = runBlocking {
    // WRONG usage:
    // launch(NonCancellable) { ... } // launches a coroutine that cannot be cancelled
    // RIGHT usage:
    launch {
        try { delay(500) }
        finally {
            withContext(NonCancellable) {
                println("Safe cleanup")
            }
        }
    }.also { delay(50); it.cancel(); it.join() }
}

Zwalnianie wielu zasobów

Połącz wiele operacji porządkowych w jednym bloku withContext(NonCancellable).

import kotlinx.coroutines.*
fun main() = runBlocking {
    launch {
        try {
            delay(1000)
        } finally {
            withContext(NonCancellable) {
                delay(20); println("Step 1: flush cache")
                delay(20); println("Step 2: close socket")
                delay(20); println("Step 3: log audit")
            }
        }
    }.also { delay(50); it.cancel(); it.join() }
}

Wzorzec try/catch/finally

Połącz try-catch do obsługi błędów biznesowych z finally do porządkowania zasobów — jest to standardowy wzorzec programowania ustrukturyzowanego.

import kotlinx.coroutines.*
fun main() = runBlocking {
    launch {
        try {
            delay(100)
            throw RuntimeException("business error")
        } catch (e: RuntimeException) {
            println("Handling: ${e.message}")
        } finally {
            withContext(NonCancellable) {
                println("Always cleanup")
            }
        }
    }.join()
}

Kolejność porządkowania zasobów

Bloki finally są wykonywane w odwrotnej kolejności zagnieżdżenia. Zewnętrzny blok try-finally jest wykonywany po wewnętrznych, tak samo jak w zwykłym kodzie Java/Kotlin.

import kotlinx.coroutines.*
fun main() = runBlocking {
    launch {
        try {
            try {
                delay(1000)
            } finally { println("Inner cleanup") }
        } finally { println("Outer cleanup") }
    }.also { delay(50); it.cancel(); it.join() }
}

use() dla zasobów AutoCloseable

W przypadku zasobów AutoCloseable używaj rozszerzenia Kotlin use { }, które automatycznie wywołuje close(), nawet w przypadku wyjątków lub anulowania.

import kotlinx.coroutines.*
class Connection : AutoCloseable {
    init { println("Opened") }
    override fun close() { println("Closed") }
    suspend fun query(): String { delay(50); return "result" }
}
fun main() = runBlocking {
    val result = Connection().use { it.query() }
    println(result)
}

Rejestrowanie przyczyny anulowania

W bloku catch lub finally pobierz komunikat o anulowaniu z obiektu CancellationException, aby zarejestrować przyczynę zatrzymania korutyny.

import kotlinx.coroutines.*
fun main() = runBlocking {
    val job = launch {
        try {
            delay(1000)
        } catch (e: CancellationException) {
            println("Cancelled: ${e.message}")
            throw e
        }
    }
    delay(50)
    job.cancel("user navigated away")
    job.join()
}

Porządkowanie CoroutineScope za pomocą invokeOnCompletion

Job.invokeOnCompletion rejestruje wywołanie zwrotne wykonywane po zakończeniu zadania z dowolnej przyczyny — jest to alternatywa dla finally w przypadku porządkowania zasobów na poziomie rodzica.

import kotlinx.coroutines.*
fun main() = runBlocking {
    val job = launch {
        delay(1000)
    }
    job.invokeOnCompletion { cause ->
        if (cause != null) println("Ended with: ${cause::class.simpleName}")
        else println("Completed normally")
    }
    delay(50)
    job.cancel()
    job.join()
}

Szybkie sprawdzenie

Jaki jest cel użycia withContext(NonCancellable) w bloku finally?

Podsumowanie

finally jest zawsze wykonywany po anulowaniu. Wywołania zawieszające wewnątrz finally należy opakować w withContext(NonCancellable), aby zostały ukończone mimo anulowania. Używaj use { } dla zasobów AutoCloseable.

Często zadawane pytania

Czy lekcja „Sprzątanie za pomocą finally i NonCancellable” jest bezpłatna?

Tak — pełny tekst „Sprzątanie za pomocą finally i NonCancellable” jest dostępny za darmo tutaj w sieci. Aby ćwiczyć ją interaktywnie (wbudowany edytor kodu i tutor AI dostępny 24/7) i odblokować resztę kursu Kotlin Academy, przejdź na CoddyKit PRO. Kurs Kotlin Academy zawiera 4 lekcji w sumie.

Co nauczysz się w „Sprzątanie za pomocą finally i NonCancellable”?

Zwalniaj zasoby w anulowanych korutynach za pomocą finally i withContext(NonCancellable). Ćwiczysz Kotlin Academy z praktycznym kodem, który uruchamiasz bezpośrednio w przeglądarce, a tutor AI dostępny 24/7 odpowiada na Twoje pytania podczas pracy nad lekcją.

Czy potrzebuję doświadczenia, aby zacząć Kotlin Academy?

Nie wymagamy żadnego doświadczenia. Kotlin Academy w CoddyKit jest strukturyzowany dla początkujących i zaawansowanych użytkowników, więc możesz zacząć tutaj lub od początku i uczyć się w swoim tempie. To lekcja 3 z 4.

Ile czasu zajmuje lekcja „Sprzątanie za pomocą finally i NonCancellable”?

Większość lekcji CoddyKit trwa około 5–10 minut. Każda lekcja to mały, interaktywny krok, dzięki czemu robisz systematyczne postępy i zawsze wracasz dokładnie do tego samego miejsca — na webie i w aplikacji.

Czy mogę pisać i uruchamiać kod w tej lekcji Kotlin Academy?

Tak. Każda lekcja Kotlin Academy zawiera wbudowany edytor kodu, więc piszesz i uruchamiasz prawdziwy kod bezpośrednio w przeglądarce i od razu otrzymujesz sprzężenie zwrotne od AI — bez konfiguracji na komputerze.

Wszystkie lekcje w tym kursie

  1. Kooperatywne anulowanie: isActive i ensureActive
  2. withTimeout i withTimeoutOrNull
  3. Sprzątanie za pomocą finally i NonCancellable
  4. Propagacja anulowania w hierarchiach korutyn
← Powrót do Kotlin Academy