تخطَّ إلى المحتوى

المجموعات في Java: ArrayList و HashMap و HashSet

الدرس 11 من 11 · Java

المصفوفة حجمها ثابت، والتطبيقات الحقيقية بياناتها تكبر وتصغر طوال الوقت: سلة مشتريات، قائمة أصدقاء، درجات طلاب. لهذا توفر Java مكتبة المجموعات (Collections). في هذا الدرس ستتقن أهم ثلاثة أنواع فيها: القائمة List، والخريطة Map، والمجموعة Set، وستعرف متى تختار كل واحدة.

كل أمثلة الدرس تحتاج هذا السطر في أول الملف:

import java.util.*;

تعرفت عليها سريعاً في درس المصفوفات. هي قائمة مرتبة يتغير حجمها، وتسمح بتكرار العناصر:

List<String> tasks = new ArrayList<>();
tasks.add("المذاكرة");
tasks.add("الرياضة");
tasks.add(0, "الفطور");
System.out.println(tasks);
System.out.println(tasks.get(1));
System.out.println(tasks.size());
tasks.set(2, "السباحة");
tasks.remove("المذاكرة");
System.out.println(tasks);
System.out.println(tasks.contains("الرياضة"));
الناتج
[الفطور, المذاكرة, الرياضة]
المذاكرة
3
[الفطور, السباحة]
false
  • add(x) تضيف في الآخر، و add(0, x) تضيف في موضع محدد.
  • get(i) للقراءة، و set(i, x) للاستبدال، و size() لعدد العناصر.
  • remove تحذف بالقيمة أو بالموضع، و contains تبحث.
List<Integer> scores = new ArrayList<>(List.of(70, 95, 82, 60));
Collections.sort(scores);
System.out.println(scores);
scores.sort(Comparator.reverseOrder());
System.out.println(scores);
int sum = 0;
for (int score : scores) {
sum += score;
}
System.out.println("المجموع: " + sum);
System.out.println("الأعلى: " + Collections.max(scores));
الناتج
[60, 70, 82, 95]
[95, 82, 70, 60]
المجموع: 307
الأعلى: 95

List.of(...) تنشئ قائمة ثابتة لا تقبل التعديل، ولذلك وضعناها داخل new ArrayList<>(...) للحصول على نسخة قابلة للتغيير.

الخريطة (Map) تخزن أزواجاً: مفتاح وقيمته. تماماً مثل دليل الهاتف: تبحث بالاسم فتحصل على الرقم مباشرة، دون المرور على كل الصفحات.

Map<String, Integer> stock = new HashMap<>();
stock.put("قلم", 40);
stock.put("دفتر", 15);
stock.put("قلم", 38);
System.out.println(stock.get("قلم"));
System.out.println(stock.get("مسطرة"));
System.out.println(stock.getOrDefault("مسطرة", 0));
System.out.println(stock.containsKey("دفتر"));
System.out.println(stock.size());
الناتج
38
null
0
true
2
  • Map<String, Integer>: نوع المفتاح ثم نوع القيمة.
  • put: تضيف زوجاً جديداً، وإذا كان المفتاح موجوداً تستبدل قيمته. المفاتيح لا تتكرر.
  • get: تُرجع القيمة، أو null إذا لم يوجد المفتاح.
  • getOrDefault: تُرجع قيمة بديلة بدل null، وهي أكثر أماناً.
Map<String, Integer> ages = new TreeMap<>();
ages.put("Omar", 15);
ages.put("Ali", 13);
ages.put("Sara", 14);
for (Map.Entry<String, Integer> entry : ages.entrySet()) {
System.out.println(entry.getKey() + " = " + entry.getValue());
}
System.out.println(ages.keySet());
الناتج
Ali = 13
Omar = 15
Sara = 14
[Ali, Omar, Sara]

مثال عملي: عدّ التكرارات

Section titled “مثال عملي: عدّ التكرارات”

من أشهر استخدامات الخريطة: كم مرة ظهرت كل كلمة؟

String[] votes = { "أحمر", "أزرق", "أحمر", "أخضر", "أحمر", "أزرق" };
Map<String, Integer> counts = new TreeMap<>();
for (String vote : votes) {
counts.put(vote, counts.getOrDefault(vote, 0) + 1);
}
System.out.println(counts.get("أحمر"));
System.out.println(counts.get("أزرق"));
System.out.println(counts.get("أخضر"));
الناتج
3
2
1

في كل مرة نقرأ العدد الحالي للون (أو صفراً إن لم يظهر من قبل)، ونزيده واحداً.

المجموعة (Set) تشبه القائمة لكنها ترفض التكرار، ولا ترقّم عناصرها:

Set<String> visitors = new TreeSet<>();
visitors.add("Sara");
visitors.add("Omar");
System.out.println(visitors.add("Sara"));
System.out.println(visitors);
System.out.println(visitors.contains("Omar"));
List<Integer> numbers = List.of(3, 1, 3, 2, 1);
Set<Integer> unique = new TreeSet<>(numbers);
System.out.println(unique);
الناتج
false
[Omar, Sara]
true
[1, 2, 3]

add تُرجع false عندما يكون العنصر موجوداً ولا تضيفه مرة ثانية. وكما في الخرائط: HashSet أسرع لكن بلا ترتيب، و TreeSet ترتب عناصرها. المجموعة مثل سجل حضور: الاسم يُكتب مرة واحدة مهما دخل صاحبه وخرج.

تحتاج إلى استخدم
عناصر مرتبة تصل إليها برقم الموضع ArrayList
البحث عن قيمة بمفتاح (اسم ← رقم) HashMap
عناصر بلا تكرار والتحقق السريع من الوجود HashSet
  1. أنشئ ArrayList فيها خمس درجات، واحذف أقل درجة، ثم اطبع المتوسط.
  2. أنشئ HashMap تربط اسم الدولة بعاصمتها، واطبع عاصمة دولة غير موجودة باستخدام getOrDefault.
  3. خزّن جملة في متغير، وقسّمها بـ split(" ")، واستخدم Set لمعرفة عدد الكلمات المختلفة فيها.
  4. تحدٍّ: استخدم Map<String, List<Integer>> لتخزين عدة درجات لكل طالب، ثم اطبع متوسط كل طالب.
  • الحذف من List الأرقام: list.remove(1) تحذف العنصر في الموضع 1، لا القيمة 1. لحذف القيمة اكتب list.remove(Integer.valueOf(1)).
  • تعديل قائمة ثابتة: الإضافة إلى ناتج List.of(...) ترمي UnsupportedOperationException.
  • الحذف داخل for-each: حذف عنصر من القائمة أثناء المرور عليها يرمي ConcurrentModificationException. استخدم removeIf مثل list.removeIf(x -> x < 50).
  • تجاهل null: map.get(key) قد تُرجع null، واستخدامها مباشرة في عملية حسابية يسبب NullPointerException.

سؤال

ماذا يحدث عند استدعاء put بمفتاح موجود مسبقاً في HashMap؟

سؤال

أي مجموعة تختار لتخزين أسماء الزوار دون تكرار؟

  • ArrayList: قائمة مرتبة يتغير حجمها، وتُرتب بـ Collections.sort أو sort.
  • HashMap: أزواج مفتاح وقيمة، مع put و get و getOrDefault و entrySet.
  • HashSet: عناصر بلا تكرار. و TreeMap و TreeSet نسخ مرتبة منهما.
  • المجموعات تخزن كائنات: Integer وليس int.
  • مبروك! أنهيت كورس Java. طبّق ما تعلمته في مشروع صغير، فالتطبيق أفضل معلم.