أساسيات جافا

قراءة مدخلات المستخدم باستخدام Scanner

15 دقيقة الدرس 6 من 14

قراءة مدخلات المستخدم باستخدام Scanner

حتى الآن كانت جميع القيم في برامجك مكتوبةً مسبقًا في الكود. البرامج الحقيقية تحتاج إلى الاستجابة للمستخدم — طلب اسم أو رقم أو خيار. توفّر Java الصنف Scanner الموجود في حزمة java.util تحديدًا لهذا الغرض؛ إذ يُغلّف أي تيار إدخال (لوحة المفاتيح، الملف، الشبكة) ويتيح لك استخراج البيانات قطعةً قطعة.

الاستيراد وإنشاء Scanner

قبل استخدام Scanner يجب استيراده، ثم إنشاء نسخة منه مرتبطة بـ System.in — تيار الإدخال القياسي الذي يمثّل لوحة المفاتيح.

import java.util.Scanner; public class HelloInput { public static void main(String[] args) { Scanner scanner = new Scanner(System.in); System.out.print("Enter your name: "); String name = scanner.nextLine(); System.out.println("Hello, " + name + "!"); scanner.close(); } }
أغلق Scanner دائمًا عند الانتهاء من القراءة. استدعاء scanner.close() يُحرّر المورد الداخلي. في البرامج البسيطة يكون هذا أقل أهمية، لكنه عادة جيدة تستحق البناء عليها منذ البداية.

قراءة أنواع مختلفة من البيانات

يمتلك Scanner عائلةً من توابع next…() تتناسب كل منها مع نوع أساسي في Java:

  • nextLine() — يقرأ السطر كاملًا حتى حرف السطر الجديد ويُعيد النص دون ذلك الحرف.
  • next() — يقرأ الرمز التالي (سلسلة من الأحرف مفصولة بمسافات). يتوقف عند المسافة.
  • nextInt() — يقرأ الرمز التالي ويُحوّله إلى int.
  • nextDouble() — يقرأ الرمز التالي ويُحوّله إلى double.
  • nextBoolean() — يقرأ true أو false (غير حساس لحالة الأحرف).
  • nextLong()، nextFloat() — للأعداد الأكبر أو أحادية الدقة.
import java.util.Scanner; public class ReadNumbers { public static void main(String[] args) { Scanner scanner = new Scanner(System.in); System.out.print("Enter your age: "); int age = scanner.nextInt(); System.out.print("Enter your GPA: "); double gpa = scanner.nextDouble(); System.out.println("Age: " + age + ", GPA: " + gpa); scanner.close(); } }

عند استدعاء nextInt() يقرأ Scanner الأحرف حتى يرى مسافةً بيضاء، يُحوّل النص إلى int ويُعيده. حرف السطر الجديد الذي ضغطه المستخدم يبقى في المخزن المؤقت — وهذا هو مصدر المشكلة الأكثر شيوعًا في Scanner.

مشكلة nextLine() الشهيرة

تخيّل أنك تريد قراءة عدد صحيح ثم سطر نصي كامل:

import java.util.Scanner; public class PitfallDemo { public static void main(String[] args) { Scanner scanner = new Scanner(System.in); System.out.print("Enter your age: "); int age = scanner.nextInt(); // يقرأ "25" ويترك "\n" في المخزن System.out.print("Enter your city: "); String city = scanner.nextLine(); // يستهلك "\n" المتبقي فورًا — city تساوي ""! System.out.println("Age: " + age + ", City: " + city); scanner.close(); } }

البرنامج لا ينتظر إدخال المدينة لأن nextLine() استهلك السطر الجديد الذي تركه nextInt(). الحل هو إضافة استدعاء scanner.nextLine() مجاني مباشرةً بعد القراءة الرقمية لتفريغ ذلك السطر المتبقي:

import java.util.Scanner; public class PitfallFixed { public static void main(String[] args) { Scanner scanner = new Scanner(System.in); System.out.print("Enter your age: "); int age = scanner.nextInt(); scanner.nextLine(); // تفريغ السطر الجديد المتبقي System.out.print("Enter your city: "); String city = scanner.nextLine(); // الآن ينتظر المدخل الحقيقي System.out.println("Age: " + age + ", City: " + city); scanner.close(); } }
مشكلة nextLine() هي أكثر أخطاء Scanner شيوعًا لدى المبتدئين. في كل مرة تمزج فيها بين nextInt() أو nextDouble() أو أي تابع رمزي آخر وبين nextLine() لاحق، أضف استدعاء scanner.nextLine() فارغًا بينهما لاستهلاك السطر الجديد المعلّق.

قراءة قيم متعددة باستخدام حلقة

يمكن دمج الحلقة مع Scanner لمعالجة أي عدد من المدخلات. نمط شائع هو القراءة حتى يكتب المستخدم قيمة نهائية — مدخل خاص يشير إلى انتهاء الإدخال:

import java.util.Scanner; public class SumLoop { public static void main(String[] args) { Scanner scanner = new Scanner(System.in); double total = 0; int count = 0; System.out.println("Enter numbers one per line. Type 0 to stop."); double value = scanner.nextDouble(); while (value != 0) { total += value; count++; value = scanner.nextDouble(); } if (count > 0) { System.out.printf("Sum: %.2f Average: %.2f%n", total, total / count); } else { System.out.println("No numbers were entered."); } scanner.close(); } }

التحقق من توفر المدخل

قبل استدعاء تابع القراءة يمكنك التحقق من أن الرمز التالي من النوع المتوقع فعلًا باستخدام التابع المقابل has…(). هذا يمنع الاستثناء InputMismatchException عندما يكتب المستخدم نصًا حيث يُتوقع رقم:

import java.util.Scanner; public class SafeRead { public static void main(String[] args) { Scanner scanner = new Scanner(System.in); System.out.print("Enter an integer: "); if (scanner.hasNextInt()) { int number = scanner.nextInt(); System.out.println("You entered: " + number); } else { System.out.println("That is not a valid integer."); } scanner.close(); } }
استخدم hasNextInt() / hasNextDouble() عند بناء برامج تفاعلية يجب أن تتعامل مع المدخلات الخاطئة بأمان. في برامج التمارين البسيطة القراءة المباشرة كافية — لكن معرفة هذا النمط ستنقذك عندما تكون المدخلات غير متوقعة.

الخلاصة

الصنف Scanner هو الجسر بين لوحة المفاتيح وبرنامجك. تذكّر النقاط الأساسية: استورد java.util.Scanner، أنشئ نسخة بـ new Scanner(System.in)، استخدم nextInt() و nextDouble() للمدخلات الرقمية و nextLine() للنصوص الكاملة، فرّغ السطر الجديد المتبقي بعد كل قراءة رمزية يعقبها nextLine()، وأغلق Scanner عند الانتهاء. بهذه الأداة يمكنك كتابة برامج تفاعلية تستجيب لمدخلات المستخدم الحقيقية — وهو الأساس لآلة الحاسبة التي ستبنيها في نهاية هذا الدرس التعليمي.