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 ব্যবহার মোবাইল ডেভেলপমেন্টে বিশেষভাবে গুরুত্বপূর্ণ, যেখানে বাহ্যিক কারণ — নেটওয়ার্ক ক্ষতি, সার্ভারের ভুল প্রতিক্রিয়া, অপর্যাপ্ত মেমরি — নিয়মিত ঘটে। সঠিক ব্যতিক্রম পরিচালনা অ্যাপ্লিকেশন ক্র্যাশ প্রতিরোধ করে এবং সঠিক UX নিশ্চিত করে: ব্যবহারকারী হঠাৎ অ্যাপ্লিকেশন বন্ধ হওয়ার পরিবর্তে একটি ত্রুটি বার্তা দেখে। 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 — নেটওয়ার্ক বা সার্ভার ত্রুটির জন্য ন্যূনতম পর্যাপ্ত UX। পুনরুদ্ধার বিকল্প ছাড়া সাধারণ “একটি ত্রুটি ঘটেছে” ডায়ালগ এড়িয়ে চলুন।
সচরাচর জিজ্ঞাসিত প্রশ্ন
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 নিতে পারে। প্রবাহ নিয়ন্ত্রণের জন্য ব্যতিক্রম ব্যবহার করবেন না — এটি একটি অ্যান্টি-প্যাটার্ন।
Coroutine-এ, বৈশ্বিক ধরার জন্য 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 অ্যাপ্লিকেশন তৈরি করে। আমরা আপনাকে পরামর্শ দেব এবং সেরা সমাধান প্রস্তাব করব।
আরও পড়ুন