مقدّمة إلى Records
مقدّمة إلى Records
كتب كلّ مطوّر جافا في حياته كلاسًا لا غرض منه سوى حمل عدد من القيم وتمريرها — إحداثيتا نقطة، استجابة من واجهة برمجية، نتيجة بحث. كتابة هذا الكلاس بالطريقة التقليدية تعني ملء لوحة المفاتيح بمنشئ، وحقل لكل عنصر، وgetters، وequals()، وhashCode()، وtoString(). هذا نحو 30–50 سطرًا لما هو في جوهره مجرد صف مسمّى. أصبحت السجلات (records) ميزةً دائمة في لغة جافا منذ الإصدار 16، وجاءت لتحلّ هذه المشكلة تحديدًا.
المشكلة التي تحلّها السجلات
لنفكّر في كلاس بسيط يمثّل نقطة ثنائية الأبعاد:
في كل مرة يتغيّر فيها التصميم تضطرّ لتعديل عدة توابع. القصد الأصلي — "نقطة لها x وy" — يضيع وسط ضجيج التنفيذ.
الكلمة المفتاحية record
يُعلن السجل عن اسم الكلاس ومكوّناته في سطر واحد:
هذا السطر الواحد يمنحك كل ما منحه الإصدار ذو الثلاثين سطرًا:
- حقلان
private final، هماxوy. - منشئ أساسي (canonical constructor) —
Point(int x, int y)— يُسنِد كلا الحقلين. - توابع وصول
x()وy()(لاحظ: بدون بادئةget— وهذا مقصود). equals()قائم على القيمة يقارن جميع المكوّنات.hashCode()متسق مشتق من جميع المكوّنات.toString()مقروء يطبعPoint[x=3, y=7].
استخدام السجل
لاحظ أن equals قائم على القيمة: كائنان منفصلان من نوع Point بنفس الإحداثيات يُعدّان متساويَين، تمامًا كما تتوقّع من كلاس بيانات.
السجلات ضمنيًا نهائية (final)
الكلاس المُعرَّف كسجل هو final بشكل افتراضي — لا يمكنك التوسّع منه. يمكنك تطبيق واجهات (interfaces)، لكن لا يمكنك إنشاء كلاس فرعي من سجل. هذا ليس قيدًا بل خيارًا تصميميًا مدروسًا يُبقي معنى السجل واضحًا: هويّته تتحدّد كليًا بمكوّناته، والسماح للكلاسات الفرعية بإضافة حالة خفية يكسر هذا الضمان.
السجلات غير قابلة للتغيير بحكم التصميم
كل حقل مكوّن هو private final. لا يوجد setters مولَّد. بمجرد إنشاء السجل لا يمكن تغيير حالته. هذه الثبوتية (immutability) إحدى أهم الخصائص التي يجلبها السجل — تجعله آمنًا للمشاركة عبر خيوط التنفيذ (threads) وسهل التفكير فيه.
equals() وhashCode() موثوقَين، تعمل بشكل صحيح كمفاتيح في Map وفي Set وفي المجموعات — دون الحاجة إلى نسخ دفاعية.
مثال ثانٍ: ملخّص استجابة HTTP
ما السجلات ليست عليه
- ليست JavaBeans — لا توابع وصول بأسلوب
getX()، ولا منشئ بلا معاملات، ولا setters. - ليست مجرد اختصار لأي كلاس — استخدم السجلات فقط حين يكون الكلاس حقًا هو بياناته (نتيجة، أمر، إحداثية، نطاق). إن احتجت قابلية التغيير أو الوراثة، استخدم كلاسًا عاديًا.
- ليست أنواع قيمة (كـ structs في C) — لا تزال كائنات مرجعية مخصَّصة على الكومة (heap) في الـ JVM الحالية.
الخلاصة
السجلات هي إجابة جافا على ضريبة الشكليات في كلاسات البيانات غير قابلة التغيير. الكلمة المفتاحية record تستبدل عشرات الأسطر من الكود الميكانيكي بتعريف واحد يُعبّر بوضوح عمّا يكون عليه النوع. يولّد المُصرِّف المنشئ الأساسي والتوابع الوصولية وequals وhashCode وtoString نيابةً عنك — والنوع الناتج نهائي وثابت وصحيح بحكم البناء. في الدرس القادم ستتعلّم كيف تُضيف توابعك الخاصة إلى سجل وتُخصّص المنشئ المولَّد حين تحتاج التحقق من المدخلات.