Xatolarni tarqatish: bu nima, xatolarni tarqatish mexanizmi va mobil ishlanmada qanday ishlaydi

Muallif: IT Sectr Nashr etilgan: 2026-05-26 O'qish vaqti: 9 daq

Xatolarni tarqatish — xatoning paydo bo'lgan joyidan yuqoriga, chaqiruvlar steki bo'ylab ishlov beruvchiga tarqalish mexanizmi. Funksiya xatoni mustaqil ishlay olmasa, uni istisno (exception), throws deklaratsiyasi yoki qaytarish turi orqali chaqiruvchi tomonga uzatadi. Xatolarni to'g'ri tarqatish mobil ilovalarning barqarorligi uchun juda muhim: ishlanmagan yoki noto'g'ri uzatilgan xatolar qulashlarga olib keladi. Apple Swift Documentation (2026) ma'lumotlariga ko'ra, Swift-da throws orqali avtomatik tarqatish xatoni boilerplate kodsiz istalgan darajaga uzatish imkonini beradi.

Asosiy fikrlar

  • Xatolarni tarqatish — xatoning paydo bo'lgan joyidan stek bo'ylab ishlov beruvchiga, oraliq funksiyalarni chetlab o'tib uzatilishi
  • Swift-da throws orqali avtomatik tarqatish xatoni stekning har bir darajasida aniq kodsiz uzatadi
  • Kotlin va Dart-da qo'lda tarqatish har bir darajada aniq try-catch yoki Result konteynerida uzatishni talab qiladi
  • Java-da tekshirilgan istisnolar imzoda throws orqali tarqatishni majburlaydi, tekshirilmaganlar — e'tiborsiz qoldirishga imkon beradi
  • Result turi — stekni ochmasdan xato qiymat sifatida uzatiladigan istisnolarga alternativa

Xatolarni tarqatish nima?

Xatolarni tarqatish — xato obyektini paydo bo'lgan funksiyadan chaqiruvlar zanjiri bo'ylab eng yaqin mos ishlov beruvchiga uzatish jarayoni. Chaqiruvlar stekini tasavvur qiling: ViewController ViewModel-ni, ViewModel Repository-ni, Repository API-ni chaqiradi. Agar API tarmoq xatosini qaytarsa, u Repository va ViewModel orqali foydalanuvchiga xabar ko'rsatadigan ViewController-ga etib borishi kerak. Har bir oraliq funksiya qaror qiladi: xatoni ishlash yoki undan keyingi uzatish (tarqatish).

Tarqatishning ikkita yondashuvi mavjud: avtomatik va qo'lda. Avtomatik yondashuvda (Swift throws, Java tekshirilgan istisnolar) kompilyator dasturchini yo xatoni ishlashga yoki imzoda tarqatishni e'lon qilishga majburlaydi. Qo'lda yondashuvda (Result turi, Kotlin Try) xato qiymat sifatida uzatiladi — dasturchi xatoni uzatish yoki transformatsiya qilish uchun aniq kod yozadi. Kotlin Result Docs (2026) ga ko'ra, Kotlin-da Result<T> to'g'ridan-to'g'ri funksiya chegaralari bo'ylab tarqatish uchun mo'ljallanmagan — uni har bir darajada transformatsiya qilish yoki ishlash kerak, bu tarqatishni ongliroq, ammo uzunroq qiladi.

Yondashuvni tanlash ilova arxitekturasi va tilga bog'liq. Swift-da throws orqali avtomatik tarqatish ustunlik qiladi, Kotlin-da — istisnolar (kutilmagan xatolar uchun) va Result-ga o'xshash konteynerlar (kutilgan xatolar uchun) aralashmasi. Tushunish muhim: tarqatish maqsad emas, balki zaruriyatdir. Ideal arxitektura qaror qabul qilish uchun yetarli kontekst mavjud bo'lgan eng past darajada xatolarni ishlab, tarqatish chuqurligini minimal darajaga tushiradi.

Swift-da Throws orqali tarqatish

