ArrayList<String> إلى String[]: لا تدع نفسك تُخدع
\n\nمرحبًا، يا صديقي! إذا كنت تقرأ هذا، فهذا يعني أنك واجهت بالفعل المهمة الكلاسيكية - تحتاج إلى تحويل ArrayList<String> إلى مصفوفة عادية String[]. قد يبدو الأمر بسيطًا؟ تأخذ طريقة toArray()، تستدعيها - وتنتهي. لكن الأمر ليس بهذه السهولة! Java لغة ماكرة، وحتى هذه العملية البسيطة يمكن أن تتحول إلى صداع إذا كنت لا تعرف المخاطر الخفية.
على Stack Overflow، حصد هذا السؤال آلاف المشاهدات، وهذا ليس بدون سبب. لقد جمعنا أفضل 5 أخطاء يرتكبها حتى المطورون ذوو الخبرة، وسنوضح لك كيفية تجنبها. هيا بنا!
\n\nلماذا لا يعمل list.toArray() ببساطة؟
\n\nدعنا نبدأ مباشرة. لديك قائمة:
\n\nArrayList<String> list = new ArrayList<>();\nlist.add("Java");\nlist.add("Python");\nlist.add("C++");\n\nتريد الحصول على مصفوفة من السلاسل النصية. أول فكرة تتبادر إلى الذهن هي استدعاء list.toArray(). انظر ماذا سيحدث:
Object[] objectArray = list.toArray(); // يعمل، لكنه يُرجع Object[]\n// String[] stringArray = list.toArray(); // خطأ في الترجمة!\n\nالخطأ رقم 1: نسيان تحويل الأنواع. الطريقة toArray() بدون وسائط تُرجع Object[] وليس String[]. لن يسمح لك المترجم ببساطة بتعيين Object[] لمتغير من النوع String[]. تحتاج إلى تحويل صريح:
String[] stringArray = (String[]) list.toArray(); // ClassCastException في وقت التشغيل!\n\nهنا يبدأ الجزء المثير للاهتمام. الخطأ الثاني هو الاعتقاد بأن تحويل الأنواع سينقذ الموقف. ستحصل على ClassCastException، لأنه داخل toArray() يتم إنشاء مصفوفة من النوع Object[] وليس String[]. التحويل لا يغير نوع الكائن - إنه فقط يخبر المترجم: "ثق بي، هذا سلسلة نصية". لكن Java في وقت التشغيل تتحقق وتلقي استثناءً.
الطريقة الصحيحة: toArray(new String[0])
\n\nالطريقة الأكثر شيوعًا وصحة هي تمرير مصفوفة فارغة من النوع المطلوب إلى toArray():
String[] stringArray = list.toArray(new String[0]);\n\nلماذا يعمل هذا؟ لأن الطريقة toArray(T[] a) هي طريقة عامة (generic). تقبل مصفوفة من النوع T وتُعيد مصفوفة من نفس النوع. إذا كانت المصفوفة الممررة غير كبيرة بما يكفي، تقوم الطريقة بإنشاء مصفوفة جديدة من النوع الصحيح باستخدام الانعكاس (reflection). إذا كان الحجم مناسبًا - تملؤها.
الخطأ رقم 3: تمرير مصفوفة بحجم غير صحيح. بعض المبتدئين يكتبون:
\n\nString[] stringArray = list.toArray(new String[list.size()]);\n\nهذا يعمل أيضًا، لكن دعنا نفهم أيهما أفضل. عندما نمرر مصفوفة بحجم list.size()، تقوم الطريقة بملئها وإعادتها. إذا مررنا new String[0] - يتم إنشاء مصفوفة جديدة. قد يبدو، لماذا نضيع الوقت في إنشاء مصفوفة جديدة؟ في الواقع، JVM يحسن إنشاء المصفوفة الفارغة، وفي معظم الحالات يعمل new String[0] بشكل أسرع من new String[list.size()]. لماذا؟ لأنه في الحالة الثانية، يتم إنشاء المصفوفة، ثم تملأ بقيم null، ثم تُعاد كتابتها. عمل إضافي.
غالبًا ما تعمل إصدارات JVM الحديثة (Java 8+) على تحسين new String[0] إلى ثابت، مما يجعله أسرع. لكن إذا كنت تعمل مع Java 6 أو 7 - قد يكون الفرق ملحوظًا. على أي حال، أفضل ممارسة هي استخدام new String[0]، إذا لم تكن هناك حاجة لأداء فائق السرعة. لأجزاء الكود الحساسة للسرعة - اختبر كلا الخيارين.
المخاطر الخفية: التزامن وتعدد الخيوط
\n\nالخطأ رقم 4: التحويل في بيئة متعددة الخيوط بدون مزامنة. تخيل: لديك ArrayL