📘 شرح الدرس الوحدة 3: القرار والتكرار وتشخيص الأخطاء · الدرس 8 من 17
الدرس 8
📋 في الخطة: الوحدتان 6 و 12: الأخطاء وأدوات التشخيص والتتبع · ⏱ 1 نظري + 3 عملي

أنواع الأخطاء وأدوات التشخيص

نتعرّف على أخطاء الصياغة والتنفيذ والمنطق، ونكشفها بعبارات الطباعة ونقاط التوقف وجدول التتبّع.

trymyNumbers[10] ! catch (Exception e)
بعد هذا الدرس ستستطيع أن:
  • تميّز بين أخطاء الصياغة وأخطاء زمن التنفيذ والأخطاء المنطقية.
  • تستخدم عبارات الطباعة لتتبّع قيم المتغيرات.
  • تستخدم نقاط التوقف والتنفيذ خطوة بخطوة في NetBeans.
  • تتتبّع البرنامج يدويًّا بجدول التتبّع لتحديد مصدر المشكلة.

١الأخطاء جزء طبيعي من البرمجة

لا يوجد مبرمج لا يخطئ. الفرق بين المبتدئ والمحترف أن المحترف يعرف نوع الخطأ بسرعة ويعرف أين يبحث عنه. يُسمّى الخطأ في البرنامج Bug، وتُسمّى عملية البحث عنه وإصلاحه Debugging أي التصحيح.

تنقسم أخطاء البرامج إلى ثلاثة أنواع رئيسية:

النوعمتى يُكتشف؟من يكتشفه؟العلامة
أخطاء الصياغة Syntax Errorsقبل التشغيل، أثناء الترجمةالمترجم compilerخط أحمر في NetBeans، ولا يعمل البرنامج
أخطاء زمن التنفيذ Runtime Errorsأثناء التشغيلآلة جافا JVMيتوقف البرنامج فجأة برسالة Exception
الأخطاء المنطقية Logic Errorsبعد التشغيل، عند مراجعة النتائجالمبرمج نفسهيعمل البرنامج لكن النتيجة خاطئة

٢أخطاء الصياغة Syntax Errors

تحدث عندما نخالف قواعد كتابة اللغة، كما يخطئ الطالب في الإملاء أو النحو. المترجم يرفض ترجمة البرنامج، فلا يعمل أبدًا حتى نصلح الخطأ. وتظهر في NetBeans بخط أحمر متعرّج وعلامة ❗ بجانب رقم السطر.

١. نسيان الفاصلة المنقوطة

Main.java
public class Main {    public static void main(String[] args) {        int x = 10        System.out.println(x);    }}
Output – JavaApplication (run)×
Main.java:3: error: ';' expected
int x = 10
^
1 error
BUILD FAILED (total time: 0 seconds)

٢. متغير غير معرّف أو مكتوب بشكل خاطئ

Main.java
public class Main {    public static void main(String[] args) {        int total = 5;        System.out.println(totl);    }}
Output – JavaApplication (run)×
Main.java:4: error: cannot find symbol
System.out.println(totl);
^
symbol: variable totl
location: class Main
1 error
BUILD FAILED (total time: 0 seconds)

٣. عدم توافق الأنواع

Main.java
public class Main {    public static void main(String[] args) {        int n = "ten";    }}
Output – JavaApplication (run)×
Main.java:3: error: incompatible types: String cannot be converted to int
int n = "ten";
^
1 error
BUILD FAILED (total time: 0 seconds)

٣أخطاء زمن التنفيذ Runtime Errors

البرنامج صحيح الصياغة ويبدأ العمل، لكنه يواجه موقفًا لا يستطيع التعامل معه فيتوقف فجأة. تسمّى هذه الأخطاء في جافا استثناءات Exceptions. لاحظ أن الأسطر قبل الخطأ تُنفَّذ، وما بعده لا يُنفَّذ.

١. القسمة على صفر

Main.java
public class Main {    public static void main(String[] args) {        int a = 10, b = 0;        System.out.println("قبل القسمة");        System.out.println(a / b);        System.out.println("بعد القسمة");    }}
Output – JavaApplication (run)×
run:
قبل القسمة
Exception in thread "main" java.lang.ArithmeticException: / by zero
at Main.main(Main.java:5)
BUILD FAILED (total time: 0 seconds)

٢. إدخال من نوع غير متوقع

