Try-Catch ایک استثنا پکڑنے کا ڈھانچہ ہے جو ممکنہ طور پر خطرناک کوڈ کو محفوظ بلاک میں چلانے اور پروگرام کو کریش کیے بغیر غلطیوں کو درست طریقے سے ہینڈل کرنے کی اجازت دیتا ہے۔ try بلاک میں وہ کوڈ ہوتا ہے جو استثنا پھینک سکتا ہے، catch اسے پکڑتا ہے اور بحالی کا منطق چلاتا ہے۔ Apple Swift Documentation (2026) کے مطابق، finally بلاک اس بات سے قطع نظر کہ استثنا پھینکا گیا یا نہیں، چلتا ہے، وسائل کی رہائی کو یقینی بناتا ہے۔
اہم نکات
Try-Catch ایک بنیادی ساختی استثنا ہینڈلنگ ڈھانچہ ہے جو زیادہ تر جدید پروگرامنگ زبانوں میں موجود ہے۔ یہ تین بلاکس پر مشتمل ہے: try (خطرناک کوڈ چلانے کی کوشش)، catch (استثنا کو پکڑنا اور ہینڈل کرنا) اور اختیاری finally (اختتام)۔ ڈھانچے کا خیال کاروباری منطق کو غلطی ہینڈلنگ کی منطق سے الگ کرنا ہے، کوڈ کو مزید پڑھنے کے قابل اور پیش قیاس بنانا ہے۔
اس تصور کو سب سے پہلے C++ میں try/catch کے طور پر لاگو کیا گیا، پھر Java، C#، Swift، Kotlin، Dart، Python، JavaScript اور دیگر زبانوں نے اپنایا۔ ہر زبان اپنی خصوصیات شامل کرتی ہے: Swift میں catch بلاک کو جامع ہونا چاہیے، Kotlin میں try-catch ایک ایکسپریشن ہو سکتا ہے، Dart میں سٹریم وسائل کے لیے finally لازمی ہے۔ اختلافات کے باوجود، بنیادی اصول ایک ہی ہے: غلطی کو عالمی طور پر نہیں بلکہ وقوع کے مقام کے جتنا ممکن ہو قریب ہینڈل کیا جاتا ہے۔
Try-Catch کا استعمال موبائل ڈویلپمنٹ میں خاص طور پر اہم ہے، جہاں بیرونی عوامل — نیٹ ورک کا نقصان، سرور کا غلط جواب، ناکافی میموری — مسلسل ہوتے رہتے ہیں۔ مناسب استثنا ہینڈلنگ ایپلیکیشن کو کریش ہونے سے روکتی ہے اور درست یوزر تجربہ کو یقینی بناتی ہے: صارف اچانک ایپلیکیشن بند ہونے کے بجائے ایک غلطی کا پیغام دیکھتا ہے۔ Google Android Kotlin Style Guide (2026) کے مطابق، ہر فنکشن جو استثنا پھینک سکتا ہے، اسے یا تو try-catch کے ذریعے ہینڈل کرنا چاہیے یا اپنے دستخط میں throws اعلان کرنا چاہیے۔
try-catch کا عمل درآمد میکانزم اسٹیک انوائنڈنگ (stack unwinding) پر مبنی ہے۔ جب try بلاک کے اندر throw آپریٹر کے ذریعے (یا سسٹم کی غلطی کے نتیجے میں) ایک استثنا پھینکا جاتا ہے، تو عام عمل کا بہاؤ فوری طور پر روک دیا جاتا ہے۔ عمل درآمد مناسب catch بلاک کی تلاش میں کال اسٹیک میں ایک سطح اوپر چلا جاتا ہے۔ جدید زبانیں قسم مماثلت کا طریقہ کار (type matching) استعمال کرتے ہوئے پھینکے گئے استثنا کی قسم سے مماثل catch تلاش کرتی ہیں۔
اگر مماثل catch مل جاتا ہے، تو اس کا باڈی چلایا جاتا ہے، جس کے بعد پوری try-catch-finally ساخت کے بعد عمل جاری رہتا ہے۔ اگر کوئی catch نہیں ملتا، تو استثنا اسٹیک میں مزید اوپر جاتا ہے اور اونچی سطح پر ہینڈل کیا جا سکتا ہے — ایک عالمی ہینڈلر تک، جو موبائل ایپلیکیشن میں صارف کو غلطی کا ڈائیلاگ دکھاتا ہے۔ اگر استثنا کہیں بھی ہینڈل نہیں کیا جاتا، تو ایپلیکیشن کریش ہو جاتی ہے۔ یہی وجہ ہے کہ تمام ممکنہ استثنا اقسام کا درست ہینڈلنگ ایپلیکیشن کے استحکام کے لیے اہم ہے۔
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 اجزاء کے رساؤ کو روکتا ہے۔
Swift میں، غلطی کا نظم Error پروٹوکول (پہلے ErrorType) کے ذریعے لاگو کیا گیا ہے۔ Error کے مطابق کوئی بھی قسم throw آپریٹر کے ذریعے پھینکی جا سکتی ہے۔ جو فنکشن غلطی پھینک سکتا ہے، اس کے دستخط میں throws کلیدی لفظ سے نشان زد کیا جاتا ہے۔ ایسے فنکشن کو کال کرنے کے لیے try سابقہ (واضح try-catch کے لیے)، try? (اختیاری نتیجہ) یا try! (غلطی ہینڈلنگ کے بغیر جبری عمل) کی ضرورت ہوتی ہے۔
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 قسم اور دیگر تمام غلطیاں۔ یہ مسئلہ کی قسم کے مطابق صارف کو مختلف پیغامات دکھانے کی اجازت دیتا ہے۔
Kotlin نے Java سے try-catch-finally وراثت میں لیا لیکن ایک اہم فرق شامل کیا: Kotlin میں، try-catch ایک ایکسپریشن (expression) ہے، بیان (statement) نہیں۔ اس کا مطلب ہے کہ try بلاک یا catch بلاک کا نتیجہ ایک متغیر کو تفویض کیا جا سکتا ہے۔ try بلاک میں آخری ایکسپریشن کامیابی پر نتیجہ بن جاتا ہے، catch میں آخری ایکسپریشن — غلطی پر۔ اگر غلطی کسی catch سے ہینڈل نہیں ہوتی، تو استثنا اسٹیک میں اوپر جاتا ہے۔
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۔ یہ طریقہ کار کالر کو استثنا کے بغیر غلطیوں کو ہینڈل کرنے کی اجازت دیتا ہے — Result قسم پر when ایکسپریشن کے ذریعے۔ یہ Jetpack Compose میں StateFlow اور collectAsState کے ذریعے مختلف UI حالتیں (Loading, Success, Error) دکھانے کے لیے خاص طور پر آسان ہے۔
Dart Java جیسے نحو کے ساتھ try-catch-finally کو سپورٹ کرتا ہے، لیکن ایک متغیر متعین کیے بغیر استثنا کی قسم کے مطابق فلٹر کرنے کے لیے ایک on شق کے اضافے کے ساتھ۔ یہ اس وقت آسان ہے جب خود استثنا کی ضرورت نہ ہو — صرف اس کی قسم کی حقیقت اہم ہے۔ Dart دو پیرامیٹرز کے ساتھ catch بلاک کو بھی سپورٹ کرتا ہے: استثنا آبجیکٹ اور StackTrace، جو مکمل کال چین کو لاگ کرنے کے لیے مفید ہے۔
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 کے ساتھ کام کرتے ہوئے غلطیاں کرتے ہیں جو میموری رساؤ، پوشیدہ بگز یا ایپلیکیشن کے نامناسب رویے کا سبب بنتی ہیں۔ آئیے موبائل ڈویلپمنٹ میں پانچ سب سے عام مسائل دیکھتے ہیں۔
خالی catch بدترین طریقوں میں سے ایک ہے۔ استثنا نگل لیا جاتا ہے، ایپلیکیشن غلط حالت میں کام کرتی رہتی ہے اور ڈویلپر کو مسئلے کا علم نہیں ہوتا۔ ہمیشہ کم از کم استثنا کو لاگ کریں۔ Kotlin میں catch(e: Exception) { Log.e(...) }، Swift میں — catch { print($0) } استعمال کریں۔ Dart میں، کم از کم قابل قبول catch کو debugPrint کال کرنا چاہیے یا Crashlytics میں لکھنا چاہیے۔
اقسام میں فرق کیے بغیر catch (Exception e) کے ذریعے تمام استثنا پکڑنا غیر متوقع غلطیاں — NullPointerException، OutOfMemoryError، StackOverflowError چھپا دیتا ہے۔ صرف وہی اقسام پکڑیں جن کی آپ توقع کرتے ہیں اور ہینڈل کر سکتے ہیں۔ باقی سب کے لیے، اوپر پھیلنے کی اجازت دیں۔ موبائل ڈویلپمنٹ میں، IOException، TimeoutException، AuthException کے لیے مخصوص catch صارف کو زیادہ معنی خیز پیغامات دیتے ہیں۔
وسائل — فائلیں، ساکٹ، DB کرسرز، اینیمیشن — finally میں یا use بلاک (AutoCloseable) میں خالی کیے جانے چاہئیں۔ ڈویلپرز اکثر استثنا ہونے پر وسائل بند کرنا بھول جاتے ہیں، جو رساؤ کا سبب بنتا ہے۔ Kotlin میں Closeable وسائل کے لیے .use { }، Swift میں — defer { }، Dart میں — async پیکج سے await using استعمال کریں۔ finally بلاک catch کے اندر استثنا پھینکے جانے پر بھی رہائی کو یقینی بناتا ہے۔
غیر متزامن کوڈ میں، try-catch دوسرے تھریڈز سے استثنا نہیں پکڑتا۔ Kotlin Coroutines میں CoroutineExceptionHandler یا SupervisorJob استعمال کریں۔ Swift async/await میں — Task کے اندر do-catch۔ Flutter میں — عالمی پکڑ کے لیے runZonedGuarded۔ اس اصول کو نظر انداز کرنا پروڈکشن میں مشکل سے دوبارہ پیدا ہونے والے کریشز کا سبب ہے۔
استثنا ہینڈلنگ کو یوزر انٹرفیس کو غیر معینہ مدت تک بلاک نہیں کرنا چاہیے۔ صارف کو ایک مخصوص پیغام دکھائیں اور انہیں آپریشن دوبارہ کرنے کا موقع دیں۔ Kotlin/Compose میں Retry بٹن کے ساتھ Snackbar، Swift میں UIAlertController، Flutter میں SnackBar — نیٹ ورک یا سرور کی غلطیوں کے لیے کم از کم کافی یوزر تجربہ۔ بحالی کے اختیارات کے بغیر عام “ایک غلطی ہوئی” ڈائیلاگ سے بچیں۔
اکثر پوچھے گئے سوالات
Try-catch غلطی ہینڈلنگ کے لیے استثنا اور اسٹیک انوائنڈنگ استعمال کرتا ہے، جو بہت سی غلطیوں سے نمٹنے پر کارکردگی میں مہنگا ہو سکتا ہے۔ Result Type ایک کنٹینر قسم ہے (Success یا Failure) جو اسٹیک انوائنڈنگ کے بغیر پیٹرن میچنگ کے ذریعے ہینڈل کیا جاتا ہے، متوقع غلطیوں کے لیے زیادہ موثر ہے۔
Finally ضروری ہے اگر try بلاک وسائل (فائلیں، ساکٹ، کرسرز) کھولتا ہے جنہیں بند کرنے کی ضرورت ہے۔ اگر کوئی وسائل نہیں کھولے جاتے، finally کی ضرورت نہیں ہے۔ جدید زبانوں میں finally کے بغیر خودکار وسائل بند کرنے کے لیے AutoCloseable/use/defer استعمال کریں۔ Kotlin اور Swift میں use بلاک Closeable آبجیکٹس کے لیے finally کی جگہ لیتا ہے۔
عام بہاؤ میں (استثنا کے بغیر)، try-catch عملی طور پر کارکردگی کو متاثر نہیں کرتا — JVM اور Swift کمپائلر اس کیس کو بہتر بناتے ہیں۔ لیکن جب استثنا پھینکا جاتا ہے، اسٹیک انوائنڈنگ ہوتی ہے، جو اسٹیک کی گہرائی کے لحاظ سے 10–100 μs لے سکتی ہے۔ بہاؤ کنٹرول کے لیے استثنا استعمال نہ کریں — یہ ایک اینٹی پیٹرن ہے۔
Coroutines میں، عالمی پکڑ کے لیے coroutineScope کے اندر try-catch یا CoroutineExceptionHandler استعمال کریں۔ SupervisorJob چائلڈ coroutine کے ناکام ہونے پر پیرنٹ coroutine کو منسوخ ہونے سے روکتا ہے۔ launch کے لیے CoroutineExceptionHandler، async کے لیے — await() کے ارد گرد try-catch استعمال کریں۔
ایک سے زیادہ catch بہتر ہیں: کوڈ لکیری طور پر پڑھا جاتا ہے، ہر بلاک ایک استثنا قسم کو ہینڈل کرتا ہے۔ if-else والا ایک catch برقرار رکھنا مشکل ہے اور نئی استثنا قسم کو نظر انداز کرنا آسان ہے۔ Swift میں، enum Error کے جامع ہینڈلنگ کے لیے ایک سے زیادہ catch لازمی ہیں، Kotlin میں کوئی پابندی نہیں ہے، لیکن بہترین عمل یہ ہے کہ ہر قسم کے لیے علیحدہ catch ہو۔
خلاصہ
ہم ایک موبائل ایپلیکیشن ٹرنکی تیار کریں گے
IT Sectr 2017 سے اسٹارٹ اپس اور کاروبار کے لیے iOS اور Android ایپلیکیشنز بناتا ہے۔ ہم آپ کو مشورہ دیں گے اور بہترین حل تجویز کریں گے۔
مزید پڑھیں