قائمة تُعيد ضبط حجمها بنفسها
للمصفوفة العادية في جافا طول ثابت: إذا اخترت عشرة مواضع فستبقى عشرة مواضع إلى الأبد. أما ArrayList فهي البديل المتغير الحجم من java.util - تكبر مع الإضافة وتصغر مع الحذف، وتحمل طرقاً مفيدة لما تفعله فعلاً مع القائمة.
لاحظ النوع بين القوسين الزاويين - List<String> - الذي يخبر المترجم بأن هذه القائمة تحمل قيم String. والقوسان <> ("الماسة") على الجانب الآخر يتيحان لجافا استنتاج النوع نفسه دون تكراره. ولاحظ أنك تستورد java.util.ArrayList؛ فهي ليست متاحة افتراضياً.
صرّح كـ List وأنشئ كـ ArrayList
ستجد المتغير دائماً تقريباً مُصرّحاً عنه بواجهة List بدلاً من ArrayList الملموسة:
List<String> names = new ArrayList<>();
هذه عادة جيدة وليست قاعدة. البرمجة وفق واجهة List تعني أن بقية شيفرتك لا تهتم بأي تنفيذ للقائمة استخدمت، فيمكنك استبداله بآخر لاحقاً دون المساس بها. وفي الاستخدام اليومي يتصرف كلاهما بالطريقة نفسها.
الإضافة والجلب والتعديل
add(value)يضيف في النهاية.add(index, value)يُدرج عند موضع معيّن، مع إزاحة العناصر اللاحقة إلى الأمام.get(index)يقرأ العنصر عند موضع معيّن (يبدأ من الصفر).set(index, value)يكتب فوق عنصر موجود.
تبدأ الفهارس من الصفر، واستدعاء get على فهرس خارج النطاق يُطلق استثناء IndexOutOfBoundsException.
حذف العناصر
ثمة فخّ كلاسيكي عندما تحمل القائمة Integer. فـ remove(int) تعني "الحذف حسب الفهرس" وremove(Object) تعني "الحذف حسب القيمة"، لذلك:
List<Integer> nums = new ArrayList<>(List.of(10, 20, 30));
nums.remove(1); // يحذف الفهرس 1 -> القيمة 20
nums.remove(Integer.valueOf(20)); // يحذف القيمة 20
غلّف القيمة بـ Integer.valueOf(...) عندما تقصد "احذف هذه القيمة" لا "احذف هذا الفهرس".
الحجم وcontains والبحث بالفهرس
تُنشئ List.of(...) قائمة غير قابلة للتعديل بسرعة؛ وتمريرها إلى مُنشئ ArrayList يمنحك نسخة قابلة للتعديل مهيّأة بتلك القيم.
التكرار على ArrayList
أنظف حلقة هي for المُحسَّنة (حلقة "for-each"):
عندما تحتاج إلى الفهرس أيضاً، استخدم حلقة معدودة مع size() وget(i):
قاعدة واحدة: لا تُضِف عناصر إلى قائمة ولا تحذف منها بينما تتكرر حلقة for-each عليها - فذلك يُطلق استثناء ConcurrentModificationException. ولحذف العناصر المطابقة بأمان، استخدم removeIf:
الفرز
تُرتّب Collections.sort القائمة في مكانها وفق الترتيب الطبيعي (أبجدياً للسلاسل النصية وعددياً للأعداد):
لترتيبات مخصّصة، مرّر Comparator إلى list.sort(...) - مثلاً names.sort(Comparator.comparingInt(String::length)) للفرز حسب الطول.
ArrayList تحمل كائنات لا أنواعاً أولية
لا يمكنك كتابة ArrayList<int>. فالأنواع العامة (Generics) تعمل مع أنواع الكائنات فقط، لذا استخدم أصناف التغليف Integer وDouble وBoolean وهكذا:
يتولّى التغليف التلقائي (autoboxing) في جافا التحويل نيابةً عنك بين int وInteger، فتُقرأ الشيفرة على نحو طبيعي - فقط تذكّر أن القائمة نفسها تخزّن كائنات Integer.
التالي: HashMap
ArrayList هي الأداة المناسبة عندما يهمّك الترتيب والموضع. أما حين تحتاج إلى البحث عن الأشياء بمفتاح - اسم مستخدم مقابل مستخدم، رمز منتج مقابل سعر - فأنت بحاجة إلى HashMap، وهي موضوع الصفحة التالية.
الأسئلة الشائعة
كيف تُنشئ ArrayList في جافا؟
صرّح عنها بنوع العناصر بين قوسين زاويين واستدعِ المُنشئ: ArrayList<String> names = new ArrayList<>();. القوسان <> على الجانب الآخر (الماسة) يتيحان لجافا استنتاج النوع. عادةً ما تُصرّح عن المتغير بواجهة List: List<String> names = new ArrayList<>();.
ما الفرق بين المصفوفة وArrayList في جافا؟
للمصفوفة العادية طول ثابت يُحدَّد عند إنشائها، ويمكنها أن تحمل أنواعاً أولية مثل int. أما ArrayList فتكبر وتصغر تلقائياً كلما أضفت أو حذفت عناصر، ولا تحمل سوى الكائنات (فيصبح int هو Integer)، وتأتي بطرق مثل add وremove وcontains وsize. استخدم المصفوفة للبيانات الأولية ذات الحجم الثابت؛ واستخدم ArrayList عندما يتغير الحجم.
كيف تحذف عنصراً من ArrayList؟
استدعِ remove(index) للحذف حسب الموضع، أو remove(object) لحذف أول عنصر مطابق. انتبه مع قوائم Integer: فـ list.remove(2) يحذف الفهرس 2، بينما list.remove(Integer.valueOf(2)) يحذف القيمة 2. للحذف أثناء التكرار، استخدم remove() الخاص بـ Iterator أو removeIf(...) لتجنّب استثناء ConcurrentModificationException.