Try-Catch, potansiyel olarak tehlikeli kodun korumalı bir blokta çalıştırılmasına ve program çökmeden hataların doğru şekilde ele alınmasına olanak tanıyan bir istisna yakalama yapısıdır. try bloğu istisna fırlatabilecek kodu içerir, catch onu yakalar ve kurtarma mantığını çalıştırır. Apple Swift Documentation (2026)'ya göre, finally bloğu istisna fırlatılsın veya fırlatılmasın çalıştırılır ve kaynakların serbest bırakılmasını garanti eder.
Önemli Noktalar
Try-Catch, çoğu modern programlama dilinde bulunan temel bir yapısal istisna işleme yapısıdır. Üç bloktan oluşur: try (tehlikeli kodu çalıştırma girişimi), catch (istisnayı yakalama ve işleme) ve isteğe bağlı finally (sonlandırma). Yapının fikri, iş mantığını hata işleme mantığından ayırarak kodu daha okunabilir ve öngörülebilir hale getirmektir.
Kavram ilk olarak C++'da try/catch olarak uygulanmış, daha sonra Java, C#, Swift, Kotlin, Dart, Python, JavaScript ve diğer diller tarafından benimsenmiştir. Her dil kendi özelliklerini ekler: Swift'te catch bloğu kapsamlı olmalıdır, Kotlin'de try-catch bir ifade olabilir, Dart'ta akış kaynakları için finally zorunludur. Farklılıklara rağmen, temel prensip aynıdır: bir hata küresel olarak değil, oluşma noktasına mümkün olduğunca yakın bir yerde işlenir.
Try-Catch kullanımı mobil geliştirmede özellikle önemlidir, çünkü ağ kaybı, yanlış sunucu yanıtı, yetersiz bellek gibi dış etkenler sürekli olarak ortaya çıkar. Doğru istisna yönetimi, uygulama çökmelerini önler ve doğru kullanıcı deneyimi sağlar: kullanıcı aniden kapanan bir uygulama yerine bir hata mesajı görür. Google Android Kotlin Style Guide (2026)'ya göre, istisna fırlatabilecek her işlev, bunu try-catch aracılığıyla işlemeli veya imzasında throws bildirmelidir.
try-catch'in yürütme mekanizması yığın açma (stack unwinding) temeline dayanır. try bloğu içinde throw operatörü aracılığıyla (veya bir sistem hatası sonucu) bir istisna fırlatıldığında, normal yürütme akışı derhal kesintiye uğrar. Yürütme, uygun bir catch bloğu aramak için çağrı yığınında bir seviye yukarı hareket eder. Modern diller, tür eşleştirme mekanizması (type matching) kullanarak fırlatılan istisnanın türüyle eşleşen bir catch arar.
Eşleşen bir catch bulunursa, gövdesi çalıştırılır ve ardından tüm try-catch-finally yapısından sonra yürütme devam eder. Hiçbir catch bulunamazsa, istisna yığında daha yukarı çıkar ve daha üst düzeyde işlenebilir — mobil uygulamada kullanıcıya bir hata iletişim kutusu gösteren küresel bir işleyiciye kadar. İstisna hiçbir yerde işlenmezse, uygulama çöker. Bu nedenle, tüm olası istisna türlerinin doğru şekilde işlenmesi uygulama kararlılığı için kritiktir.
fun readUserData(): User {
return try {
val response = api.fetchUser()
parseUser(response)
} catch (e: IOException) {
logError("Ağ hatası", e)
throw AppException("Veriler yüklenemedi")
} catch (e: JsonParseException) {
logError("Ayrıştırma hatası", e)
return User.default()
} finally {
closeLoadingIndicator()
}
}
Kod önce bir API isteği yapmayı ve yanıtı ayrıştırmayı dener. Bir IOException (ağ sorunu) oluşursa, istisna günlüğe kaydedilir ve AppException olarak yeniden fırlatılır. Bir JsonParseException oluşursa — varsayılan bir kullanıcı döndürülür. finally bloğu, yükleme göstergesini gizlemeyi garanti ederek ekranda UI bileşeni sızıntılarını önler.
Swift'te hata yönetimi, Error protokolü (eski adıyla ErrorType) aracılığıyla uygulanır. Error'a uyan herhangi bir tür, throw operatörü aracılığıyla fırlatılabilir. Hata fırlatabilecek bir işlev, imzasında throws anahtar sözcüğüyle işaretlenir. Böyle bir işlevi çağırmak için try öneki (açık try-catch için), try? (isteğe bağlı sonuç) veya try! (hata yönetimi olmadan zorunlu yürütme) gerekir.
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("Ağ " + error.localizedDescription)
} catch {
showGenericError()
}
NetworkError enum'u Error protokolünü uygulayarak üç durum tanımlar: noConnection, kodlu serverError ve timeout. fetchUser işlevi throws ile işaretlenmiştir: önce bağlantıyı kontrol eder, ardından isteği ve ayrıştırmayı gerçekleştirir. do-catch bloğunda, üç catch farklı senaryoları işler: belirli noConnection durumu, genel NetworkError türü ve diğer tüm hatalar. Bu, sorun türüne göre kullanıcıya farklı mesajlar gösterilmesini sağlar.
Kotlin, Java'dan try-catch-finally'yi devraldı ancak önemli bir fark ekledi: Kotlin'de try-catch bir ifade (expression)'dir, bir deyim (statement) değil. Bu, try bloğunun veya catch bloğunun sonucunun bir değişkene atanabileceği anlamına gelir. try bloğundaki son ifade başarı durumunda sonuç olur, catch'teki son ifade ise hata durumunda sonuç olur. Hata hiçbir catch tarafından işlenmezse, istisna yığında yukarı çıkar.
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("Ağ ", e)
Result.Error(e)
}
}
Örnekte, sealed class Result başarılı bir yanıtı veya bir hatayı sarar. loadData işlevi try-catch'i bir ifade olarak kullanır: başarıda Result.Success döndürür, HttpException veya IOException'da — günlükleme ile Result.Error döndürür. Bu yaklaşım, çağıran tarafın istisnalar olmadan hataları işlemesine olanak tanır — Result türünde bir when ifadesi aracılığıyla. Bu, Jetpack Compose'ta StateFlow ve collectAsState aracılığıyla farklı UI durumlarını (Loading, Success, Error) görüntülemek için özellikle uygundur.
Dart, Java'ya benzer sözdizimiyle try-catch-finally'yi destekler, ancak bir değişken belirtmeden istisna türüne göre filtreleme için bir on cümlesi eklenmiştir. Bu, istisnanın kendisi gerekli olmadığında kullanışlıdır — yalnızca türünün gerçeği önemlidir. Dart ayrıca iki parametreli bir catch bloğunu da destekler: istisna nesnesi ve StackTrace, tam çağrı zincirini günlüğe kaydetmek için kullanışlıdır.
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, ayrıntılı günlük kaydı için istisna nesnesi ve StackTrace ile yakalanır, ardından AppException olarak yeniden fırlatılır. FormatException değişken olmadan yakalanır — yanıt biçiminin yanlış olduğunu bilmek yeterlidir. finally bloğu, HttpClient'ı kapatmayı garanti ederek soket sızıntılarını önler. Flutter'da bu yaklaşım, Widget testleri için özellikle önemlidir, çünkü State.initState'te işlenmeyen istisnalar tüm test oturumunu çökertebilir.
Deneyimli geliştiriciler bile try-catch ile çalışırken bellek sızıntılarına, gizli hatalara veya uygunsuz uygulama davranışına yol açan hatalar yapar. Mobil geliştirmedeki en yaygın beş soruna bakalım.
Boş catch en kötü uygulamalardan biridir. İstisna yutulur, uygulama hatalı bir durumda çalışmaya devam eder ve geliştirici sorundan haberdar olmaz. Her zaman en azından istisnayı günlüğe kaydedin. Kotlin'de catch(e: Exception) { Log.e(...) }, Swift'te — catch { print($0) } kullanın. Dart'ta, minimum kabul edilebilir catch, debugPrint çağırmalı veya Crashlytics'e yazmalıdır.
Türlere göre ayırt etmeden catch (Exception e) aracılığıyla tüm istisnaları yakalamak, beklenmeyen hataları — NullPointerException, OutOfMemoryError, StackOverflowError — gizler. Yalnızca beklediğiniz ve işleyebileceğiniz türleri yakalayın. Geri kalan her şey için yukarı yayılmaya izin verin. Mobil geliştirmede, IOException, TimeoutException, AuthException için belirli catch blokları kullanıcıya daha anlamlı mesajlar verir.
Kaynaklar — dosyalar, soketler, DB imleçleri, animasyonlar — finally'de veya bir use bloğunda (AutoCloseable) serbest bırakılmalıdır. Geliştiriciler genellikle bir istisna oluştuğunda kaynakları kapatmayı unutur ve bu da sızıntılara yol açar. Kotlin'de Closeable kaynaklar için .use { }, Swift'te — defer { }, Dart'ta — async paketinden await using kullanın. finally bloğu, catch içinde bir istisna fırlatılsa bile serbest bırakmayı garanti eder.
Zamansız kodda try-catch, diğer iş parçacıklarından gelen istisnaları yakalamaz. Kotlin Coroutines'te CoroutineExceptionHandler veya SupervisorJob kullanın. Swift async/await'te — Task içinde do-catch. Flutter'da — küresel yakalama için runZonedGuarded. Bu kuralı görmezden gelmek, üretimde tekrarlanması zor çökmelerin nedenidir.
İstisna işleme, kullanıcı arayüzünü belirsiz bir süre boyunca bloke etmemelidir. Kullanıcıya belirli bir mesaj gösterin ve işlemi yeniden deneme fırsatı verin. Kotlin/Compose'da Retry düğmesiyle Snackbar, Swift'te UIAlertController, Flutter'da SnackBar — ağ veya sunucu hataları için minimum yeterli kullanıcı deneyimi. Kurtarma seçenekleri olmayan genel “Bir hata oluştu” iletişim kutularından kaçının.
Sıkça Sorulan Sorular
Try-catch, hata işleme için istisnalar ve yığın açma kullanır, bu da çok sayıda hata olduğunda performans açısından maliyetli olabilir. Result Type, yığın açma olmadan desen eşleme yoluyla işlenen bir kapsayıcı türüdür (Success veya Failure), beklenen hatalar için daha verimlidir.
Finally, try bloğu kapatılması gereken kaynaklar (dosyalar, soketler, imleçler) açıyorsa zorunludur. Hiçbir kaynak açılmazsa, finally gerekli değildir. Modern dillerde, finally olmadan otomatik kaynak kapatma için AutoCloseable/use/defer kullanın. Kotlin ve Swift'teki use bloğu, Closeable nesneler için finally'nin yerini alır.
Normal akışta (istisnasız), try-catch performansı pratikte etkilemez — JVM ve Swift derleyicisi bu durumu optimize eder. Ancak bir istisna fırlatıldığında, yığın açma gerçekleşir ve bu, yığın derinliğine bağlı olarak 10–100 μs sürebilir. Akış kontrolü için istisnaları kullanmayın — bu bir anti-kalıptır.
Coroutine'lerde, küresel yakalama için coroutineScope içinde try-catch veya CoroutineExceptionHandler kullanın. SupervisorJob, alt coroutine başarısız olduğunda üst coroutine'in iptal edilmesini önler. launch için CoroutineExceptionHandler, async için — await() çevresinde try-catch kullanın.
Birden çok catch tercih edilir: kod doğrusal olarak okunur, her blok bir istisna türünü işler. if-else'li tek bir catch bakımı daha zordur ve yeni bir istisna türünü kaçırmak kolaydır. Swift'te, enum Error'ın kapsamlı işlenmesi için birden çok catch zorunludur, Kotlin'de kısıtlama yoktur ancak en iyi uygulama tür başına ayrı catch kullanmaktır.
Özet
Anahtar teslim bir mobil uygulama geliştireceğiz
IT Sectr, 2017'den beri girişimler ve işletmeler için iOS ve Android uygulamaları oluşturmaktadır. Size danışmanlık yapacak ve en iyi çözümü önereceğiz.
Ayrıca okuyun