Try-Catch — kivételkezelő szerkezet, amely lehetővé teszi potenciálisan veszélyes kód végrehajtását egy védett blokkban és a hibák megfelelő kezelését a program hirtelen megszakítása nélkül. A try blokk olyan kódot tartalmaz, amely kivételt dobhat, a catch elkapja azt és végrehajtja a helyreállítási logikát. A Apple Swift Documentation (2026) szerint a finally blokk attól függetlenül végrehajtódik, hogy a kivételt dobtak-e vagy sem, garantálva az erőforrások felszabadítását.
Főbb Pontok
Try-Catch — a strukturált kivételkezelés alapvető szerkezete, amely a legtöbb modern programozási nyelvben megtalálható. Három blokkból áll: try (veszélyes kód végrehajtásának kísérlete), catch (kivétel elkapása és kezelése) és opcionális finally (befejezés). A szerkezet ötlete az üzleti műveletek logikájának elválasztása a hibakezelés logikájától, ami olvashatóbbá és kiszámíthatóbbá teszi a kódot.
A koncepciót először a C++ nyelvben implementálták try/catch néven, majd átvették a Java, C#, Swift, Kotlin, Dart, Python, JavaScript és más nyelvek. Minden nyelv hozzáadja a saját jellemzőit: Swift-ben a catch blokknak kimerítőnek kell lennie, Kotlin-ban a try-catch lehet kifejezés (expression), Dart-ban a finally kötelező a folyam erőforrásokhoz. A különbségek ellenére az alapelv ugyanaz: a hibát a lehető legközelebb kell kezelni a keletkezés helyéhez, nem globálisan.
A Try-Catch használata különösen fontos a mobilfejlesztésben, ahol külső tényezők — hálózat elvesztése, helytelen szerverválasz, memóriahiány — folyamatosan előfordulnak. A megfelelő kivételkezelés megakadályozza az alkalmazás összeomlását és biztosítja a megfelelő UX-et: a felhasználó hibaüzenetet kap az alkalmazás hirtelen bezáródása helyett. A Google Android Kotlin Style Guide (2026) szerint minden olyan függvénynek, amely kivételt dobhat, vagy try-catch-en keresztül kell kezelnie azt, vagy throws-t kell deklarálnia az aláírásában.
A try-catch végrehajtási mechanizmusa a verem kitekerésén (stack unwinding) alapul. Amikor a try blokkon belül egy kivételt dobnak a throw operátoron keresztül (vagy rendszerhiba következtében), a normál végrehajtási folyamat azonnal megszakad. A végrehajtás a hívási verem magasabb szintjére lép egy megfelelő catch blokk keresése céljából. A modern nyelvek olyan catch-t keresnek, amelynek típusa megegyezik a dobott kivétel típusával, típusegyeztetési mechanizmust (type matching) használva.
Ha a megfelelő catch megtalálható, annak törzse végrehajtódik, majd a végrehajtás a teljes try-catch-finally szerkezet után folytatódik. Ha a catch nem található, a kivétel továbbhalad a veremben felfelé, és magasabb szinten kezelhető — egészen a globális kezelőig, amely a mobil alkalmazásban egy hiba dialógust jelenít meg a felhasználónak. Ha a kivétel sehol sincs kezelve, az alkalmazás összeomlik. Pontosan ezért az összes lehetséges kivételtípus megfelelő kezelése kritikus az alkalmazás stabilitása szempontjából.
fun readUserData(): User {
return try {
val response = api.fetchUser()
parseUser(response)
} catch (e: IOException) {
logError("Hálózati hiba", e)
throw AppException("Nem sikerült betölteni az adatokat")
} catch (e: JsonParseException) {
logError("Feldolgozási hiba", e)
return User.default()
} finally {
closeLoadingIndicator()
}
}
A kód először megpróbál végrehajtani egy API-kérést és feldolgozni a választ. Ha IOException (hálózati probléma) lép fel, a kivétel naplózásra kerül és AppException-ként továbbítódik. Ha JsonParseException — az alapértelmezett felhasználó kerül visszaadásra. A finally blokk garantáltan elrejti a betöltés jelzőt, megakadályozva a UI-komponensek szivárgását a képernyőn.
Swift-ben a hibakezelés az Error protokollon keresztül van implementálva (korábban ErrorType). Bármely típus, amely megfelel az Error-nak, dobható a throw operátoron keresztül. Az a függvény, amely hibát dobhat, a throws kulcsszóval van megjelölve az aláírásában. Egy ilyen függvény meghívása a try előtagot igényli (explicit try-catch-hez), try?-t (opcionális eredményhez) vagy try!-t (kényszerített végrehajtás hibakezelés nélkül).
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("Hálózat " + error.localizedDescription)
} catch {
showGenericError()
}
Enum NetworkError implementálja az Error protokollt, három esetet definiálva: noConnection, serverError kóddal és timeout. A fetchUser függvény throws-szal van jelölve: először ellenőrzi a kapcsolatot, majd végrehajtja a kérést és a feldolgozást. A do-catch blokkban három catch kezel különböző forgatókönyveket: a specifikus noConnection esetet, az általános NetworkError típust és az összes többi hibát. Ez lehetővé teszi, hogy a probléma típusától függően különböző üzeneteket jelenítsünk meg a felhasználónak.
A Kotlin örökölte a try-catch-finally-t a Java-tól, de hozzáadott egy fontos különbséget: Kotlin-ban a try-catch egy kifejezés (expression), nem pedig utasítás (statement). Ez azt jelenti, hogy a try blokk vagy a catch blokk eredménye változóhoz rendelhető. A try blokk utolsó kifejezése sikernél az eredmény, a catch utolsó kifejezése — hiba esetén. Ha a hibát egyetlen catch sem kezeli, a kivétel továbbítódik felfelé a veremben.
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("Hálózat ", e)
Result.Error(e)
}
}
A példában a sealed class Result egy sikeres választ vagy hibát csomagol be. A loadData függvény try-catch-t használ kifejezésként: siker esetén Result.Success-t ad vissza, HttpException vagy IOException kivételnél — Result.Error-t naplózással. Ez a megközelítés lehetővé teszi a hívó fél számára, hogy kivételek nélkül kezelje a hibákat — a when-kifejezésen keresztül a Result típusa alapján. Ez különösen kényelmes a Jetpack Compose-ban a különböző UI-állapotok (Loading, Success, Error) megjelenítéséhez StateFlow és collectAsState segítségével.
A Dart támogatja a try-catch-finally-t a Java-hoz hasonló szintaxissal, de kiegészítve az on klauzulával a kivétel típus szerinti szűréséhez változó megadása nélkül. Ez akkor kényelmes, ha maga a kivétel nem szükséges — csak a típusának ténye fontos. A Dart támogatja a catch blokkot két paraméterrel is: a kivétel objektum és a StackTrace, ami hasznos a teljes hívási lánc naplózásához.
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();
}
}
}
A SocketException az objektum és StackTrace rögzítésével van elkapva részletes naplózáshoz, majd AppException-ként továbbítódik. A FormatException változó nélkül van elkapva — elég tudni, hogy a válasz formátuma helytelen. A finally blokk garantáltan bezárja a HttpClient-t, megakadályozva a socket szivárgást. Flutter-ben ez a megközelítés különösen fontos a Widget teszteléshez, ahol a State.initState-ben kezeletlen kivételek a teljes tesztelési munkamenet összeomlásához vezetnek.
Még tapasztalt fejlesztők is követnek el hibákat a try-catch használatakor, amelyek memóriaszivárgáshoz, rejtett hibákhoz vagy az alkalmazás helytelen viselkedéséhez vezetnek. Vizsgáljuk meg az öt leggyakoribb problémát a mobilfejlesztésben.
Üres catch — az egyik legrosszabb gyakorlat. A kivétel lenyelődik, az alkalmazás helytelen állapotban folytatja a működést, és a fejlesztő nem tud a problémáról. Mindig legalább naplózza a kivételt. Kotlin-ban használja a catch(e: Exception) { Log.e(...) }, Swift-ben — a catch { print($0) } függvényt. Dart-ban a minimálisan elfogadható catch-nek debugPrint-et kell hívnia vagy Crashlytics-be kell írnia.
Az összes kivétel elkapása catch (Exception e) segítségével típus szerinti megkülönböztetés nélkül elrejti a váratlan hibákat — NullPointerException, OutOfMemoryError, StackOverflowError. Csak azokat a típusokat kapja el, amelyeket vár és kezelni tud. A többinél engedje a terjedést felfelé. A mobilfejlesztésben a specifikus catch IOException, TimeoutException, AuthException esetén értelmesebb üzeneteket ad a felhasználónak.
Az erőforrásokat — fájlok, socketek, adatbázis kurzorok, animációk — a finally-ban vagy a use blokkban (AutoCloseable) kell felszabadítani. A fejlesztők gyakran elfelejtik bezárni az erőforrásokat kivétel esetén, ami szivárgáshoz vezet. Kotlin-ban használja a .use { } függvényt Closeable erőforrásokhoz, Swift-ben — a defer { }, Dart-ban — az await using-et az async csomagból. A finally blokk garantálja a felszabadítást még akkor is, ha kivételt dobnak a catch-en belül.
Aszinkron kódban a try-catch nem kapja el a más szálakból származó kivételeket. Kotlin Coroutines-ben használja a CoroutineExceptionHandler-t vagy a SupervisorJob-ot. Swift async/await-ben — do-catch-et a Task-on belül. Flutter-ben — runZonedGuarded-ot a globális elkapáshoz. Ennek a szabálynak a figyelmen kívül hagyása nehezen reprodukálható összeomlások oka a production környezetben.
A kivétel kezelése nem blokkolhatja a felhasználói felületet határozatlan ideig. Mutasson a felhasználónak konkrét üzenetet és adjon lehetőséget a művelet megismétlésére. Snackbar Retry gombbal Kotlin/Compose-ban, UIAlertController action-nel Swift-ben, SnackBar action-nel Flutter-ben — minimálisan elegendő UX hálózati vagy szerverhibák esetén. Kerülje az általános „Hiba történt" dialógusokat helyreállítási lehetőség nélkül.
Gyakran Ismételt Kérdések
A try-catch kivételeket és verem kitekerést használ a hibakezeléshez, ami sok hiba esetén teljesítmény szempontjából költséges lehet. Result Type egy konténer típus (Success vagy Failure), amely pattern matchingen keresztül kerül kezelésre verem kitekerés nélkül, ami hatékonyabb a várható hibákhoz.
A finally kötelező, ha a try blokk olyan erőforrásokat nyit meg (fájlok, socketek, kurzorok), amelyeket be kell zárni. Ha nem nyit meg erőforrásokat, a finally nem szükséges. Modern nyelvekben használja az AutoCloseable/use/defer függvényeket az erőforrások automatikus bezárásához finally nélkül. A use blokk Kotlin-ban és Swift-ben helyettesíti a finally-t a Closeable objektumoknál.
Normál folyamatban (kivétel nélkül) a try-catch gyakorlatilag nincs hatással a teljesítményre — a JVM és a Swift fordító optimalizálja ezt az esetet. De kivétel dobásakor verem kitekerés történik, ami a verem mélységétől függően 10–100 µs-ig tarthat. Ne használja a kivételeket a végrehajtási folyamat irányítására — ez antiminta.
Korutinokban használja a try-catch-et a coroutineScope-on belül vagy a CoroutineExceptionHandler-t a globális elkapáshoz. A SupervisorJob megakadályozza a szülő korutin visszavonását a gyermek korutin hibája esetén. A launch-hoz használjon CoroutineExceptionHandler-t, az async-hez — try-catch-et az await() körül.
A több catch előnyösebb: a kód lineárisan olvasható, minden blokk egy kivételtípust kezel. Egy catch if-else-sel nehezebben karbantartható, könnyen kihagyható egy új kivételtípus. Swift-ben a teljes körű enum Error kezeléshez több catch kötelező, Kotlin-ban nincs korlátozás, de a legjobb gyakorlat a típusonként külön catch.
Összefoglalás
Kulcsrakész mobilalkalmazást fejlesztünk
Az IT Sectr 2017 óta készít iOS és Android alkalmazásokat induló vállalkozásoknak és vállalkozásoknak. Tanácsot adunk, és a legjobb megoldást javasoljuk.
Olvassa el is