كيفية ترويض الفوضى: فرز ArrayList للكائنات حسب أي حقل في Java
\n\nتخيل: أنت تكتب تطبيقًا لفهرس الكتب. لديك كلاس Book مع حقول title، author، price و year. تقوم بتجميع عشرات الكتب في ArrayList. وفجأة يطلب منك المستخدم: "أظهر الأحدث أولاً!"، وبعد دقيقة — "لا، رتب حسب السعر!".
إذا واجهت هذه المهمة من قبل، فأنت تعلم أن مجرد استدعاء Collections.sort(list) لن ينجح. Java لا تستطيع قراءة الأفكار. تحتاج إلى توضيح: أي حقل بالضبط تريد الفرز بناءً عليه. هذا هو بالضبط الموضوع الأكثر شيوعًا على Stack Overflow حول فرز الكائنات المخصصة.
في هذه المقالة، سنستعرض جميع طرق فرز ArrayList حسب خاصية الكائن: من الكلاسيكي Comparable إلى تعبيرات لامدا الأنيقة و Stream API. هيا بنا!
التحضير: الكلاس الذي سنقوم بفرزه
\n\nللأمثلة، سننشئ كلاسًا بسيطًا Person:
public class Person {\n private String name;\n private int age;\n private double salary;\n\n public Person(String name, int age, double salary) {\n this.name = name;\n this.age = age;\n this.salary = salary;\n }\n\n // Getters (سنحذف Setters للاختصار)\n public String getName() { return name; }\n public int getAge() { return age; }\n public double getSalary() { return salary; }\n\n @Override\n public String toString() {\n return name + " (" + age + " سنة، $" + salary + ")";\n }\n}\n\n\nوسنملأ قائمتنا:
\n\nArrayList<Person> people = new ArrayList<>();\npeople.add(new Person("آنا", 28, 55000));\npeople.add(new Person("بوريس", 35, 72000));\npeople.add(new Person("فيكتور", 22, 48000));\npeople.add(new Person("غالينا", 30, 62000));\n\n\nالآن كل شيء جاهز للتجارب. كيف نفرز هذه القائمة حسب العمر؟ حسب الاسم؟ حسب الراتب؟ لدى Java ثلاث طرق على الأقل. لنبدأ بالأساسي.
\n\nالطريقة 1: Comparable — دمج منطق الفرز مباشرة في الكلاس
\n\nالواجهة Comparable هي "الترتيب الطبيعي" للكائن. إذا كنت تريد أن يتم فرز كائناتك دائمًا حسب حقل واحد (مثل العمر)، قم بتطبيق هذه الواجهة.
لنعدل كلاس Person:
public class Person implements Comparable<Person> {\n // ... الحقول، المُنشئ، الـ Getters ...\n\n @Override\n public int compareTo(Person other) {\n return Integer.compare(this.age, other.age);\n }\n}\n\n\nالآن الفرز في سطر واحد:
\n\nCollections.sort(people);\nSystem.out.println(people);\n// الإخراج: [فيكتور (22 سنة، $48000), آنا (28 سنة، $55000), غالينا (30 سنة، $62000), بوريس (35 سنة، $72000)]\n\n\nالإيجابيات: البساطة، لا حاجة للتفكير في المقارنات الخارجية.
\nالسلبيات: تقوم "بتضمين" طريقة فرز واحدة فقط في الكلاس. إذا احتجت غدًا للفرز حسب الاسم — سيتعين عليك تغيير الكلاس.
بالمناسبة، للترتيب العكسي (من الأكبر إلى الأصغر) يمكنك استخدام Collections.reverseOrder():
Collections.sort(people, Collections.reverseOrder());\n\n\nالطريقة 2: Comparator — مرونة دون تغيير الكلاس
\n\nعندما تحتاج إلى الفرز بطرق مختلفة في أجزاء مختلفة من البرنامج، يأتي Comparator للإنقاذ. هو كلاس منفصل أو كلاس مجهول يحتوي على منطق المقارنة.
الكلاس المجهول — طريقة الأجداد
\n\nCollections.sort(people, new Comparator<Person>() {\n @Override\n public int compare(Person p1, Person p2) {\n return p1.getName().compareTo(p2.getName());\n }\n});\n\n\nيعمل، لكنه يبدو ضخمًا. في