Try-Catch: суштина, конструкција хватања изузетака и како ради у мобилном развоју

Аутор: IT Sectr Објављено: 2026-05-25 Време читања: 9 мин

Try-Catch — конструкција хватања изузетака која омогућава извршавање потенцијално опасног кода у заштићеном блоку и коректно обрађивање грешака без наглог прекида програма. Блок try садржи код који може да баци изузетак, catch га хвата и извршава логику опоравка. Према Apple Swift Documentation (2026), блок finally се извршава без обзира на то да ли је изузетак бачен или не, гарантујући ослобађање ресурса.

Главно

  • Try-Catch — конструкција за хватање изузетака која спречава нагли прекид програма при грешкама
  • Блок try садржи код који може бацити изузетак — извршење се прекида при првој грешци
  • Блок catch хвата изузетак наведеног типа и извршава логику обраде или опоравка
  • Блок finally се гарантовано извршава након try/catch ради ослобађања ресурса, нпр. затварања датотека
  • Угњеждени try-catch омогућавају обраду грешака на различитим нивоима апстракције унутар једне функције

Шта је Try-Catch?

Try-Catch — фундаментална конструкција структуралне обраде изузетака, присутна у већини савремених програмских језика. Састоји се од три блока: try (покушај извршења опасног кода), catch (хватање и обрада изузетка) и опционог finally (финализација). Идеја конструкције је одвајање логике пословних операција од логике обраде грешака, чинећи код читљивијим и предвидљивијим.

Концепт је први пут имплементиран у језику C++ као try/catch, затим преузет од Java, C#, Swift, Kotlin, Dart, Python, JavaScript и других језика. Сваки језик додаје своје карактеристике: у Swift блок catch мора бити исцрпан, у Kotlin try-catch може бити израз (expression), у Dart finally је обавезан за ресурсе тока. Упркос разликама, основни принцип је исти: грешка се обрађује што ближе месту настанка, а не глобално.

Коришћење Try-Catch је посебно важно у мобилном развоју, где спољни фактори — губитак мреже, неисправан одговор сервера, недовољно меморије — стално настају. Исправна обрада изузетака спречава краш апликације и обезбеђује коректан UX: корисник добија поруку о грешци уместо наглог затварања апликације. Према Google Android Kotlin Style Guide (2026), свака функција која може бацити изузетак треба или да га обради кроз try-catch, или да декларише throws у потпису.

Како ради Try-Catch

Механизам извршења try-catch се заснива на одмотавању стека (stack unwinding). Када се унутар блока try баци изузетак путем оператора throw (или као резултат системске грешке), нормалан ток извршења се одмах прекида. Извршење се помера на виши ниво стека позива у потрази за одговарајућим блоком catch. Савремени језици траже catch са типом који одговара типу баченог изузетка, користећи механизам подударања типова (type matching).

Ако се одговарајући catch пронађе, извршава се његово тело, након чега се извршење наставља након целе конструкције try-catch-finally. Ако catch није пронађен, изузетак се подиже даље по стеку и може бити обрађен на вишем нивоу — све до глобалног хендлера који у мобилној апликацији приказује кориснику дијалог са грешком. Ако изузетак није обрађен нигде, апликација се нагло прекида. Управо зато је коректна обрада свих могућих типова изузетака критична за стабилност апликације.

Синтакса основне конструкције

kotlin
fun readUserData(): User {
    return try {
        val response = api.fetchUser()
        parseUser(response)
    } catch (e: IOException) {
        logError("Грешка у мрежи", e)
        throw AppException("Није успело учитавање података")
    } catch (e: JsonParseException) {
        logError("Грешка при рашчлањивању", e)
        return User.default()
    } finally {
        closeLoadingIndicator()
    }
}

Код прво покушава да изврши упит ка API-ју и рашчлани одговор. Ако настане IOException (проблем са мрежом), изузетак се логира и прослеђује даље као AppException. Ако настане JsonParseException — враћа се подразумевани корисник. Блок finally гарантовано сакрива индикатор учитавања, спречавајући цурење UI компоненти на екрану.

Try-Catch у Swift

У Swift-у обрада грешака је имплементирана кроз протокол Error (раније ErrorType). Сваки тип који је у складу са Error може бити бачен путем оператора throw. Функција која може бацити грешку се означава кључном речи throws у потпису. Позив такве функције захтева префикс try (за експлицитни try-catch), try? (опциони резултат) или try! (принудно извршење без обраде грешке).