Swift-da throws orqali tarqatish avtomatik ravishda sodir bo'ladi: agar throws bilan A funksiyasi throws bilan B funksiyasini chaqirsa va A do-catch da B ning xatosini ishlamasa, xato avtomatik ravishda A ni chaqiruvchi tomonga uzatiladi. Bu Java tekshirilgan istisnolariga xos bo'lgan boilerplate kodini yo'q qiladi, bu erda throws zanjirning har bir metodida e'lon qilinishi kerak. Swift printsipni qo'llaydi: „zanjirda bitta throws funksiyasi = oraliq darajalarda ishlanmasa, butun zanjir throws bo'ladi”.

swift
struct UserRepository {
    func fetchUser(id: Int) throws -> User {
        let data = try networkService.request(path: "/users/\(id)")
        return try parseUser(from: data)
    }
}

class UserViewModel {
    let repo = UserRepository()

    func loadUser(id: Int) throws -> User {
        return try repo.fetchUser(id: id)
    }
}

// ViewController — yakuniy ishlov beruvchi
func onButtonTap() {
    let vm = UserViewModel()
    do {
        let user = try vm.loadUser(id: 42)
        updateUI(user)
    } catch {
        showError("Foydalanuvchini yuklash muvaffaqiyatsiz tugadi")
    }
}

Tarqatish zanjiri: networkService.request -> fetchUser -> loadUser -> onButtonTap. Har bir oraliq funksiya throws bilan belgilangan va do-catch ni o'z ichiga olmaydi — xato avtomatik ravishda yuqoriga uzatiladi. ViewController onButtonTap do-catch bilan yakuniy ishlov beruvchidir. Agar ViewModel xatoni transformatsiya qilishga (boshqa turga o'rash) qaror qilganida, do-catch va yangi throw dan foydalanishi mumkin edi. Avtomatik tarqatish kodni qisqartiradi: Repository xatoni qanday ishlashni bilishi shart emas — bu UI ga foydalanuvchiga xabar ko'rsatish uchun kirish huquqiga ega bo'lgan ViewController-ning mas'uliyatidir.

Kotlin-da istisnolar orqali tarqatish

Kotlin-da istisnolar orqali tarqatish imzoda throws deklaratsiyasini talab qilmaydi (barcha istisnolar tekshirilmagan). Istisno try-catch ga duch kelguncha stek bo'ylab avtomatik ravishda ko'tariladi. Biroq, imzoda throws ning yo'qligi tarqatishni noaniq qiladi: dasturchi funksiya imzosidan uning istisno tashlashi mumkinligini ko'rmaydi. Bu ham afzallik (kamroq boilerplate), ham kamchilik (ishlashni unutish oson) hisoblanadi. Kotlin bu muammoni til orqali emas, balki konventsiyalar va arxitektura na'munalari orqali hal qiladi.

kotlin
class UserRepository(
    private val api: ApiService,
    private val db: Database
) {
    suspend fun getUser(id: String): User {
        return try {
            api.fetchUser(id)
        } catch (e: IOException) {
            db.getCachedUser(id) ?: throw AppException("User unavailable")
        }
    }
}

class UserViewModel(private val repo: UserRepository) {
    private val _state = MutableStateFlow<UiState<User>>(UiState.Loading)
    val state: StateFlow<UiState<User>> = _state

    fun loadUser(id: String) {
        viewModelScope.launch {
            try {
                val user = repo.getUser(id)
                _state.value = UiState.Success(user)
            } catch (e: AppException) {
                _state.value = UiState.Error(e.message ?: "Unknown")
            }
        }
    }
}

Repository-da transformatsiya bilan tarqatish: IOException (tarmoq mavjud emas) da funksiya ma'lumotlar bazasidan keshlangan ma'lumotlarni olishga harakat qiladi. Kesh bo'sh bo'lsa, AppException tashlaydi — tarqatish yangi xato turi bilan davom etadi. ViewModel AppException ni ushlaydi va UiState.Error ga tarjima qiladi — xato oldinga ketmaydi, tarqatish UI qatlamida tugallanadi. Kotlin Coroutines xususiyatlarni qo'shadi: launch dagi istisnolar avtomatik ravishda CoroutineExceptionHandler orqali tarqaladi, async da esa — faqat await() chaqirilganda. SupervisorJob koroutinlarda tarqatishni loyihalashda buni hisobga olish muhim — SupervisorJob ota-koroutinning bekor qilinishini oldini oladi.

