الوسائط المتغيرة (varargs)
الوسائط المتغيرة (varargs)
حتى الآن كنت تكتب توابع تعرف فيها عدد المعاملات المطلوب تحديدًا. لكن ماذا لو كان عدد القيم التي يريد المُستدعي تمريرها غير ثابت؟ تحلّ Java هذه المشكلة بأناقة عبر الوسائط المتغيرة، المعروفة اختصارًا بـ varargs. وهي تتيح لتابع واحد قبول أي عدد من الوسائط التي تنتمي إلى نفس النوع — صفر، أو واحد، أو أكثر — دون الحاجة إلى بناء مصفوفة قبل الاستدعاء.
صياغة ...
تُعلن عن معامل varargs بوضع ثلاث نقاط (...) بين النوع واسم المعامل:
داخل التابع، يتصرف numbers تمامًا كمصفوفة int[] عادية. يجمع وقت تشغيل Java تلقائيًا كل الوسائط التي يمررها المُستدعي ويحزمها في تلك المصفوفة نيابةً عنك.
وهذا مثال على طريقة استدعاء التابع أعلاه:
sum(1, 2, 3)، يحوّلها المُترجم صامتًا إلى sum(new int[]{1, 2, 3}). بمعنى آخر، يمكنك أيضًا تمرير مصفوفة جاهزة مباشرةً: int[] vals = {4, 5, 6}; sum(vals);. كلا الأسلوبين يُترجم ويعمل بالطريقة ذاتها.
لماذا نستخدم varargs؟
تأمّل البديل من دون varargs. للسماح بعدد مرن من الوسائط ستحتاج إلى توابع متعددة متحمّلة (overloads)، أو إجبار كل مُستدعٍ على إنشاء مصفوفة:
تستبدل varargs كل تلك التوابع بتابع واحد نظيف. تكتب المنطق مرة واحدة، ويحصل المُستدعون على صياغة طبيعية تُقرأ كوسائط عادية.
varargs مع المعاملات العادية
يمكن دمج معامل varargs مع معاملات عادية، لكن مع قاعدة صارمة واحدة: يجب دائمًا أن يكون معامل varargs في النهاية في قائمة المعاملات.
طريقة استدعاء هذا التابع:
يرتبط الوسيط الأول دائمًا بـ title. كل ما يليه — بأي عدد من القيم — يتدفق إلى مصفوفة scores. إذا لم تُمرَّر قيم للدرجات، فإن scores تكون ببساطة مصفوفة فارغة (طولها 0)، وليست null.
null.
نمط شائع في الواقع العملي: مساعدو تنسيق النصوص
تستخدم مكتبة Java القياسية varargs بكثافة. كلٌّ من String.format() وSystem.out.printf() وأطر تسجيل الأحداث الكثيرة تقبل سلسلة تنسيق يتبعها مصفوفة varargs من القيم:
فهم varargs يساعدك على قراءة مثل هذه الواجهات البرمجية واستخدامها بثقة.
القيود والأخطاء الشائعة
- varargs واحدة فقط لكل تابع. لا يمكن كتابة
void foo(int... a, String... b)— المُترجم يرفض ذلك. - يجب أن تكون الأخيرة.
void foo(int... nums, String label)لا يُترجم. - غموض التحميل الزائد. إذا حمّلت تابعًا وكان أحد الإصدارات يستخدم varargs، فقد لا يعرف المُترجم أي إصدار يستدعي. احرص على أن تكون التوابع المتحمّلة لا لبس فيها.
T... items يولّد تحذير مُترجم حول "تلوث الكومة" (heap pollution). تعرّف الآن أن هذا التحذير موجود؛ ويمكن إسكاته بـ @SafeVarargs على التوابع النهائية أو الثابتة. ستتعلم عن الأنواع العامة لاحقًا في المقرر.
الخلاصة
تتيح varargs (بصياغة type... name) كتابة تابع واحد يقبل أي عدد من الوسائط التي تنتمي إلى النوع ذاته. داخل التابع، يُعامَل المعامل كمصفوفة عادية. يجب أن يظهر معامل varargs دائمًا في آخر قائمة المعاملات. استخدم varargs حين يكون عدد المدخلات متغيرًا بالفعل، لكن آثر المعاملات العادية حين يكون العدد ثابتًا — ذلك يجعل الواجهة البرمجية أوضح ويتجنب الاستخدام الخاطئ غير المقصود.