Varargs בג'אווה

1. הקדמה

Varargs הוצגו בשנת ג'אווה 5 ולספק יד קצרה לשיטות התומכות במספר שרירותי של פרמטרים מסוג אחד.

במאמר זה נראה כיצד נוכל להשתמש בתכונת ליבה זו של Java.

2. לפני Varargs

לפני Java 5, בכל פעם שרצינו להעביר מספר שרירותי של ארגומנטים, היינו צריכים להעביר את כל הארגומנטים במערך או ליישם שיטות N (אחת לכל פרמטר נוסף):

פורמט מחרוזת ציבורי () {...} פורמט מחרוזת ציבורי (ערך מחרוזת) {...} פורמט מחרוזת ציבורי (מחרוזת val1, מחרוזת val2) {...}

3. שימוש ב Varargs

Varargs עזור לנו להימנע מכתיבת קוד boilerplate על ידי הצגת התחביר החדש שיכול להתמודד עם מספר פרמטרים שרירותי באופן אוטומטי - באמצעות מערך מתחת למכסה המנוע.

אנו יכולים להגדיר אותם באמצעות הצהרת סוג סטנדרטית, ואחריה אליפסה:

פורמט מחרוזת ציבוריWithVarArgs (מחרוזת ... ערכים) {// ...}

ועכשיו, אנו יכולים לקרוא לשיטה שלנו עם מספר שרירותי של טיעונים, כמו:

formatWithVarArgs (); formatWithVarArgs ("a", "b", "c", "d");

כפי שהוזכר מוקדם יותר, varargs הם מערכים ולכן עלינו לעבוד איתם בדיוק כמו שהיינו עובדים עם מערך רגיל.

4. כללים

Varargs פשוטים לשימוש. אבל יש כמה כללים שעלינו לזכור:

  • לכל שיטה יכולה להיות רק אחת varargs פָּרָמֶטֶר
  • ה varargs הארגומנט חייב להיות הפרמטר האחרון

5. זיהום ערימה

באמצעות varargs יכול להוביל לזה שמכונה זיהום ערימה. כדי להבין טוב יותר את זיהום הערימה, שקול זאת varargs שיטה:

מחרוזת סטטית firstOfFirst (רשימה ... מחרוזות) {רשימה ints = Collections.singletonList (42); אובייקט [] אובייקטים = מיתרים; אובייקטים [0] = ints; // מחרוזות החזרת זיהום ערימה [0] .get (0); // ClassCastException}

אם נקרא בשיטה מוזרה זו במבחן:

מחרוזת אחת = firstOfFirst (Arrays.asList ("אחד", "שניים"), Collections.emptyList ()); assertEquals ("אחד", אחד);

היינו מקבלים ClassCastException אף על פי שלא השתמשנו כאן בשירותים מפורשים מסוג זה:

java.lang.ClassCastException: לא ניתן להעביר את java.lang.Integer למחלקה java.lang.String

5.1. שימוש בטוח

בכל פעם שאנחנו משתמשים varargs, מהדר Java יוצר מערך שיחזיק את הפרמטרים הנתונים. במקרה זה, המהדר יוצר מערך עם רכיבים מהסוג הגנרי להחזקת הטיעונים.

כשאנחנו משתמשים varargs עם סוגים כלליים, מכיוון שקיים סיכון פוטנציאלי לחריג זמן רציני קטלני, מהדר Java מזהיר אותנו מפני אפשרות לא בטוחה varargs נוֹהָג:

אזהרה: [varargs] זיהום ערימה אפשרי מ- vararg מסוג T פרמטר

ה varargs השימוש בטוח אם ורק אם:

  • אנו לא מאחסנים דבר במערך שנוצר במרומז. בדוגמה זו אכן אחסנו א רשימה במערך ההוא
  • אנו לא נותנים להתייחסות למערך שנוצר לחמוק מהשיטה (על כך בהמשך)

אם אנו בטוחים שהשיטה עצמה משתמשת בבטחה ב- varargs, נוכל להשתמש בה @ SafeVarargs כדי לדכא את האזהרה.

במילים פשוטות, ה varargs השימוש בטוח אם אנו משתמשים בהם כדי להעביר מספר משתנה של ארגומנטים מהמתקשר לשיטה ותו לא!

5.2. בורח Varargs התייחסות

בואו ניקח בחשבון שימוש אחר לא בטוח של varargs:

סטטי T [] toArray (T ... טיעונים) {טיעונים להחזיר; }

בהתחלה, נראה כי ה- toArray השיטה אינה מזיקה לחלוטין. עם זאת, מכיוון שהוא נתן למערך ה- varargs לברוח למתקשר, הוא מפר את הכלל השני של כספת varargs.

כדי לראות כיצד שיטה זו עלולה להיות מסוכנת, בואו נשתמש בה בשיטה אחרת:

סטטי T [] returnAsIs (T a, T b) {חזרה ל- Array (a, b); }

ואז אם נקרא לשיטה זו:

מחרוזת [] args = returnAsIs ("אחד", "שניים");

היינו מקבלים שוב ClassCastException. הנה מה שקורה כשאנחנו קוראים returnAsIs שיטה:

  • לעבור א ו ב אל ה toArray שיטה, Java צריך ליצור מערך
  • מאז לְהִתְנַגֵד[] יכול להכיל פריטים מכל סוג שהוא, המהדר יוצר פריטים
  • ה toArray השיטה מחזירה את הנתון לְהִתְנַגֵד[] למתקשר
  • מכיוון שאתר השיחות מצפה א חוּט[], המהדר מנסה ללהק את לְהִתְנַגֵד[] למצופה חוּט[]ומכאן ClassCastException

לדיון מפורט יותר על זיהום ערימה, מומלץ לקרוא את פריט 32 של Java Effective מאת ג'ושוע בלוך.

6. מסקנה

Varargs יכול לגרום להרבה תנור חימום להיעלם בג'אווה.

ובזכות המרומז שלהם תיבה אוטומטית אל ומ מַעֲרָך, הם ממלאים תפקיד בהגנה עתידית על הקוד שלנו.

כמו תמיד, כל דוגמאות הקוד ממאמר זה יכולות להיות זמינות במאגר GitHub שלנו.