עבודה עם מפות באמצעות זרמים

1. הקדמה

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

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

2. רעיון בסיסי

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

מפות בעלי מבנה שונה, עם מיפוי ממפתחות לערכים, ללא רצף. זה לא אומר שאנחנו לא יכולים להמיר a מַפָּה מבנה לרצפים שונים המאפשרים לנו לעבוד בצורה טבעית עם ה- API של Stream.

בואו נראה דרכים להשיג שונות אוסףs מ- a מַפָּה, אשר נוכל לאחר מכן להסתובב ב- a זרם:

מפה someMap = HashMap חדש ();

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

מַעֲרֶכֶת ערכים = someMap.entrySet ();

אנו יכולים גם להשיג את ערכת המפתחות המשויכת ל- מַפָּה:

הגדר keySet = someMap.keySet ();

או שנוכל לעבוד ישירות עם מכלול הערכים:

ערכי אוסף = someMap.values ​​();

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

זרם entriesStream = entries.stream (); זרם ערכים זרם = ערכים.זרם (); Stream keysStream = keySet.stream ();

3. קבלת א מַפָּהמפתחות באמצעות זרםס

3.1. נתוני קלט

נניח שיש לנו a מַפָּה:

ספרי מפה = HashMap חדש (); books.put ("978-0201633610", "דפוסי עיצוב: אלמנטים של תוכנה מונחית עצמים לשימוש חוזר"); books.put ("978-1617291999", "Java 8 בפעולה: Lambdas, זרמים ותכנות בסגנון פונקציונלי"); books.put ("978-0134685991", "Java אפקטיבי");

אנו מעוניינים למצוא את ה- ISBN של הספר עם הכותרת "Java אפקטיבי".

3.2. אחזור התאמה

מכיוון ששם הספר לא יכול היה להתקיים אצלנו מַפָּה, אנו רוצים להיות מסוגלים לציין שאין לזה ISBN משויך. אנחנו יכולים להשתמש ב- אופציונאלי לבטא זאת:

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

אופציונלי optionalIsbn = books.entrySet (). Stream () .filter (e -> "Java אפקטיבי". Equals (e.getValue ())). מפה (Map.Entry :: getKey) .findFirst (); assertEquals ("978-0134685991", optionalIsbn.get ());

בואו ננתח את הקוד. ראשון, אנו משיגים את entrySet מ ה מַפָּה, כפי שראינו קודם.

אנו רוצים לשקול רק את הערכים עם "Java אפקטיבי" ככותרת, כך שפעולת הביניים הראשונה תהיה מסנן.

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

מכיוון שאנחנו רוצים רק תוצאה אחת, אנחנו יכולים ליישם את findFirst () פעולת המסוף, שתספק את הערך ההתחלתי ב- זרם כמו אופציונאלי לְהִתְנַגֵד.

בוא נראה מקרה שבו כותרת לא קיימת:

אופציונלי OptionIsbn = books.entrySet (). Stream () .filter (e -> "כותרת לא קיימת". Equals (e.getValue ())). מפה (Map.Entry :: getKey) .findFirst (); assertEquals (false, optionalIsbn.isPresent ());

3.3. אחזור תוצאות מרובות

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

כדי להחזיר מספר תוצאות, בואו נוסיף את הספר הבא לספר שלנו מַפָּה:

books.put ("978-0321356680", "Java אפקטיבי: המהדורה השנייה"); 

אז עכשיו, אם נחפש את כל ספרים שמתחילים עם "Java יעיל", נקבל יותר מתוצאה אחת בחזרה:

רשימת isbnCodes = books.entrySet (). Stream () .filter (e -> e.getValue (). StartsWith ("Java יעיל")). Map (Map.Entry :: getKey) .collect (Collectors.toList () ); assertTrue (isbnCodes.contains ("978-0321356680"); assertTrue (isbnCodes.contains ("978-0134685991"));

מה שעשינו במקרה זה הוא להחליף את מצב המסנן כדי לוודא אם הערך ב- מַפָּה מתחיל עם "Java יעיל" במקום להשוות עבור חוּט שוויון.

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

4. קבלת מַפָּה'S ערכים באמצעות זרםס

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

בואו נשתמש במקור מַפָּה. אנו רוצים למצוא כותרות שעבורן ה- ISBN שלהם מתחיל עם "978-0".

רשימת כותרות = books.entrySet (). Stream () .filter (e -> e.getKey (). StartsWith ("978-0")) .map (Map.Entry :: getValue) .collect (Collectors.toList ( )); assertEquals (2, titels.size ()); assertTrue (titels.contains ("דפוסי עיצוב: אלמנטים של תוכנה מונחית עצמים לשימוש חוזר")); assertTrue (titels.contains ("Java יעיל"));

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

וכמו בעבר, אם היינו רוצים להחזיר רק את המשחק הראשון, היינו יכולים אחרי ה- מַפָּה בשיטה קוראים findFirst () שיטה במקום לאסוף את כל התוצאות ב- a רשימה.

5. מסקנה

הראינו כיצד לעבד א מַפָּה בצורה פונקציונלית.

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

וכמובן, את כל הדוגמאות ניתן למצוא בפרויקט GitHub.