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
- Kooperatywne anulowanie: isActive i ensureActive
- withTimeout i withTimeoutOrNull
- Sprzątanie za pomocą finally i NonCancellable
- Propagacja anulowania w hierarchiach korutyn