Result turi orqali tarqatish

Istisnolarga alternativa — muvaffaqiyat yoki xatoni qiymat sifatida uzatuvchi tur-konteyner orqali tarqatish. Bu yondashuvda funksiya qiymatni emas, balki o'ramni qaytaradi: Swift-da Result<T, E>, Kotlin-da Result<T>, Dart-da Either<L, R> (fpdart yoki dartz paketidan). Xato stekni ochmaydi — shunchaki konteynerda yotadi va keyingi daraja u bilan nima qilishni hal qiladi. Bu tarqatishni aniqroq va boshqariladigan qiladi.

kotlin
data class HttpResult<out T>(
    val data: T?,
    val error: AppError?
) {
    val isSuccess: Boolean get() = data != null
    val isError: Boolean get() = error != null
}

sealed class AppError {
    data class Network(val message: String) : AppError()
    data class Auth(val message: String) : AppError()
}

fun fetchUser(id: String): HttpResult<User> {
    return try {
        val response = api.get("/users/$id")
        HttpResult(data = parseUser(response), error = null)
    } catch (e: IOException) {
        HttpResult(data = null, error = AppError.Network("No internet"))
    }
}

HttpResult<T> — data va error maydonlari bo'lgan oddiy konteyner. Sealed class AppError xato turlarini (Network, Auth) belgilaydi. fetchUser funksiyasi HttpResult qaytaradi, tarqatish stekni ochishni talab qilmaydi — chaqiruvchi tomon shunchaki isSuccess/isError ni tekshiradi. Bu yondashuv ayniqsa Toza Arxitekturada foydali, bu erda har bir qatlam (data, domain, presentation) xatoni transformatsiya qilishi mumkin: IOError -> DomainError -> UiError. Konteyner orqali tarqatish bu transformatsiyalarni aniq va sinab ko'rish mumkin qiladi, istisnolardan farqli o'laroq, bu erda o'zgartirishlar zanjiri funksiya imzolarida ko'rinmaydi.

Tarqatish va Qayta ishlash: qachon uzatish, qachon ishlash

Xatolarni qayta ishlashni loyihalashdagi asosiy qarorlardan biri tarqatish (yuqoriga uzatish) va ishlash (bu erda ishlash) o'rtasidagi tanlovdir. Qaror qabul qilish qoidasi: xatoni mazmunli harakat uchun yetarli kontekst mavjud bo'lgan darajada ishla. UI ga kirishing bo'lsa — foydalanuvchiga xabar ko'rsat. Keshga kirishing bo'lsa — tiklanishga harakat qil. Hech biri bo'lmasa — tarqat.

SsenariyHarakatAsoslash
Repository-da tarmoq xatosiTarqatRepository foydalanuvchi so'rovni takrorlashni xohlayotganini bilmaydi
Repository-da tahlil xatosiIshla (standart qiymat qaytar)Repository formatni biladi, zaxira qiymat qaytarishi mumkin
ViewModel-da vaqt chegarasiIshla (UiState.Error)ViewModel UiState ni boshqaradi, xatoni qanday tarjima qilishni biladi
Interceptor-da avtorizatsiya xatosiIshla (tokenni yangila)Interceptor tokenlarga kirish huquqiga ega va seansni tiklay oladi
UseCase-da noma'lum xatoTarqatUseCase UI kontekstiga ega emas — faqat biznes mantiq

