البوابة تسأل — boolean والمقارنة
صباح يوم جامعي: تصل إلى بوابة الحرم فتجد حارسًا ذكيًا لا يفهم إلا لغة واحدة — «نعم» أو «لا».
الحارس الذكي عند البوابة يسألك أسئلة سريعة: «هل عمرك أكبر من 17؟»، «هل معك البطاقة؟»، «هل رقم قاعتك يساوي 204؟». وهو لا يقبل إجابة «ربما» ولا «تقريبًا» — الإجابة إما true (نعم) وإما false (لا)، ولا ثالث لهما. هذا بالضبط ما يحتاجه أي برنامج ليتخذ قرارًا.
في جافا يوجد نوع بيانات مخصص لهذه الإجابات اسمه boolean (قيمة منطقية). متغير من هذا النوع يحمل قيمة واحدة من اثنتين فقط: true أو false — تُكتبان بحروف صغيرة ودون تنصيص.
أسئلة الحارس تُكتب في جافا بـ عوامل المقارنة (relational operators). كل عامل يأخذ قيمتين ويعيد جوابًا واحدًا: true أو false:
| العامل | سؤال الحارس | مثال | النتيجة |
|---|---|---|---|
| == | هل الاثنان متساويان؟ | 8 == 8 | true |
| != | هل هما مختلفان؟ | 5 != 5 | false |
| > | هل الأول أكبر؟ | 7 > 3 | true |
| < | هل الأول أصغر؟ | 3 < 3 | false |
| >= | هل الأول أكبر أو يساوي؟ | 4 >= 5 | false |
| <= | هل الأول أصغر أو يساوي؟ | 2 <= 9 | true |
جرّب ميزان الحارس بنفسك — المقارنة التالية تسأل هل الرقم الأول أكبر من الثاني:
والآن مثال كامل يطبع نتائج أربع مقارنات. لاحظ أن المقارنة نفسها تُكتب بين قوسين لتُحسب أولًا، ثم تلتصق نتيجتها (true أو false) بالنص الذي قبلها:
public class ComparisonDemo { public static void main(String[] args) { int num1 = 10; int num2 = 6; System.out.println("num1 > num2: " + (num1 > num2)); System.out.println("num1 == num2: " + (num1 == num2)); System.out.println("num1 != num2: " + (num1 != num2)); System.out.println("num1 <= num2: " + (num1 <= num2)); }}
اقرأ المثال سطرًا سطرًا
- num1 > num2 تسأل: هل 10 أكبر من 6؟ الجواب true.
- num1 == num2 تسأل: هل 10 تساوي 6؟ الجواب false.
- num1 != num2 تسأل: هل 10 تختلف عن 6؟ الجواب true.
- num1 <= num2 تسأل: هل 10 أصغر من 6 أو تساويها؟ الجواب false.
- الأقواس حول كل مقارنة مهمة: بدونها يحاول جافا إلصاق النص بالرقم قبل أن يقارن فيحدث خطأ.
الجواب الذي يعطيه الحارس ليس للطباعة فقط؛ يمكن أن نحفظه في متغير boolean ونستعمله لاحقًا، تمامًا كما نحفظ رقمًا في int:
public class StoreAnswer { public static void main(String[] args) { int age = 17; boolean canEnter = age >= 18; System.out.println("canEnter = " + canEnter); boolean isSeventeen = age == 17; System.out.println(isSeventeen); }}
المتغير canEnter يحمل الجواب false لأن 17 ليست أكبر من أو تساوي 18 — لا دخول اليوم يا صديقي! أما isSeventeen فجوابه true.
فخ المبتدئين: = مقابل ==
علامة = الواحدة ليست سؤالًا. هي أمر: «ضع هذه القيمة في الصندوق». أما السؤال «هل يساوي؟» فيحتاج علامتين ==. الخلط بينهما من أشهر أخطاء بدايات جافا:
اكشف الإجابة
لا — نكون قد وضعنا 18 في age دون أن نسأل. السؤال الحقيقي يحتاج age == 18.الحارس يعرف الآن أن يسأل سؤالًا واحدًا ويجيب بـ true أو false. في الدرس التالي سيتعلّم أن يجمع سؤالين معًا وأن يقلب جوابه.
int age = 17; boolean canEnter = age >= 18; System.out.println(canEnter);
بوابة القبول المزدوجة — دمج الشروط
بعد أن تعلّم الحارس أن يسأل سؤالًا واحدًا، قررت إدارة الحرم أن تجعله أذكى: بوابة بحارسين، ولكل حارس رأي.
اليوم لا يكفي أن يسألك الحارس «هل عمرك 18؟». الإدارة تريد أسئلة مركّبة: «هل عمرك 18 و معك البطاقة؟»، أو «هل عمرك 18 أو أكثر أو معك البطاقة؟». لدمج أكثر من سؤال في سؤال واحد تعطينا جافا العوامل المنطقية (logical operators): && («و»، AND) و || («أو»، OR) و ! («ليس»، NOT).
جداول الصدق: AND و OR و NOT
تخيّل بوابة بحارسين، a و b، وكل حارس يجيب بـ true («نعم») أو false («لا»). السؤال: متى تُفتح البوابة؟ الجواب يعتمد على العامل الذي يجمع رأيي الحارسين. جدول الصدق (truth table) يعرض كل الاحتمالات الممكنة ونتيجة كل منها:
«و» (AND) — نربط الحارسين بسؤالَي البوابة الأول:
- boolean a = age >= 18; ← الحارس الأول: هل عمرك 18 أو أكثر؟
- boolean b = hasCard; ← الحارس الثاني: هل معك البطاقة؟
| a العمر 18+؟ |
b معك البطاقة؟ |
a && b يدخل؟ |
المعنى |
|---|---|---|---|
| true | true | true | عمره 18 ومعه البطاقة ← يدخل |
| true | false | false | كبير لكن نسي البطاقة ← يُرفض |
| false | true | false | معه بطاقة لكنه أصغر من 18 ← يُرفض |
| false | false | false | لا هذا ولا ذاك ← يُرفض |
و: يجب أن يقول الحارسان نعم.
«أو» (OR) — في يوم المعرض المفتوح خفّفت الإدارة الشرط: يكفي أن تكون 18 أو أكثر أو أن تحمل البطاقة. نفس الحارسين a و b من جدول «و»، فلا نعيد تعريفهما، ونقارن الجدولين صفًّا بصف:
| a العمر 18+؟ |
b معك البطاقة؟ |
a || b يدخل؟ |
المعنى |
|---|---|---|---|
| true | true | true | عمره 18 ومعه البطاقة ← يدخل |
| true | false | true | كبير بلا بطاقة ← يدخل (يكفي العمر) |
| false | true | true | أصغر من 18 لكن معه البطاقة ← يدخل (تكفي البطاقة) |
| false | false | false | لا هذا ولا ذاك ← يُرفض |
أو: يكفي حارس واحد.
«ليس» (NOT) — عند مدخل الحرم مكتب صغير: موظفه يخدم فقط من ليس معه بطاقة، ليصدر له واحدة. نكتبها في جافا هكذا:
if (!hasCard) ← «تفضّل، نصدر لك بطاقة»
| hasCard معك البطاقة؟ |
!hasCard يحتاج المكتب؟ |
المعنى |
|---|---|---|
| true | false | معه بطاقة ← لا يحتاج المكتب، يكمل طريقه إلى البوابة |
| false | true | بلا بطاقة ← يُوجَّه إلى مكتب إصدار البطاقات |
ليس: تعكس القيمة — الصح (true) يصير خطأ (false)، والخطأ يصير صحًّا.
اكشف الإجابة
مع && لا تُفتح (الناتج false) لأن «لا» واحدة تكفي لإفسادها. ومع || تُفتح (الناتج true) لأن «نعم» واحدة تكفي.والآن بوابة القبول المزدوجة في برنامج حقيقي. الطالب عمره 20 ومعه البطاقة، والمطلوب أن نختبر الحارسين بالعوامل الثلاثة. لاحظ: هذا بالضبط الصف الأول من جدول «و» (a هو age >= 18 وb هو البطاقة، وهي هنا hasCard):
public class DoubleGate { public static void main(String[] args) { int age = 20; boolean hasCard = true; boolean both = age >= 18 && hasCard; boolean either = age >= 18 || hasCard; System.out.println("both = " + both); System.out.println("either = " + either); System.out.println("not hasCard = " + (!hasCard)); }}
اقرأ المثال سطرًا سطرًا
- age >= 18 && hasCard يجمع حارسين: الأول عمر الطالب 20 فيقول «نعم»، والثاني البطاقة موجودة فيقول «نعم». الاثنان وافقا فالناتج true.
- age >= 18 || hasCard يكفيه حارس واحد وقد وافق الاثنان، فالناتج true أيضًا.
- (!hasCard) تقلب true إلى false. الأقواس هنا اختيارية، نكتبها لتوضيح القصد.
نعود إلى مثال 5·1: المدى والخارج عنه
في الدرس السابق قارنّا num1 بـ num2 فقط. الآن نستطيع أن نسأل أسئلة مركّبة عن num1 وحدها: هل هو داخل المدى من 1 إلى 20 (حارسان بـ &&)؟ وهل هو خارج المدى من 0 إلى 20 (حارسان بـ ||)؟
public class ComparisonDemo2 { public static void main(String[] args) { int num1 = 10; boolean inRange = (num1 > 0) && (num1 <= 20); boolean outside = (num1 < 0) || (num1 > 20); System.out.println("num1 is from 1 to 20: " + inRange); System.out.println("num1 is outside 0 to 20: " + outside); }}
- (num1 > 0) && (num1 <= 20): 10 أكبر من 0 («نعم») و10 لا تزيد عن 20 («نعم»). وافق الحارسان فالناتج true.
- (num1 < 0) || (num1 > 20): 10 ليست أصغر من 0 («لا») ولا أكبر من 20 («لا»). لم يوافق أي حارس فالناتج false.
«ليس»: قلب الجواب
أما ! فتعمل على حارس واحد وتعكس جوابه. هذا مثال المعمل: لا نسمح بالدخول إلا لمن معه تصريح:
public class PermissionDemo { public static void main(String[] args) { boolean hasPermission = false; if (!hasPermission) { System.out.println("Access denied"); } }}
- hasPermission قيمته false، أي لا يوجد تصريح.
- !hasPermission تعكس القيمة من false إلى true — يعني «ليس معه تصريح» صحيح.
- الأمر if (شرط، condition) ينفّذ ما بين { } عندما يكون الجواب true، فيُطبع «Access denied». سنتقنه في الدرس 5·3.
فحص المدى: هل الرقم بين حدّين؟
أشهر استعمال لـ && هو أن نسأل: هل الرقم داخل مدى معيّن؟ إدارة الحرم تقبل رقم القاعة من 1 إلى 100 فقط. نحتاج حارسين: الأول «هل الرقم لا يقل عن 1؟» والثاني «هل لا يزيد عن 100؟»، ولا بد من موافقتهما معًا. وهذه هي المسألة الرابعة في المعمل. وفي التحدي الاختياري نضيف حارسًا ثالثًا: المدى من 10 إلى 20 و الرقم زوجي.
public class RangeCheck { public static void main(String[] args) { int x = 57; System.out.println("x is from 1 to 100: " + (x >= 1 && x <= 100)); int n = 14; System.out.println("n is even and from 10 to 20: " + (n >= 10 && n <= 20 && n % 2 == 0)); }}
تنبّه إلى فخ شائع: الكتابة الرياضية 1 <= x <= 100 لا تصلح في جافا. كل حارس يسأل سؤالًا كاملًا، فنكتب x >= 1 && x <= 100 بحارسين منفصلين. والرقم الزوجي يُعرف بأن باقي قسمته على 2 يساوي صفرًا: n % 2 == 0.
من يُحسب أولًا؟ الأولوية
عند وجود أكثر من عامل منطقي في سطر واحد، تُحسب بهذا الترتيب: ! أولًا، ثم &&، ثم || أخيرًا. أي أن «و» تلتصق بجارتيها أقوى من «أو»، تمامًا كما يسبق الضرب الجمع في الرياضيات. مثلًا true || false && false تُحسب كأنها true || (false && false) أي true || false فتعطي true. والمقارنات (>= و <) تُحسب قبل العوامل المنطقية كلها، لذلك age >= 18 && hasCard لا تحتاج أقواسًا.
الحارس يتوقف عند أول رفض: القصر (short-circuit)
الحارسان في بوابة && لا يُسألان دائمًا. جافا تسأل الحارس الأول، فإن قال «لا» فالنتيجة false مهما كان رأي الثاني، ولذلك لا تكلّف نفسها سؤاله. هذا يسمى القصر (short-circuit). وفائدته عملية جدًا: حماية الحارس الثاني من سؤال خطير. المثال هنا متوسط الدرجات: totalScore / assignmentsDone تنهار بقسمة على صفر إذا لم يسلّم الطالب أي واجب. فنضع حارس الأمان أولًا:
توقّع: لو رفض الحارس الأول، هل ستحاول جافا مع ذلك تنفيذ totalScore / 0 ؟
اكشف الإجابة
يُسأل الحارس الذي يقسم أولًا فتقع القسمة على صفر ويتوقف البرنامج بخطأ. الترتيب هو الحماية: حارس الأمان يأتي أولًا.وهذا هو مثال التحدي في المعمل، المتوسط الآمن، بحارس الأمان في مكانه الصحيح:
public class SafeAverage { public static void main(String[] args) { int assignmentsDone = 0; int totalScore = 150; boolean passing = assignmentsDone > 0 && totalScore / assignmentsDone > 50; System.out.println("passing = " + passing); }}
الناتج passing = false وبلا أي خطأ. جرّب أن تغيّر assignmentsDone إلى 3: ستُسأل الحارسان معًا، والمتوسط 50 ليس أكبر من 50 فيبقى الناتج false أيضًا. وللعامل || قصر مماثل: إن قال الحارس الأول «نعم» فلا حاجة لسؤال الثاني.
int x = 150; System.out.println(x >= 1 && x <= 100);
مكتب الدرجات — القرارات
دخلت الحرم بسلام، والآن تمرّ على مكتب الدرجات حيث يقرر الموظف مصيرك: ناجح، راسب، أو «تفضّل بزيارتنا الأسبوع القادم».
حتى الآن كان البرنامج ينفّذ أسطره كلها من الأول إلى الآخر. لكن موظف المكتب لا يعمل هكذا: ينظر إلى درجتك ثم يختار فرعًا (branch) من الطرق الممكنة. الأمر الذي يمنح البرنامج هذه القدرة اسمه if، وشكله:
- if (condition) { ... } ينفّذ ما بين القوسين المعقوفين فقط عندما يكون الشرط true، وإلا يتخطاه.
- if (condition) { ... } else { ... } ينفّذ الفرع الأول إن صح الشرط، والفرع الثاني (else) إن لم يصح. فرع واحد بالضبط يُنفَّذ دائمًا.
public class RetryOrPass { public static void main(String[] args) { int mark = 45; if (mark >= 50) { System.out.println("Passed"); } else { System.out.println("Try again"); } }}
الدرجة 45 لا تحقق الشرط، فيُنفَّذ فرع else ويُطبع «Try again». غيّر الدرجة إلى 70 وشغّل لترى الفرع الآخر.
الأقواس {} ليست زينة
إذا حذفنا الأقواس المعقوفة، فإن if تتحكم في أول سطر فقط بعدها. أما السطر الثاني فيُنفَّذ دائمًا، سواء صح الشرط أم لا. شاهد ما يحدث لطالب راسب:
public class BracesTrap { public static void main(String[] args) { int mark = 40; if (mark >= 50) System.out.println("Passed"); System.out.println("Congratulations!"); }}
الدرجة 40 راسبة، ومع ذلك يُطبع «Congratulations!». فالمسافة البادئة لا تعني شيئًا لجافا؛ السطر الثاني ليس داخل الشرط. هذا خطأ يضحك الجميع إلا صاحبه. فاكتب الأقواس دائمًا حتى مع سطر واحد.
سلّم التقديرات: else if
ماذا لو كانت الطرق أكثر من اثنين؟ التقدير له خمسة أحوال: A وB وC وD وF. نسلسل الشروط بـ else if من الأعلى إلى الأسفل، وتُفحص بالترتيب، وأول شرط يصح يُنفَّذ فرعه وحده ثم يخرج البرنامج من السلّم كله. هذه هي الممارسة الأولى في المعمل، GradeMessage:
public class GradeMessage { public static void main(String[] args) { int mark = 82; if (mark >= 90) { System.out.println("Excellent"); System.out.println("Grade: A"); } else if (mark >= 80) { System.out.println("Very Good"); System.out.println("Grade: B"); } else if (mark >= 70) { System.out.println("Good"); System.out.println("Grade: C"); } else if (mark >= 60) { System.out.println("Pass"); System.out.println("Grade: D"); } else { System.out.println("Fail"); System.out.println("Grade: F"); } }}
تابع الدرجة 82 على السلّم خطوة بخطوة، وتوقّع قبل كل ضغطة أين ستقف:
توقّع: الدرجة 82 أكبر من 80 وأكبر من 70 وأكبر من 60 كذلك. فكم فرعًا سيُنفَّذ منها؟
اكشف الإجابة
يطبع «Grade: D»! لأن 95 تحقق الشرط الأول (أكبر من 60) فيُنفَّذ فرعه ويخرج السلّم قبل أن يصل إلى 90. الترتيب في السلّم يبدأ من الأصعب إلى الأسهل.if داخل if: العمر ثم البطاقة
أحيانًا يكون القرار على مرحلتين: عند باب الكلية يسألك الحارس أولًا عن العمر، وفقط إذا نجحت يسأل عن البطاقة. نضع if داخل فرع if آخر وهذا يسمى الشرط المتداخل (nested if). هذه هي الممارسة الثانية في المعمل:
public class GateNested { public static void main(String[] args) { int age = 20; boolean hasCard = true; if (age >= 18) { if (hasCard) { System.out.println("Welcome in"); } else { System.out.println("Show your ID card"); } } else { System.out.println("Too young"); } }}
اكشف الإجابة
لا. شرط العمر يرفضه فيذهب مباشرة إلى فرع else الخارجي ويُطبع «Too young»، ولا يصل إلى سؤال البطاقة. السؤال الداخلي لا يُطرح إلا عند نجاح الخارجي.الاختصار: العامل الشرطي ? :
عندما يكون القرار بين قيمتين فقط، تمنحنا جافا اختصارًا اسمه العامل الشرطي (ternary operator) وصيغته condition ? valueIfTrue : valueIfFalse. يُقرأ هكذا: «هل الشرط صحيح؟ خذ القيمة الأولى، وإلا فالثانية». هذه هي الممارسة الثالثة في المعمل، أكبر عددين:
public class MaxDemo { public static void main(String[] args) { int n1 = 12; int n2 = 7; int max = (n1 > n2) ? n1 : n2; System.out.println("Maximum = " + max); }}
الشرط n1 > n2 يعني هل 12 أكبر من 7؟ نعم، فتؤخذ القيمة الأولى n1 وتُحفظ في max، فيُطبع Maximum = 12. وهو يعادل تمامًا if-else يضع في max إحدى القيمتين، لكن في سطر واحد.
تطبيق من الكافتيريا: خصم الطلبات الكبيرة
الكافتيريا تعطي خصم 10% لمن تبلغ فاتورته 200 أو أكثر. هذا قرار if بلا else؛ نبدأ بأن المبلغ المدفوع هو الفاتورة نفسها، ثم نعدّله إذا تحقق الشرط:
public class Cafeteria { public static void main(String[] args) { int total = 240; int pay = total; if (total >= 200) { pay = total - total / 10; } System.out.println("You pay: " + pay); }}
الفاتورة 240 تتجاوز حد الخصم، فيُخصم عُشرها (24) ويُطبع You pay: 216. جرّب أن تجعل total يساوي 150 فلن يدخل البرنامج فرع الخصم ويبقى المطبوع You pay: 150. نفس الفكرة تحل مسائل المعمل الأولى: هل العدد موجب أم سالب أم صفر؟ وهل هو زوجي أم فردي؟
int n = 0;
if (n > 0) {
System.out.println("Positive");
} else if (n < 0) {
System.out.println("Negative");
} else {
System.out.println("Zero");
}if (mark >= 60) {
System.out.println("Grade: D");
} else if (mark >= 90) {
System.out.println("Grade: A");
}int a = 3; int b = 8; System.out.println(a > b ? a : b);
لوحة المصعد — switch
وصلت إلى مبنى الكلية فوجدت مصعدًا بلوحة أزرار: تضغط رقم الطابق فيذهب إليه مباشرة دون أسئلة كثيرة.
بعد البوابة ومكتب الدرجات صعدت إلى مبنى الكلية. المصعد أمامك بلوحة أزرار: تضغط 3 فيذهب إلى الطابق الثالث، وتضغط 1 فيذهب إلى الأرضي. المصعد لا يسأل «هل الرقم أكبر من كذا؟»؛ يأخذ الرقم ويقفز إلى الطابق المناسب مباشرة.
كان يمكننا كتابة ذلك بسلسلة if / else if من الدرس 5·3، لكن حين نقارن قيمة واحدة بعدة قيم ثابتة تقدّم لنا جافا أداة أنظف هي تعليمة switch (التبديل). تأخذ التعليمة القيمة، وتبحث بين حالات (case) عن الحالة المطابقة، ثم تنفّذ ما فيها.
مثال كامل للوحة المصعد، حيث يطبع كل رقم اسم الطابق المقابل له:
public class LiftPanel { public static void main(String[] args) { int floor = 3; switch (floor) { case 1: System.out.println("Floor 1: Library"); break; case 2: System.out.println("Floor 2: Cafeteria"); break; case 3: System.out.println("Floor 3: Lecture halls"); break; default: System.out.println("There is no such floor"); } }}
اقرأ المثال سطرًا سطرًا
- switch (floor) تأخذ قيمة المتغير floor وتقارنها بالحالات بالترتيب. القيمة هنا 3 فتبدأ من case 3:.
- كل case يعني «إذا كانت القيمة تساوي هذا الرقم فابدأ التنفيذ من هنا». الرقم يُتبع بنقطتين رأسيتين :.
- break تعني «اخرج من تعليمة switch الآن». بدونها يتابع التنفيذ إلى الحالات التالية، وسنرى ذلك بعد قليل.
- default (الحالة الافتراضية) تُنفَّذ حين لا تطابق القيمة أي case، مثل الضغط على طابق غير موجود. مع القيمة 9 سيطبع البرنامج رسالة الطابق غير الموجود.
مع char وتجميع الحالات
switch لا تقتصر على int؛ تعمل أيضًا مع char ومع String. وحين تشترك أكثر من قيمة في الفرع نفسه نكتب حالاتها واحدة تحت الأخرى دون break بينها (تجميع الحالات):
public class GradeSwitch { public static void main(String[] args) { char grade = 'B'; switch (grade) { case 'A': case 'B': System.out.println("Well done"); break; case 'C': System.out.println("Pass"); break; default: System.out.println("See your instructor"); } }}
الحرفان A وB يشتركان في الفرع نفسه (الطباعة نفسها): عند B يبدأ التنفيذ من case 'B': وينزلق إلى السطر الذي يطبع Well done، ثم يخرج break. هنا الانزلاق مقصود ومفيد.
مع String
عند استخدام String تقارن switch النصوص بمعنى equals، أي حسب محتوى النص لا حسب موقعه في الذاكرة. وإذا لم يطابق النص أي حالة ولا يوجد default فلن يُنفَّذ شيء.
public class ServiceDesk { public static void main(String[] args) { String service = "print"; switch (service) { case "print": System.out.println("Printing office: floor 1"); break; case "library": System.out.println("Library: floor 2"); break; default: System.out.println("Unknown service"); } }}
فخ نسيان break
أشهر خطأ في switch هو نسيان break. حين تجد جافا الحالة المطابقة تبدأ التنفيذ منها، ثم تكمل إلى كل الحالات التي تحتها دون أن تفحصها، حتى تصل إلى break أو إلى نهاية التعليمة. هذا هو السقوط عبر الحالات (fall-through)، كمصعد يمر على كل الطوابق التالية بدل أن يتوقف:
public class LiftTrap { public static void main(String[] args) { int floor = 2; switch (floor) { case 1: System.out.println("Floor 1"); case 2: System.out.println("Floor 2"); case 3: System.out.println("Floor 3"); case 4: System.out.println("Floor 4"); } }}
تتبّع التنفيذ خطوة بخطوة عند اختيار الطابق 2:
توقّع: ماذا ستطبع لوحة المصعد عند اختيار الطابق 2؟
هل فُحص الرقم 3 هنا، أم دخلنا الحالة بالانزلاق فقط؟
الحل أن نضع break في نهاية كل حالة نريد أن تتوقف عندها:
public class LiftFixed { public static void main(String[] args) { int floor = 2; switch (floor) { case 1: System.out.println("Floor 1"); break; case 2: System.out.println("Floor 2"); break; case 3: System.out.println("Floor 3"); break; case 4: System.out.println("Floor 4"); break; } }}
switch أم if؟
الاختيار بينهما يعتمد على شكل السؤال:
| الحالة | الأنسب | مثال |
|---|---|---|
| قيمة واحدة تُقارن بقيم ثابتة | switch | رقم الطابق، رقم الشهر، خيار القائمة |
| نطاق من القيم | if / else if | الدرجة 90 فأكثر، العمر بين 18 و60 |
| شرط مركّب | if | العمر 18 فأكثر والبطاقة موجودة |
أمثلة من المعمل
المثال الأول من المعمل (Lab 5·2، التمرين 4): برنامج يقرأ رقم شهر من 1 إلى 4 ويطبع اسمه. إذا أدخلت 3 يطبع March، وأي رقم آخر يطبع رسالة الخطأ من default:
import java.util.Scanner;public class MonthName { public static void main(String[] args) { Scanner sc = new Scanner(System.in); System.out.println("Enter a month number (1-4):"); int month = sc.nextInt(); switch (month) { case 1: System.out.println("January"); break; case 2: System.out.println("February"); break; case 3: System.out.println("March"); break; case 4: System.out.println("April"); break; default: System.out.println("Invalid month"); } }}
والمثال الثاني (التمرين 5): حاسبة صغيرة تقرأ رقمين ثم اختيار العملية: 1 للجمع و2 للطرح، وأي اختيار آخر يعطي Invalid choice:
import java.util.Scanner;public class SimpleCalc { public static void main(String[] args) { Scanner sc = new Scanner(System.in); System.out.println("Enter two numbers:"); int a = sc.nextInt(); int b = sc.nextInt(); System.out.println("Choose 1 to add, 2 to subtract:"); int choice = sc.nextInt(); switch (choice) { case 1: System.out.println(a + " + " + b + " = " + (a + b)); break; case 2: System.out.println(a + " - " + b + " = " + (a - b)); break; default: System.out.println("Invalid choice"); } }}
public class ArrowLift { public static void main(String[] args) { int floor = 2; switch (floor) { case 1 -> System.out.println("Floor 1: Library"); case 2 -> System.out.println("Floor 2: Cafeteria"); case 3 -> System.out.println("Floor 3: Lecture halls"); default -> System.out.println("There is no such floor"); } }}
تلخيص الدرس
- switch تقارن قيمة واحدة (int أو char أو String) بعدة حالات case ثابتة.
- break تخرج من switch، ونسيانها يسبب السقوط عبر الحالات (fall-through).
- default تلتقط كل قيمة لا تطابق حالة، وتجميع الحالات يجعل عدة قيم تشترك في فرع واحد.
- للنطاقات والشروط المركبة نستعمل if، ولاختيار قيمة من قائمة ثابتة نستعمل switch.
int x = 2;
switch (x) {
case 1:
System.out.print("A");
case 2:
System.out.print("B");
case 3:
System.out.print("C");
break;
case 4:
System.out.print("D");
}char g = 'C';
switch (g) {
case 'A':
case 'B':
System.out.println("Great");
break;
case 'C':
case 'D':
System.out.println("Pass");
break;
default:
System.out.println("Retry");
}تحدي: أين الخطأ؟
ثلاثة برامج عن القرارات: أحدها لا يُترجم أصلًا، والثاني يعمل لكنه يطبع شيئًا غير منطقي، والثالث يسقط عبر الحالات. اقرأ الكود وتتبّعه ثم اضغط على السطر المخالف.
المقطع ١: نريد أن يسأل البرنامج هل x يساوي 5، لكنه يرفض الترجمة برسالة incompatible types. أين الخطأ؟
الشرط يجب أن يعطي true أو false. ما نوع القيمة التي تنتجها x = 5؟ وما الفرق بين علامة واحدة وعلامتين (الدرس 5·1)؟
المقطع ٢: الدرجة 45 راسبة، ومع ذلك يطبع البرنامج Passed. أين الخطأ؟
ماذا يعني وجود ; مباشرة بعد قوس الشرط؟ هل بقي للشرط جسم يتحكم في سطر الطباعة (الدرس 5·3)؟
المقطع ٣: ضغطنا الطابق 1 فطبع المصعد Floor 1: Library ثم Floor 2: Cafeteria أيضًا! أين الخطأ؟
عند مطابقة case 1: أين يتوقف التنفيذ؟ ما الذي ينقصه ليخرج من switch قبل الحالة التالية (فخ السقوط في الدرس 5·4)؟
تمارين الوحدة ٥
تمارين على القرارات في جافا (المقارنة، وif، وelse if، والمنطق، وswitch). كل تمرين أمامه كود ناقص: اضغط «✎ تعديل»، اكتب الكود المطلوب مكان التعليقات، اضغط «✔ حفظ» ثم «▶ تشغيل» وقارن النتيجة بالهدف. أدخل القيم الاختبارية المكتوبة في كل تمرين حتى يطابق إخراجك الهدف.
اقرأ عددًا صحيحًا بـ nextInt() ثم اطبع Positive إذا كان أكبر من 0، وNegative إذا كان أصغر من 0، وZero إذا كان يساوي 0. القيمة الاختبارية: أدخل «-7».
import java.util.Scanner;public class SignCheck { public static void main(String[] args) { Scanner sc = new Scanner(System.in); // ١) اطبع (بـ println في سطر مستقل) "Enter a number:" ثم اقرأ العدد في n بـ nextInt // ٢) if: إذا كان n أكبر من 0 فاطبع Positive، // else if: إذا كان أصغر من 0 فاطبع Negative، // else: فاطبع Zero }}
Enter a number: Negative
اقرأ إجمالي فاتورة الكافتيريا (عددًا صحيحًا). إذا كان 200 فأكثر اطبع Discount available وإلا اطبع No discount. القيمة الاختبارية: أدخل «250».
import java.util.Scanner;public class Discount { public static void main(String[] args) { Scanner sc = new Scanner(System.in); // ١) اطبع (بـ println في سطر مستقل) "Enter the bill total:" ثم اقرأ المبلغ في total بـ nextInt // ٢) if: إذا كان total أكبر من أو يساوي 200 فاطبع Discount available // else: فاطبع No discount }}
Enter the bill total: Discount available
اقرأ درجة الطالب وحوّلها إلى تقدير: 90 فأكثر A، ثم 80 فأكثر B، ثم 70 فأكثر C، ثم 60 فأكثر D، وما دون ذلك F، واطبع بالشكل Grade: B. القيمة الاختبارية: أدخل «83».
import java.util.Scanner;public class GradeCalc { public static void main(String[] args) { Scanner sc = new Scanner(System.in); // ١) اطبع (بـ println في سطر مستقل) "Enter your mark:" ثم اقرأ الدرجة في mark بـ nextInt // ٢) استعمل سلسلة if / else if: // 90 فأكثر A، ثم 80 B، ثم 70 C، ثم 60 D، وما عدا ذلك F // واطبع بالشكل: Grade: B }}
Enter your mark: Grade: B
البوابة تقرأ العمر وهل معك بطاقة (1 نعم، 0 لا). إذا كان العمر 18 فأكثر و البطاقة موجودة تُفتح وتعرض قائمة الوجهات لتقرأ اختيارك وتنفّذ switch. وفي else if (تحقق شرط واحد فقط: أحدهما أو الآخر) تطبع Visitor pass needed، وفي else تطبع Gate closed. القيم الاختبارية: أدخل «20» ثم «1» ثم «2».
import java.util.Scanner;public class SmartGate { public static void main(String[] args) { Scanner sc = new Scanner(System.in); // ١) اطبع (بـ println في سطر مستقل) "Enter your age:" ثم اقرأ العمر في age // ٢) اطبع (بـ println في سطر مستقل) "Enter 1 if you have a card, 0 if not:" ثم اقرأ card // ٣) if: إذا كان age أكبر من أو يساوي 18 و card يساوي 1 (&&): // اطبع (بـ println) Gate open ثم اطبع (بـ println) "Where to? 1 Library, 2 Lab, 3 Cafeteria" // واقرأ place، ثم switch: 1 يطبع Going to Library، // و2 يطبع Going to Lab، و3 يطبع Going to Cafeteria، // وغير ذلك يطبع Unknown destination // else if: إذا كان واحد من الشرطين فقط محققًا (||): اطبع Visitor pass needed // else: اطبع Gate closed }}
Enter your age: Enter 1 if you have a card, 0 if not: Gate open Where to? 1 Library, 2 Lab, 3 Cafeteria Going to Lab