17-bo‘lim
Istisnolar va Result
try/catch/finally, try ning ifoda ekani, o'z istisno sinfingiz, require va check, Nothing turi hamda runCatching bilan Result.
Ushbu bo‘lim mundarijasi
Istisno - dastur ishlayotganda yuz beradigan kutilmagan holat. Kotlin da ular Java dagidek ishlaydi, lekin bir muhim farq bilan.
try va catch #
fun main() {
try {
val son = "salom".toInt()
println(son)
} catch (e: NumberFormatException) {
println("Bu son emas")
}
println("Dastur davom etmoqda")
}
Bu son emas
Dastur davom etmoqda
try - bu ifoda #
fun oqi(matn: String): Int = try {
matn.toInt()
} catch (e: NumberFormatException) {
-1
}
fun main() {
println(oqi("456"))
println(oqi("salom"))
val natija = try {
10 / 0
} catch (e: ArithmeticException) {
0
}
println(natija)
}
456
-1
0
if va when kabi, try ham qiymat qaytaradi. Blokning oxirgi
ifodasi natija bo'ladi.
Yuqoridagi oqi funksiyasi ishlaydi, lekin Kotlin da uni shunday
yozish kerak:
fun oqi(matn: String): Int = matn.toIntOrNull() ?: -1
Qisqaroq, tezroq (istisno ko'tarish qimmat amal) va o'qishliroq.
Umumiy qoida: kutilgan holat uchun istisno ishlatmang. Foydalanuvchi noto'g'ri yozishi - bu kutilgan holat.
Bir necha catch va finally #
fun sinov(royxat: List<Int>, indeks: Int, bolovchi: Int) {
try {
println(royxat[indeks] / bolovchi)
} catch (e: ArithmeticException) {
println("Nolga bo'lib bo'lmaydi")
} catch (e: IndexOutOfBoundsException) {
println("Bunday indeks yo'q")
} catch (e: Exception) {
println("Boshqa xato: ${e::class.simpleName}")
} finally {
println(" finally bajarildi")
}
}
fun main() {
val sonlar = listOf(10, 20, 30)
sinov(sonlar, 0, 2)
sinov(sonlar, 1, 0)
sinov(sonlar, 99, 2)
}
5
finally bajarildi
Nolga bo'lib bo'lmaydi
finally bajarildi
Bunday indeks yo'q
finally bajarildi
catch bloklari yuqoridan pastga tekshiriladi, shuning uchun
Exception eng oxirida bo'lishi kerak.
finally esa har doim bajariladi.
Kotlin da tekshiriladigan istisnolar yo'q #
Java da ba'zi istisnolarni majburan ushlash kerak: metod
throws IOException deb e'lon qilgan bo'lsa, chaqiruvchi uni
try/catch ga olishi yoki o'zi ham throws yozishi shart.
Kotlin da bunday majburiyat yo'q. Har qanday istisnoni ushlash ixtiyoriy.
Sababi tajribadan kelib chiqqan: Java dasturchilari majburiyatdan
qutulish uchun bo'sh catch bloklari yozib tashlashardi - bu esa
xatolarni jimgina yutib yuborardi va holatni yomonlashtirardi.
Buning evaziga mas'uliyat sizga o'tadi: qaysi funksiya istisno ko'tarishi mumkinligini hujjatdan yoki koddan bilishingiz kerak.
Istisno ko'tarish #
fun yoshTekshir(yosh: Int) {
if (yosh < 0) {
throw IllegalArgumentException("Yosh manfiy bo'lmaydi: $yosh")
}
println("Qabul qilindi: $yosh")
}
fun main() {
yoshTekshir(25)
try {
yoshTekshir(-5)
} catch (e: IllegalArgumentException) {
println("Ushlandi: ${e.message}")
}
}
Qabul qilindi: 25
Ushlandi: Yosh manfiy bo'lmaydi: -5
require, check va error #
class Hisob(val egasi: String, boshlangich: Int) {
var qoldiq = boshlangich
private set
init {
require(egasi.isNotBlank()) { "Egasi ko'rsatilmagan" }
require(boshlangich >= 0) { "Boshlang'ich summa manfiy" }
}
fun yech(summa: Int) {
require(summa > 0) { "Summa musbat bo'lishi kerak" }
check(summa <= qoldiq) { "Qoldiq yetarli emas" }
qoldiq -= summa
}
}
fun sinab(nom: String, ish: () -> Unit) {
try {
ish()
println("$nom: muvaffaqiyat")
} catch (e: Exception) {
println("$nom: ${e::class.simpleName} - ${e.message}")
}
}
fun main() {
val h = Hisob("Husanboy", 500000)
sinab("to'g'ri") { h.yech(100000) }
sinab("manfiy") { h.yech(-5) }
sinab("ko'p") { h.yech(9000000) }
sinab("bo'sh ism") { Hisob("", 100) }
println("Qoldiq: ${h.qoldiq}")
}
to'g'ri: muvaffaqiyat
manfiy: IllegalArgumentException - Summa musbat bo'lishi kerak
ko'p: IllegalStateException - Qoldiq yetarli emas
bo'sh ism: IllegalArgumentException - Egasi ko'rsatilmagan
Qoldiq: 400000
| Funksiya | Qachon | Qaysi istisno |
|---|---|---|
require | Argument noto'g'ri | IllegalArgumentException |
check | Obyekt holati noto'g'ri | IllegalStateException |
error(...) | Bo'lmasligi kerak bo'lgan holat | IllegalStateException |
Farqni eslab qolish oson: require - "chaqiruvchi xato qildi",
check - "hozirgi holatda bu amalni bajarib bo'lmaydi".
O'z istisno sinfingiz #
class QoldiqYetmadiException(val yetishmayotgan: Int) :
Exception("Hisobda $yetishmayotgan so'm yetishmayapti")
class Hisob(private var qoldiq: Int) {
fun yech(summa: Int) {
if (summa > qoldiq) throw QoldiqYetmadiException(summa - qoldiq)
qoldiq -= summa
println("Yechildi. Qoldiq: $qoldiq")
}
}
fun main() {
val h = Hisob(500000)
try {
h.yech(200000)
h.yech(900000)
} catch (e: QoldiqYetmadiException) {
println(e.message)
println("Yetishmayotgan: ${e.yetishmayotgan}")
}
}
Yechildi. Qoldiq: 300000
Hisobda 600000 so'm yetishmayapti
Yetishmayotgan: 600000
O'z sinfingizning asosiy foydasi - qo'shimcha ma'lumot tashiy olishi. Xabar matnidan son ajratib olishga urinmang; kerakli qiymatni xossa qilib qo'shing.
Nothing turi #
fun xatoBilanTugat(xabar: String): Nothing =
throw IllegalStateException(xabar)
fun oqi(matn: String?): String {
val toza = matn?.trim() ?: xatoBilanTugat("qiymat berilmadi")
return toza.uppercase()
}
fun main() {
println(oqi(" salom "))
try {
oqi(null)
} catch (e: IllegalStateException) {
println("Ushlandi: ${e.message}")
}
}
SALOM
Ushlandi: qiymat berilmadi
Nothing - "bu funksiya hech qachon qaytmaydi" degani.
Kompilyator buni biladi, shuning uchun ?: dan keyin toza ni
String (String? emas) deb hisoblaydi.
runCatching va Result #
fun main() {
val a = runCatching { "456".toInt() }
val b = runCatching { "salom".toInt() }
println(a.isSuccess)
println(b.isFailure)
println(a.getOrNull())
println(b.getOrNull())
println(b.getOrDefault(-1))
println(a.map { it * 2 }.getOrNull())
val natija = b.fold(
onSuccess = { "OK: $it" },
onFailure = { "Xato: ${it::class.simpleName}" }
)
println(natija)
}
true
true
456
null
-1
912
Xato: NumberFormatException
runCatching istisnoni qiymatga aylantiradi. Natija - Result<T>
obyekti, uni try/catch siz tekshirish mumkin.
runCatching har qanday Throwable ni ushlaydi -
OutOfMemoryError ni ham.
Bunday xatolarni ushlab, davom etishga urinish odatda noto'g'ri: dastur allaqachon ishonchsiz holatda.
Shuning uchun runCatching ni kutilgan, aniq xatolar uchun
ishlating - fayl o'qish, tarmoq so'rovi, tahlil qilish kabi. Butun
dasturni unga o'rab qo'ymang.
Xatolarni boshqarishni tanlash #
| Holat | To'g'ri yo'l |
|---|---|
| Foydalanuvchi noto'g'ri son yozdi | toIntOrNull() |
| Qiymat bo'lmasligi mumkin | null qaytaring |
| Argument noto'g'ri | require |
| Obyekt holati noto'g'ri | check |
| Fayl yoki tarmoq | try/catch yoki runCatching |
| Dasturchining xatosi | Ushlamang - kod tuzatilsin |
try {
muhimAmal()
} catch (e: Exception) {
}
Bu eng yomon namuna: xato yuz berdi, lekin hech kim bilmaydi. Dastur "ishlayotgandek" ko'rinadi, aslida esa ish bajarilmagan.
Hech bo'lmaganda xabarni jurnalga yozing. Agar xatoni haqiqatan e'tiborsiz qoldirish kerak bo'lsa, nima uchun ekanini izohda yozib qo'ying.
- Nolga bo'lishni
try/catchbilan ushlang. tryni ifoda sifatida ishlatib, natijani o'zgaruvchiga oling.- O'sha ishni
toIntOrNull()bilan qayta yozing. finallyhar doim bajarilishini isbotlang.requirevacheckfarqini bitta sinfda ko'rsating.- O'z istisno sinfingizni qo'shimcha xossa bilan yozing.
Nothingqaytaradigan funksiya yozing.runCatchingbilan xatoni qiymatga aylantiring.Result.foldbilan ikkala holatni ishlang.- Qaysi holatda istisno, qaysida
nullto'g'ri kelishini yozing.
Xulosa #
tryKotlin da ifoda - u qiymat qaytaradi.catchbloklari aniqrog'idan umumiyga;finallyhar doim bajariladi.- Kotlin da tekshiriladigan istisnolar yo'q - mas'uliyat sizda.
require- argument uchun,check- holat uchun.- O'z istisno sinfingiz qo'shimcha ma'lumot tashiy oladi.
Nothing- hech qachon qaytmaydigan funksiya turi.runCatchingistisnoniResultqiymatiga aylantiradi, lekin hamma narsani ushlaydi.- Kutilgan holat uchun istisno emas,
nullyokiOrNullfunksiyalarini ishlating.
Keyingi bo'limda fayllar bilan ishlaymiz.
O‘qish tarixini saqlamoqchimisiz?
Tizimga kirsangiz, tugatgan bo‘limlaringiz saqlanadi va qoldirgan joyingizdan davom etasiz.
Xatolik topdingizmi?
Imlo xatosi, ishlamaydigan kod yoki noto‘g‘ri ma‘lumotni ko‘rsangiz - bizga xabar bering. Har bir xabar administrator tomonidan ko‘rib chiqiladi.