معالجة الأخطاء في Kotlin: try/catch وما بعدها
معالجة الأخطاء هي إحدى المهام الأساسية عند كتابة كود موثوق ومستقر. Kotlin، كلغة برمجة حديثة، تقدم للمطورين عدة أدوات قوية للتعامل مع الاستثناءات والمواقف غير الطبيعية. في هذه المقالة، سنشرح بالتفصيل الآلية الكلاسيكية try/catch، وميزات null safety، بالإضافة إلى الأساليب المتقدمة: استخدام Result والـ sealed classes. ستكون المادة مفيدة لكل من المبتدئين والمبرمجين ذوي الخبرة الذين يرغبون في تنظيم معرفتهم.
1. try/catch الكلاسيكي في Kotlin
Kotlin متوافق تمامًا مع Java ويدعم الكتلة التقليدية try/catch/finally. ومع ذلك، هناك اختلافات مهمة: في Kotlin، الاستثناءات هي unchecked (غير مُتحقق منها)، أي أن المترجم لا يُجبرك على معالجتها. هذا يجعل الكود أكثر إيجازًا، ولكنه يتطلب الانتباه.
الصيغة تبدو كالتالي:
try { // كود قد يرمي استثناءً val result = riskyOperation() println("النتيجة: $result")} catch (e: Exception) { // معالجة الاستثناء println("حدث خطأ: ${e.message}")} finally { // الكتلة تُنفذ في كل الأحوال println("إنهاء العملية")}في Kotlin، يمكن استخدام try كتعبير يُرجع قيمة:
val number: Int? = try { "123".toInt()} catch (e: NumberFormatException) { null}println(number) // سيُطبع: 123هذا مفيد بشكل خاص عندما تحتاج إلى الحصول على نتيجة أو قيمة افتراضية دون متغيرات إضافية.
2. Null Safety: منع الأخطاء على مستوى الأنواع
إحدى الميزات الرئيسية لـ Kotlin هي null safety. تحل اللغة مشكلة NullPointerException في مرحلة الترجمة. تنقسم الأنواع في Kotlin إلى nullable (يمكن أن تكون null) و non-null (لا يمكن).
مثال:
var name: String = "Kotlin" // لا يمكن أن تكون null// name = null // خطأ في الترجمة!
var nullableName: String? = "Kotlin" // يمكن أن تكون nullnullableName = null // يعملللعمل الآمن مع الأنواع nullable، تقدم Kotlin عدة عوامل تشغيل:
- ?. (safe call) — ينفذ العملية فقط إذا لم تكن القيمة null:
val length = nullableName?.length // إذا كانت null، فالنتيجة nullval length = nullableName?.length ?: 0val length = nullableName!!.length // إذا كانت null — استثناءاستخدام null safety بدلاً من try/catch للتحقق من null يجعل الكود أكثر قابلية للقراءة وأمانًا.
3. استخدام Result للنهج الوظيفي
توفر Kotlin فئة مدمجة Result<T>، والتي تمثل نتيجة عملية قد تنجح أو تفشل بخطأ. هذا بديل لـ try/catch يعتمد على البرمجة الوظيفية.
مثال على الاستخدام:
fun riskyDivision(a: Int, b: Int): Result<Int> { return runCatching { a / b }}
fun main() { val result = riskyDivision(10, 0)
result.onSuccess { value -> println("نجاح: $value") }.onFailure { error -> println("خطأ: ${error.message}") }
// أو يمكن الحصول على القيمة مع قيمة افتراضية val value = result.getOrDefault(0) println("القيمة: $value")}runCatching هي دالة تغليف مريحة تلتقط أي استثناءات وتُعيد Result. يمكنك دمج Result مع سلاسل الاستدعاءات، مما