מדריך ל- Java 8 forEach

1. סקירה כללית

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

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

אם אתה צריך לצחצח כמה מושגים של Java 8, יש לנו אוסף מאמרים שיכולים לעזור לך.

2. יסודות של לכל אחד

בג'אווה, ה- אוסף ממשק יש ניתן לנידון כממשק העל שלו - והחל מג'אווה 8 לממשק זה ממשק API חדש:

בטל עבור כל אחד (פעולות צרכנים)

במילים פשוטות, הג'אוודוק של לכל אחד סטטיסטיקה שזה "מבצע את הפעולה הנתונה עבור כל רכיב של ה- Iterable עד שכל האלמנטים עובדו או שהפעולה מביאה חריג."

וכך, עם לכל אחד, אנו יכולים לחזור על אוסף ולבצע פעולה נתונה בכל אלמנט, כמו כל אחד אחר איטרטור.

למשל, א לולאה גרסת איטרציה והדפסה א אוסף שֶׁל מיתרים:

עבור (שם מחרוזת: שמות) {System.out.println (שם); }

אנו יכולים לכתוב זאת באמצעות לכל אחד כפי ש:

names.forEach (שם -> {System.out.println (שם);});

3. באמצעות לכל אחד שיטה

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

ה צרכן ממשק הוא ממשק פונקציונלי (ממשק בשיטה מופשטת אחת). הוא מקבל קלט ולא מחזיר שום תוצאה.

הנה ההגדרה:

ממשק ציבורי @FunctionalInterface הצרכן {void accept (T t); }

לכן, כל יישום, למשל, צרכן שפשוט מדפיס א חוּט:

הצרכן printConsumer = צרכן חדש () {public void accept (שם מחרוזת) {System.out.println (שם); }; };

ניתן להעביר ל לכל אחד כטיעון:

names.forEach (printConsumer);

אך זו לא הדרך היחידה ליצור פעולה באמצעות צרכן ושימוש לכל אחד ממשק API.

בואו נראה את 3 הדרכים הפופולריות ביותר בהן נשתמש ב- לכל אחד שיטה:

3.1. בעילום שם צרכן יישום

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

הצרכן printConsumer = צרכן חדש () {public void accept (שם מחרוזת) {System.out.println (שם); }}; names.forEach (printConsumer);

זה עובד טוב, אבל אם ננתח בדוגמה שלמעלה נראה שהחלק האמיתי של השימוש הוא הקוד בתוך ה- לְקַבֵּל() שיטה.

אף על פי שביטויי למבדה הם כיום הנורמה והדרך הקלה יותר לעשות זאת, עדיין כדאי לדעת כיצד ליישם את צרכן מִמְשָׁק.

3.2. ביטוי למבדה

היתרון העיקרי של ממשקים פונקציונליים של Java 8 הוא בכך שאנו יכולים להשתמש בביטויי Lambda בכדי ליצור אותם ולהימנע משימוש ביישומי כיתה אנונימיים מגושמים.

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

