إعادة رمي الاستثناءات وتسلسلها
أعد رمي الاستثناءات انتقائيًا، وغلّف الأخطاء منخفضة المستوى مع تسلسل السبب.
إعادة رمي الاستثناءات وتسلسلها درس مجاني في Kotlin Academy على CoddyKit. هذا هو الدرس 4 من أصل 4. يمكنك قراءة الدرس كاملاً أدناه مجاناً — ثم تمرن عليه مباشرة في المتصفح باستخدام محرر أكواد مدمج ومدرس ذكاء اصطناعي متاح 24/7. هذا الدرس جزء من مسار التعلم في Kotlin Academy، وتقدمك يتزامن عبر الويب وتطبيق CoddyKit. تتضمن دورة Kotlin Academy 4 دروس في المجموع.
إعادة إطلاق الاستثناءات وتغليفها
قد تلتقط استثناءً أحيانًا فقط من أجل تسجيله أو تغليفه أو تحويله قبل السماح باستثناء أكثر تحديدًا بالانتشار. وتجعل Kotlin هذا الأسلوب طبيعيًا.
إعادة إطلاق مباشرة
لإعادة إطلاق الاستثناء، ما عليك سوى استخدام throw e مرة أخرى، وسيستمر انتشاره إلى المعالج التالي.
fun main() {
try {
try { "x".toInt() }
catch (e: NumberFormatException) {
println("logging: ${e.message}")
throw e // re-throw original
}
} catch (e: NumberFormatException) {
println("outer caught: ${e.message}")
}
}تغليف الاستثناء باستثناء مخصص
مرّر الاستثناء الأصلي باعتباره cause عند إنشاء استثناء جديد للحفاظ على السلسلة.
class ParseException(msg: String, cause: Throwable) : RuntimeException(msg, cause)
fun main() {
try {
try { "xyz".toInt() }
catch (e: NumberFormatException) {
throw ParseException("could not parse user input", e)
}
} catch (e: ParseException) {
println("got: ${e.message}")
println("cause: ${e.cause?.message}")
}
}فحص سلسلة الأسباب
تربط الخاصية cause الاستثناء الحالي بالاستثناء السابق. تتبّعها لطباعة السبب الجذري الكامل.
fun main() {
val e = RuntimeException("top",
RuntimeException("middle",
RuntimeException("root")))
var current: Throwable? = e
while (current != null) {
println(current.message)
current = current.cause
}
}إعادة إطلاق انتقائية
التقط نوعًا عامًا، ثم أعد إطلاقه إذا لم يطابق الحالة المتوقعة.
fun parseRequired(s: String): Int {
try {
return s.toInt()
} catch (e: NumberFormatException) {
if (s.isBlank()) return 0
throw e // unexpected — let it propagate
}
}
fun main() {
println(parseRequired("42"))
println(parseRequired(""))
// parseRequired("abc") // throws
}إضافة السياق
غلّف الاستثناء باستثناء خاص بالمجال لإضافة سياق لم يكن موجودًا في الأصل، مثل الإدخال ومعرّف الطلب وغير ذلك.
class UploadError(msg: String, cause: Throwable) : RuntimeException(msg, cause)
fun upload(file: String) {
try { throw RuntimeException("disk full") }
catch (e: Throwable) { throw UploadError("uploading $file failed", e) }
}
fun main() {
try { upload("photo.jpg") }
catch (e: UploadError) { println("${e.message} <- ${e.cause?.message}") }
}لا تفقد Stack Trace
عند التغليف، مرّر الاستثناء الأصلي دائمًا باعتباره cause، ولا تنشئ استثناءً جديدًا بالرسالة نفسها من دون سبب. إذ يُعد Stack Trace شريان حياتك عند تصحيح الأخطاء.
class Wrapped(m: String, cause: Throwable) : RuntimeException(m, cause)
fun main() {
try {
try { error("inner") }
catch (e: Throwable) { throw Wrapped("outer", e) }
} catch (e: Wrapped) {
println("message: ${e.message}")
println("cause: ${e.cause?.message}")
}
}إعادة الإطلاق دون تغليف
إذا كان التسجيل هو كل ما تحتاج إليه، فاستخدم throw e بعد استدعاء التسجيل، ولا حاجة إلى التغليف.
fun risky() {
try { throw IllegalStateException("oops") }
catch (e: IllegalStateException) {
println("Logging before rethrow: ${e.message}")
throw e
}
}
fun main() {
try { risky() }
catch (e: IllegalStateException) { println("outer: ${e.message}") }
}استخدام finally لتنظيف الموارد أثناء إعادة الإطلاق
استخدم finally لتنظيف الموارد حتى عند إعادة إطلاق الاستثناء.
fun process() {
try {
throw RuntimeException("failure")
} finally {
println("cleanup ran")
}
}
fun main() {
try { process() }
catch (e: RuntimeException) { println("caught: ${e.message}") }
}الاستثناءات المكبوتة
إذا أطلقت finally نفسها استثناءً، فسيُكبت الاستثناء الأصلي افتراضيًا. استخدم addSuppressed للحفاظ على كليهما.
fun main() {
val primary = RuntimeException("primary")
val secondary = RuntimeException("from cleanup")
primary.addSuppressed(secondary)
println(primary.suppressed.joinToString { it.message ?: "?" })
}نمط مضاد: ابتلاع الاستثناء ثم إطلاق استثناء مختلف
التقاط استثناء ثم طرح استثناء جديد غير مرتبط به (من دون سبب) يؤدي إلى فقدان معلومات تصحيح الأخطاء. مرّروا دائمًا cause.
// BAD
// catch (e: IOException) { throw RuntimeException("error") }
// GOOD
// catch (e: IOException) { throw RuntimeException("error reading config", e) }
fun main() { println("Pass cause when re-throwing!") }تحقق سريع
عند تغليف استثناء داخل استثناء جديد، ما الذي ينبغي فعله للحفاظ على تتبّع المكدس الأصلي؟
مراجعة
لإعادة الطرح: throw e. وللتغليف: اطرح استثناءً جديدًا مع cause = e. حافظوا دائمًا على سلسلة الأسباب، ولا تنشئوا أبدًا غلافًا بلا سبب. استخدموا finally للتنظيف، وaddSuppressed عندما تفشل عملية التنظيف نفسها.
تعلم Kotlin مع معلم ذكاء اصطناعي — مجانًا
اكتب وقم بتشغيل أكوادك الفعلية في المتصفح، واحصل على مساعدة فورية من معلم ذكاء اصطناعي متاح 24/7، واستمر من حيث توقفت على الويب أو في التطبيق.
- الدورات
- 51
- الدروس
- 203
الأسئلة الشائعة
هل درس «إعادة رمي الاستثناءات وتسلسلها» مجاني؟
نعم — نص درس «إعادة رمي الاستثناءات وتسلسلها» كامل متاح مجاناً هنا على الويب. لتمرينه بشكل تفاعلي (محرر أكواد مدمج ومدرس ذكاء اصطناعي متاح 24/7) وفتح باقي دورة Kotlin Academy، انتقل إلى CoddyKit PRO. تتضمن دورة Kotlin Academy 4 دروس في المجموع.
ماذا ستتعلم في «إعادة رمي الاستثناءات وتسلسلها»؟
أعد رمي الاستثناءات انتقائيًا، وغلّف الأخطاء منخفضة المستوى مع تسلسل السبب. تتمرن على Kotlin Academy مع أكواد عملية تشغلها مباشرة في المتصفح، ومدرس ذكاء اصطناعي متاح 24/7 يجيب على أسئلتك أثناء عملك.
هل أحتاج إلى خبرة سابقة لأبدأ Kotlin Academy؟
لا تُشترط خبرة سابقة. Kotlin Academy على CoddyKit منظم للمبتدئين حتى المتقدمين، لذا يمكنك البدء من هنا أو من البداية والتقدم بسرعتك الخاصة. هذا هو الدرس 4 من أصل 4.
كم من الوقت يستغرق درس «إعادة رمي الاستثناءات وتسلسلها»؟
معظم دروس CoddyKit تستغرق حوالي 5–10 دقائق. كل منها موجز وتفاعلي، لذا تحرز تقدماً مستمراً وتستأنف من حيث توقفت عبر الويب والتطبيق.
هل يمكنني كتابة وتشغيل أكواد في درس Kotlin Academy هذا؟
نعم. كل درس في Kotlin Academy يتضمن محرر أكواد مدمج، لذا تكتب وتشغل أكواداً حقيقية مباشرة في متصفحك وتحصل على تعليقات فورية من الذكاء الاصطناعي — بدون إعداد محلي.
جميع الدروس في هذه الدورة
- try/catch/finally كتعبير
- إنشاء أصناف Exception مخصصة
- runCatching وResult
- إعادة رمي الاستثناءات وتسلسلها