مقدمة: لماذا هذا الموضوع يفجر Stack Overflow؟
\n\nإذا كنت قد كتبت يومًا بلغة Kotlin وواجهت الحاجة لاعتراض عدة استثناءات مختلفة، فأنت تعلم أن هذا قد يكون مؤلمًا. خاصة إذا كنت قادمًا من Java، حيث multi-catch (catch (IOException | SQLException e)) هو المعيار منذ Java 7. في Kotlin الأمر مختلف، والعديد من المطورين يضيعون.
\n\nالسؤال "How to catch many exceptions at the same time in Kotlin?" على Stack Overflow حصل على آلاف المشاهدات. وهذا ليس من قبيل الصدفة: معالجة الأخطاء هي شيء يواجهه الجميع تمامًا. اليوم سنحل هذه المشكلة مرة واحدة وإلى الأبد.
\n\nفي هذه المقالة ستتعلم:
\n- \n
- لماذا لا يعمل multi-catch في Kotlin كما في Java \n
- كيفية اعتراض استثناءات متعددة بشكل أنيق ومضغوط \n
- متى تستخدم
whenفيcatch، ومتى تستخدمifالتقليدي \n - أمثلة حقيقية من كود إنتاجي \n
هيا بنا!
\n\nالمشكلة: أين multi-catch الخاص بي؟
\n\nفي Java تكتب ببساطة:
\ntry {\n riskyOperation()\n} catch (IOException | SQLException e) {\n // نعالج بنفس الطريقة\n}\n\n\nجميل، موجز، واضح. لكن في Kotlin هذا التركيب غير موجود. إذا حاولت كتابة catch (IOException | SQLException e)، سيخبرك المترجم بـ "لا".
لماذا؟ لأن Kotlin اختار الوضوح والنقاء. قرر مطورو اللغة أن multi-catch مع الخط العمودي ليس أسلوب Kotlin تمامًا. لكن هذا لا يعني أنه لا يمكنك التقاط استثناءات متعددة. فقط يتم ذلك بطريقة مختلفة.
\n\nدعنا نلقي نظرة على ثلاث طرق رئيسية.
\n\nالطريقة 1: كتل catch متعددة (الأكثر وضوحًا)
\n\nأبسط طريق هو ببساطة إضافة عدة كتل catch متتالية. Kotlin يدعم هذا بشكل ممتاز.
try {\n val data = loadData()\n processData(data)\n} catch (e: IOException) {\n println("خطأ في الإدخال/الإخراج: ${e.message}")\n} catch (e: SQLException) {\n println("خطأ في قاعدة البيانات: ${e.message}")\n} catch (e: Exception) {\n println("خطأ غير معروف: ${e.message}")\n}\n\n\nالإيجابيات:
\n- \n
- واضح للغاية - كل نوع استثناء يُعالج بشكل منفصل \n
- يمكن إعطاء منطق مختلف لأخطاء مختلفة \n
- يُقرأ بشكل ممتاز من قبل المبتدئين \n
السلبيات:
\n- \n
- الكثير من تكرار الكود إذا كان منطق المعالجة متطابقًا \n
- عند 5+ استثناءات يصبح الكتلة ضخمة \n
الطريقة 2: catch مع when (أنيق ومرن)
\n\nهنا يتألق Kotlin بكل جماله. بدلاً من multi-catch يمكنك استخدام when داخل كتلة catch واحدة.
try {\n val result = fetchFromNetwork()\n saveToDatabase(result)\n} catch (e: Exception) {\n when (e) {\n is IOException -> handleNetworkError(e)\n is SQLException -> handleDatabaseError(e)\n is SecurityException -> logAndNotify(e)\n else -> throw e // نعيد الرمي إذا لم نعرف كيف نعالج\n }\n}\n\n\nهذا النهج هو اكتشاف حقيقي. يسمح لك بـ:
\n- \n
- معالجة استثناءات مختلفة في مكان واحد \n
- استخدام جميع إمكانيات
when، بما في ذلك فحص الشروط \n - إضافة أنواع استثناءات جديدة بسهولة \n
إليك مثال أكثر تقدمًا مع شروط:
\n\ntry {\n connectToService()\n} catch (e: Exception) {\n when {\n e is IOException && e.message?.contains("timeout") == true -> \n println("انتهت مهلة الاتصال، نحاول مرة أخرى")\n e is IOException -> \n println("خطأ في الشبكة: ${e.message}")\n e is SQLException && e.errorCode == 1045 -> \n println("خطأ في المصادقة على قاعدة البيانات")\n else ->