swift
enum NetworkError: Error {
    case noConnection
    case serverError(code: Int)
    case timeout
}

func fetchUser(id: Int) throws -> User {
    guard isConnected() else {
        throw NetworkError.noConnection
    }
    let data = try performRequest(path: "/users/\(id)")
    return try decodeUser(from: data)
}

do {
    let user = try fetchUser(id: 42)
    updateUI(user)
} catch NetworkError.noConnection {
    showOfflineAlert()
} catch let error as NetworkError {
    showError("Мрежа " + error.localizedDescription)
} catch {
    showGenericError()
}

Enum NetworkError имплементира протокол Error, дефинишући три случаја: noConnection, serverError са кодом и timeout. Функција fetchUser је означена са throws: прво проверава везу, затим извршава упит и рашчлањивање. У do-catch блоку три catch обрађују различите сценарије: специфичан случај noConnection, општи тип NetworkError и све остале грешке. Ово омогућава приказивање различитих порука кориснику у зависности од типа проблема.

Try-Catch у Kotlin

Kotlin је наследио try-catch-finally од Java, али је додао важну разлику: у Kotlin-у try-catch је израз (expression), а не наредба (statement). То значи да се резултат try блока или catch блока може доделити променљивој. Последњи израз у try блоку постаје резултат при успеху, последњи израз у catch — при грешци. Ако грешка није обрађена ни од једног catch-а, изузетак се прослеђује више по стеку.

kotlin
sealed class Result<out T> {
    data class Success<out T>(val data: T) : Result<T>()
    data class Error(val exception: Throwable) : Result<Nothing>()
}

fun loadData(): Result<List<Item>> {
    return try {
        val response = api.getItems()
        Result.Success(response.toList())
    } catch (e: HttpException) {
        Log.e("HTTP ", e)
        Result.Error(e)
    } catch (e: IOException) {
        Log.e("Мрежа ", e)
        Result.Error(e)
    }
}

У примеру, sealed class Result обавија успешан одговор или грешку. Функција loadData користи try-catch као израз: при успеху враћа Result.Success, при изузетку HttpException или IOException — Result.Error са логирањем. Овај приступ омогућава позивајућој страни да обрађује грешке без изузетака — преко when-израза по типу Result. Ово је посебно згодно у Jetpack Compose за приказ различитих стања UI (Loading, Success, Error) кроз StateFlow и collectAsState.

Try-Catch у Dart и Flutter

Dart подржава try-catch-finally са синтаксом сличном Java, али са додатком on клаузуле за филтрирање по типу изузетка без навођења променљиве. Ово је згодно када сам изузетак није потребан — важна је само чињеница његовог типа. Dart такође подржава блок catch са два параметра: објекат изузетка и StackTrace, што је корисно за логирање целог ланца позива.

dart
import 'dart:io';
import 'dart:convert';

class UserRepository {
    Future<User> fetchUser(String id) async {
        try {
            final client = HttpClient();
            final request = await client.getUrl(
                Uri.parse('https://api.example.com/users/$id')
            );
            final response = await request.close();
            final body = await response.transform(utf8.decoder).join();
            return User.fromJson(json.decode(body));
        } on SocketException catch (e, stackTrace) {
            log("No internet", e, stackTrace);
            throw AppException("Connection failed");
        } on FormatException {
            throw AppException("Invalid response format");
        } finally {
            client.close();
        }
    }
}

SocketException се хвата са објектом и StackTrace за детаљно логирање, а затим прослеђује као AppException. FormatException се хвата без променљиве — довољно је знати да је формат одговора неисправан. Блок finally гарантовано затвара HttpClient, спречавајући цурење сокета. У Flutter-у је овај приступ посебно важан за Widget тестирање, где необрађени изузеци у State.initState доводе до пада целе сесије тестирања.

Типичне грешке при коришћењу Try-Catch

Чак и искусни програмери праве грешке при раду са try-catch које доводе до цурења меморије, скривених багова или неадекватног понашања апликације. Размотримо пет најчешћих проблема у мобилном развоју.

Празан блок catch

Празан catch — једна од најгорих пракси. Изузетак се гута, апликација наставља да ради у неисправном стању, а програмер не сазнаје за проблем. Увек бар логирајте изузетак. У Kotlin-у користите catch(e: Exception) { Log.e(...) }, у Swift-у — catch { print($0) }. У Dart-у минимално прихватљив catch треба да позове debugPrint или да запише у Crashlytics.

Сувише широк catch