Oltin qoida: pastki darajalarda minimal tarqatish, maksimal ishlash. Agar Repository keshtan tiklanishi mumkin bo'lsa — buni qilishi kerak, xatoni yuqoriga uzatmasdan. Agar ViewModel Snackbar ko'rsata olsa — ko'rsatsin, ViewController-dan qo'shimcha kod talab qilmasdan. Har bir tarqatish darajasi bog'liqlikni oshiradi va test qilishni qiyinlashtiradi. Google Android Architecture Guide (2026) ga ko'ra, ViewModel darajasida barcha mumkin bo'lgan holatlarni (Loading, Success, Error) ifodalash uchun sealed class UiState dan foydalanib, qatlam chegaralari bo'ylab tarqatishni minimal darajaga tushirish va istisnolarni to'g'ridan-to'g'ri UI qatlamiga uzatmaslik tavsiya etiladi.

Xatolarni tarqatish muammolari va anti-na'munalari

Noto'g'ri tarqatish mobil ilovalarda qiyin aniqlanadigan xatolar manbai hisoblanadi. Keling, dasturchilar duch keladigan beshta asosiy muammo va ularni hal qilish usullarini ko'rib chiqaylik.

Xato kontekstining yo'qolishi

Eng keng tarqalgan muammo: tarqatish paytida istisno ushlanadi, jurnalga yoziladi va asl istisnosiz yangisi tashlanadi. Dasturchi StackTrace ni yo'qotadi va xato qayerda sodir bo'lganini tushunolmaydi. Swift-da xato zanjirlash dan foydalaning: throw MyError(context: originalError). Kotlin-da: throw AppException(cause = originalException). Dart-da: throw AppException(message, originalException). Hech qachon sabab/asosiy xatoni uzatmasdan yangi istisno yaratmang.

Xatoni e'tiborsiz qoldirish (bo'sh catch)

catch (e: Exception) { /* hech narsa */ } — ilovaning noto'g'ri holatda ishlashni davom ettirishiga olib keladigan anti-na'muna. Agar xatoni e'tiborsiz qoldirish mumkinligiga ishonchingiz komil bo'lsa — asoslash bilan izoh qo'shing. Swift-da ixtiyoriy e'tiborsiz qoldirish uchun try? dan foydalaning (xato -> nil). Kotlin-da — Result<T>.onFailure { /* log */ }. Jurnalga yozmasdan istisnolarni bo'g'mang.

Haddan tashqari tarqatish chuqurligi

Agar xato ishlanmasdan 5+ darajadan o'tsa, arxitektura qayta ko'rib chiqilishini talab qiladi. Har bir tarqatish darajasi quyi funksiyalarning throws imzosiga bog'liqlikdir. Yechim: qatlam chegaralarida Failure konteynerlaridan (sealed class Result { Success, Error }) foydalaning, shunda tarqatish aniq va cheklangan bo'ladi. Tarqatish zanjiri qanchalik qisqa bo'lsa, kodni test qilish va tuzatish shunchalik oson bo'ladi.

SupervisorJob siz koroutinlarda tarqatish

Kotlin Coroutines-da launch dagi istisno sukut bo'yicha ota-koroutinni va barcha siblings-ni (bir scope ning bolalari) bekor qiladi. Agar 10 parallel topshiriqdan biri yiqilsa, qolgan 9 tasi bekor qilinadi, bu ko'pincha istalmagan. Xatolarni izolyatsiya qilish uchun SupervisorJob yoki supervisorScope dan foydalaning: bir child dagi xato siblings-ni bekor qilmaydi. ViewModelScope sukut bo'yicha SupervisorJob dan foydalanadi, bu Android-da bu muammodan himoya qiladi.

Ishlanmasdan callback orqali tarqatish

Callback-ga asoslangan API-da xato ko'pincha callback parametri sifatida uzatiladi. Agar callback xatoni ishlamasa (yoki noto'g'ri ishlasa), tarqatish noaniq bo'ladi va oson yo'qoladi. Yechim: async/await (Swift) yoki koroutinlarga (Kotlin) o'ting, bu erda tarqatish standart try-catch mexanizmlari orqali ishlaydi. Agar callback muqarrar bo'lsa — ikkala holatni majburiy ishlash uchun Either<Error, T> yoki Result<T> dan foydalaning.

Tez-tez beriladigan savollar