البرنامج ينتظر رقمًا صحيحًا من nextInt()، لكن المستخدم كتب كلمة:

Main.java
import java.util.Scanner;public class Main {    public static void main(String[] args) {        Scanner in = new Scanner(System.in);        System.out.println("ادخل عمرك:");        int age = in.nextInt();        System.out.println("عمرك " + age);    }}
Output – JavaApplication (run)×
run:
ادخل عمرك:
عشرون
Exception in thread "main" java.util.InputMismatchException
at java.base/java.util.Scanner.nextInt(Scanner.java:2221)
at Main.main(Main.java:6)
BUILD FAILED (total time: 0 seconds)

سنتعلم في الدرس 16 قراءة رسالة الاستثناء سطرًا سطرًا لمعرفة نوع الخطأ ورقم السطر الذي حدث فيه.

٤الأخطاء المنطقية Logic Errors

أخطرها وأصعبها: البرنامج يُترجَم ويعمل دون أي رسالة خطأ، لكن النتيجة خاطئة. المترجم لا يعرف ماذا تقصد، بل ينفذ ما كتبته حرفيًّا.

١. نسيان الأقواس في حساب المتوسط

✗ خطأ
snippet
int a = 80, b = 90;double avg = a + b / 2;System.out.println(avg);  // 125.0 ✗
✓ صواب
snippet
int a = 80, b = 90;double avg = (a + b) / 2.0;System.out.println(avg);  // 85.0 ✓

القسمة تُنفَّذ قبل الجمع، فيصبح الحساب 80 + 45 = 125. الأقواس تفرض الجمع أولًا.

٢. شرط حدّه خاطئ

✗ خطأ
snippet
int grade = 60;if (grade > 60)    System.out.println("ناجح");else    System.out.println("راسب");  // راسب ✗
✓ صواب
snippet
int grade = 60;if (grade >= 60)    System.out.println("ناجح");  // ناجح ✓else    System.out.println("راسب");

الطالب الحاصل على 60 ناجح، لكن الشرط > يستبعده. الخطأ يظهر فقط عند القيمة الحدّية 60.

٣. حلقة تنقص مرة أو تزيد مرة (Off-by-one)

✗ خطأ
snippet
int sum = 0;for (int i = 1; i < 5; i++)    sum = sum + i;System.out.println(sum);  // 10 ✗
✓ صواب
snippet
int sum = 0;for (int i = 1; i <= 5; i++)    sum = sum + i;System.out.println(sum);  // 15 ✓

المطلوب جمع الأعداد من 1 إلى 5، لكن الشرط i < 5 يتوقف عند 4.

٥أداة التشخيص ١: عبارات الطباعة

أبسط أداة وأسرعها: نضيف أوامر طباعة مؤقتة تعرض قيم المتغيرات في نقاط مهمة، فنرى ماذا يحدث داخل البرنامج فعلًا. نبدأ الرسالة بكلمة مميزة مثل DEBUG لنعرف أنها للتشخيص فقط.

snippet
int sum = 0;for (int i = 1; i < 5; i++) {    sum = sum + i;    System.out.println("DEBUG: i=" + i + " sum=" + sum);}System.out.println("المجموع = " + sum);
Output – JavaApplication (run)×
run:
DEBUG: i=1 sum=1
DEBUG: i=2 sum=3
DEBUG: i=3 sum=6
DEBUG: i=4 sum=10
المجموع = 10
BUILD SUCCESSFUL (total time: 0 seconds)

من الطباعة نرى فورًا أن الحلقة توقفت عند i=4 ولم تصل إلى 5. إذن الخطأ في شرط الحلقة. بعد الإصلاح نحذف أسطر التشخيص.

٦أداة التشخيص ٢: نقاط التوقف Breakpoints

المنقّح (Debugger) في NetBeans يسمح لك بإيقاف البرنامج عند سطر محدد، ثم تنفيذه سطرًا سطرًا ومراقبة قيم المتغيرات دون إضافة أي أوامر طباعة.

الخطوةالطريقة في NetBeans
١. ضع نقطة توقفانقر على رقم السطر في الهامش الأيسر، فيظهر مربع أحمر 🔴 ويتلون السطر
٢. ابدأ التنقيحDebug ← Debug Project، أو Ctrl + F5
٣. نفّذ سطرًا واحدًاStep Over أو F8
٤. ادخل إلى داخل دالةStep Into أو F7
٥. تابع حتى نقطة التوقف التاليةContinue أو F5
٦. راقب المتغيراتنافذة Variables أسفل الشاشة تعرض كل متغير وقيمته الحالية
٧. أنهِ التنقيحFinish Debugger Session أو Shift + F5

