مشروع: معالجة المدخلات بشكل موثوق
مشروع: معالجة المدخلات بشكل موثوق
قضيت الدروس التسعة الماضية تتعلّم كل جانب من جوانب معالجة الاستثناءات في Java — من أساسيات try/catch وصولًا إلى فئات الاستثناء المخصّصة وtry-with-resources. هذا الدرس الأخير يجمع كل شيء في مشروع صغير واقعي: تطبيق وحدة طرفية يظل يطلب من المستخدم إدخال بيانات حتى يقدّم شيئًا صالحًا، ويُشير إلى الإدخال السيئ برمي استثناء مخصّص.
التطبيقات الحقيقية نادرًا ما تتعطّل بسبب إدخال خاطئ — بل تخبر المستخدم بما حدث وتطلب منه المحاولة مرة أخرى. هذا هو النمط الذي ستبنيه هنا.
ما الذي نبنيه
برنامج صغير على سطر الأوامر يقرأ عددًا صحيحًا بين 1 و100 من المستخدم. إذا كتب المستخدم شيئًا ليس رقمًا، أو رقمًا خارج هذا النطاق، فإن البرنامج:
- يرمي
InvalidInputException(استثناء مخصّص مُدقَّق تعرّفه بنفسك). - يلتقطه، يطبع رسالة ودّية، ويعود للحلقة للطلب مرة أخرى.
- يخرج من الحلقة فقط عند استلام إدخال صالح.
الخطوة الأولى — تعريف الاستثناء المخصّص
من الدرس السابع تعلمت أن الاستثناء المخصّص هو ببساطة فئة تمتد من Exception (مُدقَّق) أو RuntimeException (غير مُدقَّق). نستخدم هنا استثناءً مُدقَّقًا لأن المُستدعِي يجب أن يعالج الإدخال السيئ — فهو جزء متوقّع من تدفق التنفيذ.
الخطوة الثانية — دالة التحقق التي ترمي الاستثناء
افصل منطق التحقق في دالة خاصة به. تقبل سلسلة نصية خام String، تحاول تحليلها، تتحقق من النطاق، وإما تُعيد عددًا صحيحًا int نظيفًا أو ترمي InvalidInputException. إعلان throws يجعل العقد صريحًا.
NumberFormatException ثم يُرمى فورًا كـ InvalidInputException. الاستثناء منخفض المستوى يُمتَص، ويُرفع بدلًا منه استثناء على مستوى النطاق. يرى المستخدم "ليس عددًا صحيحًا"، لا تتبّع مكدس خام.
الخطوة الثالثة — حلقة الإدخال
الحلقة الرئيسية تعمل إلى ما لا نهاية (while (true)) وتنكسر فقط عند وصول إدخال صالح. في كل تكرار تطلب إدخالًا، تقرأ سطرًا، تستدعي المتحقِّق، وإما تخزّن النتيجة وتخرج، أو تلتقط الاستثناء وتطبع الخطأ قبل العودة للتكرار.
مثال على تشغيل البرنامج
هذا ما يبدو عليه البرنامج حين يرتكب المستخدم خطأين قبل النجاح:
لماذا يعمل هذا التصميم
- مسؤولية واحدة:
parseAndValidateتتولى كل التحقق؛mainتتولى الحلقة والتفاعل مع المستخدم. كل قطعة تؤدي مهمة واحدة. - الاستثناء المُدقَّق يُجبر على المعالجة: لأن
InvalidInputExceptionتمتد منException، يُجبر المُجمِّع كل مُستدعٍ إما على التقاطه أو إعلانthrows. لا يمكنك إهمال الإدخال السيئ عن طريق الخطأ. - لا فشل صامت: الحلقة لا تخرج حتى يُنتَج إدخال صالح. لا توجد قيمة
return -1تحرس لتنسى التحقق منها. - رسائل خطأ مفيدة: الاستثناء يحمل رسالة مقروءة للإنسان والإدخال الخام، لذا يمكن لكتلة الالتقاط أن تعطي المستخدم ملاحظات محددة.
تطوير المشروع (أفكار)
الآن بعد أن استقر النمط، جرّب هذه الإضافات الصغيرة بنفسك:
- أضف حدًا أقصى لعدد المحاولات (مثلًا ثلاث محاولات)، ثم ارمِ استثناءً مختلفًا إذا تجاوز الحد.
- تحقق من أن الإدخال ليس فارغًا قبل محاولة تحليله، وأعطِ رسالة محددة للإدخال الفارغ.
- لفّ
Scannerفي كتلةtry-with-resources(الدرس الثامن) لضمان إغلاقه دائمًا — حتى لو أفلت استثناء غير متوقع من الحلقة. - انقل المُتحقِّق إلى فئة مساعدة واكتب اختبار وحدة يفحص كل فرع خطأ.
جمع كل شيء معًا
لمس هذا المشروع تقريبًا كل مفهوم من الدرس: تعريف فئة استثناء مخصّصة (الدرس السابع)، استخدام throws في توقيع الدالة (الدرس الخامس)، الالتقاط وإعادة الرمي من استثناء منخفض المستوى (الدرس السادس)، وبناء حلقة إعادة المحاولة التي تعطي المستخدم ملاحظات مفيدة. معالجة الاستثناءات ليست مجرد إيقاف الأعطال — بل هي بناء برامج تتواصل بوضوح وتتعافى بسلاسة. تلك هي المهارة التي تمتلكها الآن.