Try-Catch — konstrukce zachycení výjimek, která umožňuje provádět potenciálně nebezpečný kód v chráněném bloku a správně zpracovávat chyby bez náhlého ukončení programu. Blok try obsahuje kód, který může vyhodit výjimku, catch ji zachytí a provede logiku obnovy. Podle Apple Swift Documentation (2026) se blok finally provádí bez ohledu na to, zda byla výjimka vyhozena či nikoli, a zaručuje uvolnění prostředků.
Hlavní Body
Try-Catch — základní konstrukce strukturovaného zpracování výjimek, přítomná ve většině moderních programovacích jazyků. Skládá se ze tří bloků: try (pokus o provedení nebezpečného kódu), catch (zachycení a zpracování výjimky) a volitelného finally (finalizace). Myšlenkou konstrukce je oddělení logiky obchodních operací od logiky zpracování chyb, což činí kód čitelnějším a předvídatelnějším.
Koncepce byla poprvé implementována v jazyce C++ jako try/catch, poté převzata jazyky Java, C#, Swift, Kotlin, Dart, Python, JavaScript a dalšími. Každý jazyk přidává své vlastní rysy: ve Swift musí být blok catch vyčerpávající, v Kotlin může být try-catch výrazem (expression), v Dart je finally povinný pro prostředky proudu. Navzdory rozdílům je základní princip stejný: chyba je zpracována co nejblíže místu vzniku, nikoli globálně.
Použití Try-Catch je obzvláště důležité v mobilním vývoji, kde vnější faktory — ztráta sítě, nesprávná odpověď serveru, nedostatek paměti — neustále vznikají. Správné zpracování výjimek zabraňuje pádům aplikace a zajišťuje správné UX: uživatel obdrží chybovou zprávu místo náhlého zavření aplikace. Podle Google Android Kotlin Style Guide (2026) by každá funkce, která může vyhodit výjimku, měla buď ji zpracovat pomocí try-catch, nebo deklarovat throws v signatuře.
Mechanismus provádění try-catch je založen na odvíjení zásobníku (stack unwinding). Když je uvnitř bloku try vyhozena výjimka pomocí operátoru throw (nebo v důsledku systémové chyby), normální tok provádění je okamžitě přerušen. Provádění se přesune na vyšší úroveň zásobníku volání při hledání vhodného bloku catch. Moderní jazyky hledají catch s typem odpovídajícím typu vyhozené výjimky pomocí mechanismu porovnávání typů (type matching).
Pokud je nalezen odpovídající catch, provede se jeho tělo, poté provádění pokračuje za celou konstrukcí try-catch-finally. Pokud catch není nalezen, výjimka stoupá dále v zásobníku a může být zpracována na vyšší úrovni — až po globální handler, který v mobilní aplikaci zobrazí uživateli dialog s chybou. Pokud výjimka není zpracována nikde, aplikace spadne. Právě proto je správné zpracování všech možných typů výjimek kritické pro stabilitu aplikace.
fun readUserData(): User {
return try {
val response = api.fetchUser()
parseUser(response)
} catch (e: IOException) {
logError("Chyba sítě", e)
throw AppException("Nepodařilo se načíst data")
} catch (e: JsonParseException) {
logError("Chyba parsování", e)
return User.default()
} finally {
closeLoadingIndicator()
}
}
Kód se nejprve pokusí provést dotaz API a zpracovat odpověď. Pokud dojde k IOException (problém se sítí), výjimka je zalogována a předána dále jako AppException. Pokud JsonParseException — je vrácen výchozí uživatel. Blok finally zaručeně skryje indikátor načítání a zabraňuje úniku komponent UI na obrazovce.
Ve Swift je zpracování chyb implementováno prostřednictvím protokolu Error (dříve ErrorType). Jakýkoli typ kompatibilní s Error může být vyhozen pomocí operátoru throw. Funkce, která může vyhodit chybu, je označena klíčovým slovem throws v signatuře. Volání takové funkce vyžaduje předponu try (pro explicitní try-catch), try? (volitelný výsledek) nebo try! (vynucené provedení bez zpracování chyby).
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("Síť " + error.localizedDescription)
} catch {
showGenericError()
}
Enum NetworkError implementuje protokol Error a definuje tři případy: noConnection, serverError s kódem a timeout. Funkce fetchUser je označena throws: nejprve zkontroluje připojení, poté provede dotaz a zpracování. V bloku do-catch tři catch zpracovávají různé scénáře: specifický případ noConnection, obecný typ NetworkError a všechny ostatní chyby. To umožňuje zobrazovat uživateli různé zprávy v závislosti na typu problému.
Kotlin zdědil try-catch-finally od Javy, ale přidal důležitý rozdíl: v Kotlin je try-catch výraz (expression), nikoli příkaz (statement). To znamená, že výsledek bloku try nebo bloku catch lze přiřadit proměnné. Poslední výraz v bloku try se stává výsledkem při úspěchu, poslední výraz v catch — při chybě. Pokud chyba není zpracována žádným catchem, výjimka je předána výše v zásobníku.
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("Síť ", e)
Result.Error(e)
}
}
V příkladu sealed class Result obaluje úspěšnou odpověď nebo chybu. Funkce loadData používá try-catch jako výraz: při úspěchu vrací Result.Success, při výjimce HttpException nebo IOException — Result.Error s logováním. Tento přístup umožňuje volající straně zpracovávat chyby bez výjimek — pomocí when-výrazu podle typu Result. To je obzvláště výhodné v Jetpack Compose pro zobrazení různých stavů UI (Loading, Success, Error) prostřednictvím StateFlow a collectAsState.
Dart podporuje try-catch-finally se syntaxí podobnou Javě, ale s přidáním klauzule on pro filtrování podle typu výjimky bez uvedení proměnné. To je výhodné, když samotná výjimka není potřeba — důležitý je pouze fakt jejího typu. Dart také podporuje blok catch se dvěma parametry: objekt výjimky a StackTrace, což je užitečné pro logování celého řetězce volání.
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 je zachyceno s objektem a StackTrace pro podrobné logování, poté předáno jako AppException. FormatException je zachyceno bez proměnné — stačí vědět, že formát odpovědi je nesprávný. Blok finally zaručeně zavře HttpClient a zabraňuje úniku socketů. Ve Flutter je tento přístup obzvláště důležitý pro testování Widget, kde neošetřené výjimky v State.initState vedou k pádu celé testovací relace.
Dokonce i zkušení vývojáři dělají chyby při práci s try-catch, které vedou k únikům paměti, skrytým chybám nebo nevhodnému chování aplikace. Podívejme se na pět nejčastějších problémů v mobilním vývoji.
Prázdný catch — jedna z nejhorších praktik. Výjimka je spolknuta, aplikace pokračuje v činnosti v nesprávném stavu a vývojář se o problému nedozví. Vždy alespoň zalogujte výjimku. V Kotlin použijte catch(e: Exception) { Log.e(...) }, ve Swift — catch { print($0) }. V Dart by minimálně přijatelný catch měl volat debugPrint nebo zapisovat do Crashlytics.
Zachycování všech výjimek pomocí catch (Exception e) bez rozlišení podle typů skrývá neočekávané chyby — NullPointerException, OutOfMemoryError, StackOverflowError. Chytejte pouze ty typy, které očekáváte a můžete zpracovat. Pro zbytek povolte propagaci výše. V mobilním vývoji dávají specifické catch pro IOException, TimeoutException, AuthException smysluplnější zprávy uživateli.
Prostředky — soubory, sockety, kurzory DB, animace — by měly být uvolňovány v finally nebo v bloku use (AutoCloseable). Vývojáři často zapomínají zavírat prostředky při výjimce, což vede k únikům. V Kotlin použijte .use { } pro prostředky Closeable, ve Swift — defer { }, v Dart — await using z balíčku async. Blok finally zaručuje uvolnění i při vyhození výjimky uvnitř catch.
V asynchronním kódu try-catch nezachycuje výjimky z jiných vláken. V Kotlin Coroutines použijte CoroutineExceptionHandler nebo SupervisorJob. Ve Swift async/await — do-catch uvnitř Task. Ve Flutter — runZonedGuarded pro globální zachycení. Ignorování tohoto pravidla je příčinou obtížně reprodukovatelných pádů v produkci.
Zpracování výjimky by nemělo blokovat uživatelské rozhraní na neurčitou dobu. Ukažte uživateli konkrétní zprávu a dejte možnost operaci zopakovat. Snackbar s tlačítkem Retry v Kotlin/Compose, UIAlertController s action ve Swift, SnackBar s action ve Flutter — minimálně dostačující UX pro chyby sítě nebo serveru. Vyhněte se obecným dialogům „Došlo k chybě" bez možnosti obnovy.
Často kladené otázky
Try-catch používá pro zpracování chyb výjimky a odvíjení zásobníku, což může být při velkém počtu chyb výkonnostně nákladné. Result Type je typ-kontejner (Success nebo Failure), který je zpracováván pomocí pattern matching bez odvíjení zásobníku, což je efektivnější pro očekávané chyby.
Finally je povinný, pokud blok try otevírá prostředky (soubory, sockety, kurzory), které je třeba zavřít. Pokud se prostředky neotevírají, finally není vyžadován. V moderních jazycích použijte AutoCloseable/use/defer pro automatické zavírání prostředků bez finally. Blok use v Kotlin a Swift nahrazuje finally pro objekty Closeable.
V normálním toku (bez výjimky) try-catch prakticky neovlivňuje výkon — JVM a kompilátor Swift tento případ optimalizují. Ale při vyhození výjimky dochází k odvíjení zásobníku, což může trvat 10–100 µs v závislosti na hloubce zásobníku. Nepoužívejte výjimky pro řízení toku provádění — je to antivzor.
V korutinách použijte try-catch uvnitř coroutineScope nebo CoroutineExceptionHandler pro globální zachycení. SupervisorJob zabraňuje zrušení rodičovské korutiny při chybě v podřízené korutině. Pro launch použijte CoroutineExceptionHandler, pro async — try-catch kolem await().
Vícenásobné catch jsou preferovanější: kód se čte lineárně, každý blok zpracovává jeden typ výjimky. Jeden catch s if-else je obtížnější udržovat, snadno lze přehlédnout nový typ výjimky. Ve Swift jsou vícenásobné catch povinné pro vyčerpávající zpracování enum Error, v Kotlin neexistují omezení, ale nejlepší praxí je samostatný catch na typ.
Shrnutí
Vyvineme mobilní aplikaci na klíč
IT Sectr vytváří aplikace pro iOS a Android pro startupy a podniky od roku 2017. Poradíme vám a navrhneme nejlepší řešení.
Přečtěte si také