Хватање свих изузетака кроз catch (Exception e) без разликовања по типовима сакрива неочекиване грешке — NullPointerException, OutOfMemoryError, StackOverflowError. Хватајте само оне типове које очекујете и које можете обрадити. За остатак дозволите пропагацију навише. У мобилном развоју специфични catch за IOException, TimeoutException, AuthException дају смисленије поруке кориснику.

Игнорисање finally

Ресурси — датотеке, сокети, курсори БД, анимације — треба да се ослобађају у finally или у use блоку (AutoCloseable). Програмери често заборављају да затворе ресурсе при изузетку, што доводи до цурења. У Kotlin-у користите .use { } за Closeable ресурсе, у Swift-у — defer { }, у Dart-у — await using из пакета async. Блок finally гарантује ослобађање чак и при бацању изузетка унутар catch-а.

Изузеци у нитима и корутинама

У асинхроном коду try-catch не хвата изузетке из других нити. У Kotlin Coroutines користите CoroutineExceptionHandler или SupervisorJob. У Swift async/await — do-catch унутар Task. У Flutter-у — runZonedGuarded за глобално хватање. Игнорисање овог правила је узрок тешко репродуцибилних крашева у продукцији.

Блокирање UI при изузетку

Обрада изузетка не сме да блокира кориснички интерфејс на неодређено време. Прикажите кориснику конкретну поруку и дајте могућност понављања операције. Snackbar са дугметом Retry у Kotlin/Compose, UIAlertController са action у Swift-у, SnackBar са action у Flutter-у — минимално довољан UX за грешке мреже или сервера. Избегавајте опште дијалоге „Дошло је до грешке" без могућности опоравка.

Често постављана питања

По чему се try-catch разликује од Result Type?

Try-catch користи изузетке и одмотавање стека за обраду грешака, што може бити скупо у погледу перформанси при великом броју грешака. Result Type је тип-контејнер (Success или Failure) који се обрађује кроз pattern matching без одмотавања стека, што је ефикасније за очекиване грешке.

Да ли треба користити finally у сваком try-catch?

Finally је обавезан ако блок try отвара ресурсе (датотеке, сокете, курсоре) које треба затворити. Ако се ресурси не отварају, finally није потребан. У савременим језицима користите AutoCloseable/use/defer за аутоматско затварање ресурса без finally. use-блок у Kotlin и Swift замењује finally за Closeable објекте.

Може ли try-catch бити спор?

У нормалном току (без изузетка) try-catch практично не утиче на перформансе — JVM и Swift компајлер оптимизују овај случај. Али при бацању изузетка долази до одмотавања стека, што може трајати 10–100 μс у зависности од дубине стека. Не користите изузетке за управљање током извршења — то је антиобразац.

Како обрађивати грешке у Kotlin Coroutines?

У корутинама користите try-catch унутар coroutineScope или CoroutineExceptionHandler за глобално хватање. SupervisorJob спречава отказивање родитељске корутине при грешци у детету. За launch користите CoroutineExceptionHandler, за async — try-catch око await().

Шта је боље: вишеструки catch или један catch са if-else?

Вишеструки catch је пожељнији: код се чита линеарно, сваки блок обрађује један тип изузетка. Један catch са if-else је тежи за одржавање, лако се може превидети нови тип изузетка. У Swift-у су вишеструки catch обавезни за исцрпну обраду enum Error, у Kotlin-у нема ограничења, али најбоља пракса је одвојен catch по типу.

Резиме

  • Try-Catch — конструкција хватања изузетака са блоковима try, catch и опционим finally за гарантовано ослобађање ресурса
  • Механизам рада — одмотавање стека при бацању изузетка са тражењем одговарајућег catch-а по типу грешке
  • У Swift-у се користи do-catch са enum Error, try? за опциони резултат и try! за гарантовани успех
  • У Kotlin-у try-catch је израз чији резултат може бити додељен променљивој, згодно у пару са sealed class Result
  • У Dart-у подржава on клаузулу за филтрирање по типу без променљиве и finally за затварање HttpClient
  • Типичне грешке: празан catch, прешироко хватање, игнорисање finally и недостатак обраде у корутинама
  • Користите try-catch за неочекиване грешке, Result Type — за очекиване сценарије са могућим неуспехом

Развићемо мобилну апликацију под кључ

IT Sectr креира iOS и Android апликације за стартапе и предузећа од 2017. године. Саветоваћемо вас и предложити најбоље решење.

Разговарајте о пројекту

Прочитајте такође