(טיעון) -> {// גוף}

לכן, שלנו printConsumer מפשט ל:

שם -> System.out.println (שם)

ואנחנו יכולים להעביר את זה ל לכל אחד כפי ש:

names.forEach (שם -> System.out.println (שם));

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

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

3.3. הפניה לשיטה

אנו יכולים להשתמש בתחביר הפניה לשיטה במקום בתחביר Lambda הרגיל שבו קיימת כבר שיטה לביצוע פעולה בכיתה:

names.forEach (System.out :: println);

4. עבודה עם לכל אחד

4.1. מתבוסס על אוסף

כל איטרציה מסוג זה אוסף - רשימה, סט, תור וכו 'יש תחביר זהה לשימוש לכל אחד.

לכן, כפי שכבר ראינו, לחזור על אלמנטים של רשימה:

שמות רשימה = Arrays.asList ("לארי", "סטיב", "ג'יימס"); names.forEach (System.out :: println);

באופן דומה לסט:

הגדר שמות ייחודיים = HashSet חדש (Arrays.asList ("לארי", "סטיב", "ג'יימס")); uniqueNames.forEach (System.out :: println);

או נגיד בשביל a תוֹר שהוא גם א אוסף:

שמות תורים תור = ArrayDeque חדש (Arrays.asList ("לארי", "סטיב", "ג'יימס")); namesQueue.forEach (System.out :: println);

4.2. התבוססות על גבי מפה - שימוש במפות לכל אחד

מפות אינן ניתן לנידון, אבל, הם כן לספק גרסה משלהם של לכל אחד שמקבל א BiConsumer.

א BiConsumer הוצג במקום צרכן ב- Iterable לכל אחד כך שניתן לבצע פעולה גם במפתח וגם בערך של a מַפָּה בּוֹ זְמַנִית.

בואו ניצור מַפָּה בעל כניסות:

Map namesMap = HashMap חדש (); namesMap.put (1, "לארי"); namesMap.put (2, "סטיב"); namesMap.put (3, "ג'יימס");

לאחר מכן, בואו נגרום namesMap באמצעות מפות לכל אחד:

namesMap.forEach ((מפתח, ערך) -> System.out.println (מפתח + "" + ערך));

כפי שניתן לראות כאן, השתמשנו ב- BiConsumer:

(מפתח, ערך) -> System.out.println (מפתח + "" + ערך)

לחזור על הערכים של מַפָּה.

4.3. מתבוסס מעל א מפה - על ידי איטרציה entrySet

אנחנו יכולים גם לחזור על EntrySet של א מַפָּה באמצעות Iterable's לכל אחד.

מאז הערכים של א מַפָּה מאוחסנים ב מַעֲרֶכֶת שקוראים לו EntrySet, אנו יכולים לחזור על כך באמצעות לכל אחד:

namesMap.entrySet (). forEach (entry -> System.out.println (entry.getKey () + "" + entry.getValue ()));

5. Foreach לעומת For-Loop

מנקודת מבט פשוטה, שתי הלולאות מספקות את אותה פונקציונליות - עובר דרך אלמנטים באוסף.

ההבדל העיקרי בין שניהם הוא שהם איטרטורים שונים - המשופרים לולאה הוא איטרטר חיצוני ואילו החדש לכל אחד השיטה היא שיטה פנימית.

5.1. אינטרטור פנימי - לכל אחד

סוג זה של איטרטור מנהל את האיטרציה ברקע ומשאיר למתכנת רק לקודד את מה שנועד לעשות עם מרכיבי האוסף.

האיטרטור במקום, מנהל את האיטרציה ומקפיד לעבד את האלמנטים אחד-אחד.

בואו נראה דוגמה לאיטרציה פנימית:

names.forEach (שם -> System.out.println (שם));

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

5.2. אינטרטור חיצוני - לולאה

איטרטורים חיצוניים מערבבים את מה וה אֵיך יש לעשות את הלולאה.

ספירות, מחטבים ומשופרת לולאה כולם איטרטורים חיצוניים (זכרו את השיטות איטרטור (),הַבָּא() אוֹ hasNext () ? ). בכל האיטרטורים הללו תפקידנו לציין כיצד לבצע איטרציות.

שקול את הלולאה המוכרת הזו:

עבור (שם מחרוזת: שמות) {System.out.println (שם); }

אם כי איננו קוראים במפורש hasNext () אוֹ הַבָּא() תוך כדי איטרציה ברשימה, הקוד הבסיסי שגורם לאיטרציה זו לעבוד משתמש בשיטות אלה. זה מרמז על כך שמורכבות הפעולות הללו מוסתרת בפני המתכנת, אך היא עדיין קיימת.

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

6. סיכום

במאמר זה הראינו כי ה- לכל אחד לולאה נוחה יותר מהרגיל לולאה.

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

לבסוף, כל התמציות המשמשות במאמר זה זמינות במאגר Github שלנו.


$config[zx-auto] not found$config[zx-overlay] not found