catch และ onCompletion: การจัดการข้อผิดพลาดใน Flow
ดักจับ exception จากต้นทางและตอบสนองต่อเหตุการณ์ที่ Flow ทำงานเสร็จ
catch และ onCompletion: การจัดการข้อผิดพลาดใน Flow เป็นบทเรียน Kotlin Academy ฟรีบน CoddyKit นี่คือบทเรียนที่ 2 จากทั้งหมด 4 บทเรียน คุณสามารถอ่านบทเรียนทั้งหมดด้านล่างฟรี — จากนั้นลองปฏิบัติด้วยตัวคุณเองในเบราว์เซอร์พร้อมตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7 บทเรียนนี้เป็นส่วนหนึ่งของเส้นทางการเรียน Kotlin Academy และความก้าวหน้าของคุณจะซิงค์ข้ามเว็บและแอป CoddyKit คอร์ส Kotlin Academy มีบทเรียนทั้งหมด 4 บทเรียน
พื้นฐานข้อยกเว้นใน Flow
ข้อยกเว้นในโฟลว์จะทำให้โฟลว์สิ้นสุด หากไม่จัดการ ข้อยกเว้นจะแพร่ไปยังผู้รวบรวมข้อมูลและโฟลว์จะจบลง
import kotlinx.coroutines.*
import kotlinx.coroutines.flow.*
fun main() = runBlocking {
try {
flow {
emit(1)
throw RuntimeException("stream error")
emit(2)
}.collect { println(it) }
} catch (e: Exception) {
println("Caught: ${e.message}")
}
}ตัวดำเนินการ catch
catch จัดการข้อยกเว้นจากต้นทาง และสามารถส่งค่าทางเลือกออกมาหรือโยนข้อยกเว้นซ้ำได้ แต่จะไม่จับข้อยกเว้นที่ผู้รวบรวมข้อมูลเป็นผู้โยน
import kotlinx.coroutines.*
import kotlinx.coroutines.flow.*
fun main() = runBlocking {
flow {
emit(1)
throw RuntimeException("oops")
}.catch { e ->
println("Caught: ${e.message}")
emit(-1) // fallback value
}.collect { println(it) } // 1, then -1
}catch จัดการเฉพาะข้อยกเว้นจากต้นทาง
catch จะดักจับเฉพาะข้อยกเว้นจากตัวสร้างโฟลว์และตัวดำเนินการต้นทางเท่านั้น ไม่รวมข้อยกเว้นจากแลมบ์ดาของ collect
import kotlinx.coroutines.*
import kotlinx.coroutines.flow.*
fun main() = runBlocking {
try {
flowOf(1, 2, 3)
.catch { e -> println("upstream: ${e.message}") }
.collect {
if (it == 2) throw RuntimeException("collector error") // not caught by catch
println(it)
}
} catch (e: Exception) {
println("Collector exception: ${e.message}")
}
}การโยนข้อยกเว้นซ้ำใน catch
คุณสามารถตรวจสอบข้อยกเว้น แล้วเลือกโยนซ้ำเฉพาะข้อยกเว้นที่ไม่สามารถจัดการได้
import kotlinx.coroutines.*
import kotlinx.coroutines.flow.*
fun main() = runBlocking {
try {
flow {
emit(1)
throw IllegalStateException("state error")
}.catch { e ->
if (e is RuntimeException) { emit(-1); return@catch }
throw e // rethrow unknown exceptions
}.collect { println(it) }
} catch (e: Exception) {
println("Rethrown: ${e.message}")
}
}ตัวดำเนินการ onCompletion
onCompletion จะทำงานเมื่อโฟลว์เสร็จสิ้น ไม่ว่าจะเสร็จตามปกติหรือพร้อมข้อยกเว้น พารามิเตอร์ cause จะไม่เป็นค่าว่างเมื่อเกิดความล้มเหลว
import kotlinx.coroutines.*
import kotlinx.coroutines.flow.*
fun main() = runBlocking {
flowOf(1, 2, 3)
.onCompletion { cause ->
if (cause == null) println("Completed normally")
else println("Failed: ${cause.message}")
}
.collect { println(it) }
}onCompletion เมื่อเกิดข้อผิดพลาด
onCompletion จะทำงานแม้เกิดข้อยกเว้นจากต้นทาง โดยจะได้รับข้อยกเว้นใน cause แต่จะไม่ระงับข้อยกเว้นนั้น ข้อยกเว้นยังคงแพร่ต่อไป
import kotlinx.coroutines.*
import kotlinx.coroutines.flow.*
fun main() = runBlocking {
try {
flow {
emit(1)
throw RuntimeException("error")
}.onCompletion { cause ->
println("onCompletion cause=${cause?.message}")
}.collect { println(it) }
} catch (e: Exception) {
println("outer catch: ${e.message}")
}
}การใช้ catch และ onCompletion ร่วมกัน
ใช้ catch เพื่อกู้คืนการทำงานและส่งค่าทางเลือกออกมา จากนั้นใช้ onCompletion เพื่อบันทึกข้อมูลหรือล้างทรัพยากรไม่ว่าผลลัพธ์จะเป็นอย่างไร
import kotlinx.coroutines.*
import kotlinx.coroutines.flow.*
fun main() = runBlocking {
flow {
emit("ok")
throw RuntimeException("network error")
}.catch { e ->
emit("fallback") // recover
}.onCompletion {
println("Stream done — release resources")
}.collect { println(it) }
}ตัวดำเนินการ retry
retry(n) { ... } จะสมัครรับข้อมูลจากโฟลว์ต้นทางใหม่เมื่อเกิดข้อยกเว้น โดยทำซ้ำได้ไม่เกิน n ครั้ง
import kotlinx.coroutines.*
import kotlinx.coroutines.flow.*
var attempt = 0
fun unstableFlow() = flow {
attempt++
if (attempt < 3) throw RuntimeException("attempt $attempt failed")
emit("success on attempt $attempt")
}
fun main() = runBlocking {
unstableFlow()
.retry(3) { e -> println("retrying: ${e.message}"); true }
.collect { println(it) }
}retryWhen สำหรับตรรกะแบบกำหนดเอง
retryWhen ให้ทั้งข้อยกเว้นและจำนวนครั้งที่ลอง เพื่อให้คุณเพิ่มการหน่วงเวลาแบบทวีคูณหรือกรองว่าข้อยกเว้นใดจะทำให้ลองใหม่
import kotlinx.coroutines.*
import kotlinx.coroutines.flow.*
fun main() = runBlocking {
var n = 0
flow {
if (n++ < 2) throw IOException("IO error")
emit("done")
}.retryWhen { cause, attempt ->
cause is IOException && attempt < 3
}.collect { println(it) }
}ตัวดำเนินการ onStart
onStart จะทำงานก่อนมีการส่งค่าครั้งแรก เหมาะสำหรับแสดงสถานะกำลังโหลดหรือเริ่มต้นทรัพยากรก่อนข้อมูลมาถึง
import kotlinx.coroutines.*
import kotlinx.coroutines.flow.*
fun main() = runBlocking {
flowOf("data")
.onStart { emit("Loading...") }
.onCompletion { emit("Done") }
.collect { println(it) }
}การจัดการข้อผิดพลาดในการเรียก API จริง
ครอบโฟลว์ของที่เก็บข้อมูลด้วย catch เพื่อแปลงข้อยกเว้นเป็นข้อผิดพลาดของโดเมน และใช้ onCompletion เพื่อซ่อนตัวบ่งชี้การโหลด
import kotlinx.coroutines.*
import kotlinx.coroutines.flow.*
sealed class State { object Loading : State(); data class Data(val v: String) : State(); data class Error(val msg: String) : State() }
fun apiFlow(): Flow<String> = flow { delay(50); emit("response") }
fun uiFlow(): Flow<State> = apiFlow()
.map { State.Data(it) as State }
.onStart { emit(State.Loading) }
.catch { e -> emit(State.Error(e.message ?: "unknown")) }
fun main() = runBlocking { uiFlow().collect { println(it) } }ตรวจสอบความเข้าใจอย่างรวดเร็ว
ข้อจำกัดสำคัญของโอเปอเรเตอร์ catch คืออะไร
สรุปทบทวน
การดักจับข้อยกเว้นจัดการข้อยกเว้นจากต้นทางและสามารถส่งค่าทางเลือกได้ ส่วน onCompletion จะทำงานเสมอ ทั้งเมื่อทำงานตามปกติหรือเกิดข้อผิดพลาด เพื่อดำเนินการล้างข้อมูลหรือบันทึกการทำงาน ใช้ร่วมกับ การลองใหม่/retryWhen เพื่อสร้างไปป์ไลน์โฟลว์ที่ทนทาน
คำถามที่พบบ่อย
บทเรียน “catch และ onCompletion: การจัดการข้อผิดพลาดใน Flow” ฟรีหรือไม่
ใช่ — ข้อความเต็มของ “catch และ onCompletion: การจัดการข้อผิดพลาดใน Flow” ฟรีให้อ่านที่นี่บนเว็บ เพื่อปฏิบัติแบบโต้ตอบ (ตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7) และปลดล็อคส่วนที่เหลือของคอร์ส Kotlin Academy ให้อัปเกรดเป็น CoddyKit PRO คอร์ส Kotlin Academy มีบทเรียนทั้งหมด 4 บทเรียน
คุณจะเรียนรู้อะไรในบทเรียน “catch และ onCompletion: การจัดการข้อผิดพลาดใน Flow”
ดักจับ exception จากต้นทางและตอบสนองต่อเหตุการณ์ที่ Flow ทำงานเสร็จ คุณปฏิบัติ Kotlin Academy ด้วยโค้ดที่ใช้งานได้จริงที่คุณเรียกใช้โดยตรงในเบราว์เซอร์ และติวเตอร์ AI ตลอด 24/7 ตอบคำถามของคุณขณะที่คุณไปผ่านบทเรียน
คุณต้องมีประสบการณ์ก่อนที่จะเริ่มเรียน Kotlin Academy หรือไม่
ไม่จำเป็นต้องมีประสบการณ์มาก่อน Kotlin Academy บน CoddyKit ออกแบบมาสำหรับผู้เริ่มต้นไปจนถึงผู้เรียนขั้นสูง คุณสามารถเริ่มต้นที่นี่หรือเริ่มจากตัวแรกและเรียนด้วยความเร็วของคุณเอง นี่คือบทเรียนที่ 2 จากทั้งหมด 4 บทเรียน
บทเรียน “catch และ onCompletion: การจัดการข้อผิดพลาดใน Flow” ใช้เวลานานแค่ไหน
บทเรียน CoddyKit ส่วนใหญ่ใช้เวลาประมาณ 5–10 นาที แต่ละบทเรียนจึงสั้นและเป็นแบบโต้ตอบ คุณสามารถก้าวหน้าอย่างต่อเนื่องและกลับมาเรียนต่อจากตรงที่เพิ่งหยุดบนเว็บและแอปได้เลย
ฉันเขียนและรันโค้ดในบทเรียน Kotlin Academy นี้ได้ไหม
ได้ บทเรียน Kotlin Academy ทุกบทมีตัวแก้ไขโค้ดในตัว คุณจึงเขียนและรันโค้ดจริงได้เลยในเบราว์เซอร์ และได้รับข้อเสนอแนะจาก AI ในทันที — ไม่ต้องติดตั้งในเครื่องของคุณ
บทเรียนทั้งหมดในหลักสูตรนี้
- ตัวดำเนินการ Flow: map, filter, transform และ take
- catch และ onCompletion: การจัดการข้อผิดพลาดใน Flow
- combine และ zip: รวม Flow หลายสาย
- flowOn และ buffer: บริบทและแรงดันย้อนกลับ