جرّب محاكاة المنقّح

اضغط «التالي» كأنك تضغط F8 في NetBeans، وراقب نافذة المتغيرات:

🔎 تتبّع: محاكاة المنقّح: Step Over
snippet
int price = 200;int qty = 3;int total = price * qty;if (total > 500)    total = total - 50;System.out.println(total);
Variables · المتغيّرات في الذاكرة
Output×

٧تتبّع التنفيذ خطوة بخطوة

البرنامج التالي يجب أن يعدّ الأعداد الزوجية من 1 إلى 6، ويطبع 3، وهو فعلًا يطبع 3! هل هو صحيح؟ تتبّعه خطوة بخطوة:

🔎 تتبّع: عدّ الأعداد الزوجية
snippet
int count = 0;for (int i = 1; i <= 6; i++) {    if (i % 2 == 1)        count++;}System.out.println("عدد الزوجيات = " + count);
Variables · المتغيّرات في الذاكرة
Output×

الدرس المهم: نتيجة صحيحة مع مدخلات واحدة لا تعني أن البرنامج صحيح. جرّب الحدّ 7 بدل 6: الصحيح 3 زوجيات، والبرنامج يطبع 4.

جدول التتبّع اليدوي Dry Run

بدون حاسب نستطيع تتبّع البرنامج بجدول: عمود لكل متغير وعمود للشرط وعمود للناتج. هذه أقوى أداة تصحيح لأنها تجبرك على التفكير مثل الحاسب.

ii % 2الشرط i % 2 == 1count
11true1
20false1
31true2
40false2
51true3
60false3

الجدول يكشف فورًا أن count يزيد مع 1 و 3 و 5، أي الفرديات. الإصلاح: i % 2 == 0.

توقّع وتحقّق

برنامج لا يعمل أصلًا ويظهر فيه خط أحمر في NetBeans. ما نوع الخطأ؟

المترجم يرفض البرنامج، فهو خطأ صياغة.

برنامج يعمل ويطبع 125 بدل 85. ما نوع الخطأ؟

يعمل دون رسالة لكن النتيجة خاطئة: خطأ منطقي.

ما الذي يسبب ArithmeticException؟

/ by zero يعني قسمة عدد صحيح على صفر.

أي مفتاح في NetBeans ينفّذ السطر الحالي فقط أثناء التنقيح؟

F8 هو Step Over.

الخلاصة

تحدٍّ برمجي: أصلح البرنامج

متوسط

البرنامج التالي يحسب متوسط ثلاث درجات ويحكم بالنجاح إذا كان المتوسط 60 فأكثر، لكن فيه خطآن صياغيان وخطآن منطقيان.

المطلوب:
  • أصلح أخطاء الصياغة حتى يعمل البرنامج.
  • استخدم عبارات الطباعة أو نقاط التوقف لاكتشاف الخطأين المنطقيين.
  • مع الدرجات 60 و 60 و 60 يجب أن يطبع: المتوسط = 60.0 ثم ناجح.

ابدأ من هذا الكود، واضغط ▶ شغّل هنا لتكتب حلّك وتجرّبه مباشرة:

Main.java
public class Main {    public static void main(String[] args) {        int a = 60, b = 60, c = 60        double avg = a + b + c / 3.0;        System.out.println("المتوسط = " + avg);        if (avg > 60)            System.out.println("ناجح");        else            system.out.println("راسب");    }}
Output – المطلوب×
المتوسط = 60.0
ناجح
💡 تلميح 1
خطأ الصياغة الأول في السطر 3، والثاني في حالة أحد الأحرف.
💡 تلميح 2
راجع أولوية العمليات في حساب المتوسط، وراجع الحدّ في الشرط.

حاول بنفسك أولًا؛ للمسألة أكثر من حلّ صحيح.

Main.java
public class Main {    public static void main(String[] args) {        int a = 60, b = 60, c = 60;        double avg = (a + b + c) / 3.0;        System.out.println("المتوسط = " + avg);        if (avg >= 60)            System.out.println("ناجح");        else            System.out.println("راسب");    }}
انتقل إلى تقييم الدرسأسئلة الاختيار، وصح وخطأ، وأكمل الفراغات، والأسئلة العملية.ابدأ التقييم ←