Xatolarni tarqatish throw dan qanday farq qiladi?

Throw — istisnoni bir martalik tashlash harakati. Xatolarni tarqatish — xatoni throw dan catch gacha bir necha stek darajalari orqali uzatishning butun jarayoni. Tarqatish throw, oraliq funksiyalar orqali avtomatik yoki qo'lda uzatish va yakuniy ishlashni o'z ichiga oladi. Bu xatoning hayotiy siklini tavsiflovchi kengroq tushunchadir.

Xatolarni tarqatishni qanday test qilish kerak?

Berilgan ssenariylarda istisnolar tashlaydigan mock obyektlaridan foydalaning. Funksiyaning xatoni to'g'ri tarqatishini yoki ishlashini assertThrows (Kotlin/JUnit) yoki XCTAssertThrowsError (Swift/XCTest) orqali tekshiring. Result-ga asoslangan tarqatish uchun ikkala holatda isSuccess/isError va qiymatlarni tekshiring.

Qachon Result orqali tarqatish istisnolardan yaxshiroq?

Result tarqatish bitta arxitektura chegarasi ichida kutilgan xatolar (noto'g'ri ma'lumotlar, biznes qoidalari) uchun afzalroqdir. Istisnolar yuqori darajada ishlanishi kerak bo'lgan kutilmagan xatolar (tarmoq yo'qolishi, kiritish-chiqarish xatolari) uchun yaxshiroqdir. Xato bilan natija bajarilish oqimini to'xtatmaydi, istisno to'xtatadi.

Kotlin koroutinlari orqali xatoni qanday tarqatish mumkin?

Kotlin Coroutines-da launch dagi istisno avtomatik ravishda CoroutineScope orqali siblings-ni bekor qilish bilan tarqaladi. Izolyatsiya uchun supervisorScope yoki SupervisorJob dan foydalaning: bir koroutindagi xato boshqalarni bekor qilmaydi. Async uchun xato await() chaqirilganda try-catch orqali aniq ishlanishi kerak, aks holda yutiladi.

Qaysi daraja xatoning yakuniy ishlov beruvchisi bo'lishi kerak?

Ideal yakuniy ishlov beruvchi UI qatlamidir (ViewController, Fragment/Composable). Faqat u foydalanuvchi interfeysiga kirish huquqiga ega va xabar, Snackbar yoki dialogni ko'rsata oladi. Oraliq qatlamlar (Repository, UseCase, ViewModel) xatoni tarqatadi, kerak bo'lganda uni mavhumroq domen turiga aylantiradi.

Xulosa

  • Xatolarni tarqatish — xatoning paydo bo'lgan joyidan ishlov beruvchiga stek bo'ylab istisnolar yoki Result konteynerlari orqali uzatilishi
  • Swift-da throws orqali avtomatik tarqatish oraliq darajalarda kod talab qilmaydi — xato o'zi ko'tariladi
  • Kotlin-da qo'lda tarqatish har bir darajada aniq try-catch va throw orqali ishlashni ongli, ammo uzun qiladi
  • Result turi xatoni stekni ochmasdan qiymat sifatida uzatadi, Toza Arxitekturada kutilgan xatolar uchun qulay
  • Ishlash qoidasi: kontekst bilan darajada ishla (UI), kontekstsiz darajalardan tarqat (domain, data)
  • Anti-na'munalar: bo'sh catch, transformatsiyada sababni yo'qotish, haddan tashqari tarqatish chuqurligi, SupervisorJob ni e'tiborsiz qoldirish
  • Har bir qatlam uchun tiplangan xatolarni (sealed class / enum) loyihalashtiring va qatlam chegaralarini kesib o'tishda ularni transformatsiya qiling

Biz kalit topshirig'i bilan mobil ilovani ishlab chiqamiz

IT Sectr 2017-yildan beri startaplar va korxonalar uchun iOS va Android ilovalarini yaratadi. Biz sizga maslahat beramiz va eng yaxshi yechimni taklif qilamiz.

Loyihani muhokama qilish

Shuningdek o'qing