Java 8 Collectors toMap
1. הקדמה
במדריך מהיר זה נדבר על ה- למפות() שיטת ה- אספנים מעמד. נשתמש בזה לאיסוף זרםs לתוך א מַפָּה למשל.
עבור כל הדוגמאות המכוסות כאן, נשתמש ברשימת ספרים כנקודת מוצא ונהפוך אותה לשונה מַפָּה יישומים.
2. רשימה ל מַפָּה
נתחיל מהמקרה הפשוט ביותר, על ידי שינוי א רשימה לתוך מַפָּה.
שֶׁלָנוּ סֵפֶר מחלקה מוגדרת כ:
כיתת ספר {שם מחרוזת פרטי; פרסום אינטימי פרטי שנה; מחרוזת פרטית isbn; // גטרים וקובעים}
ואנחנו ניצור רשימת ספרים שתאמת את הקוד שלנו:
רשימת ספרים רשימה = ArrayList חדש (); bookList.add (ספר חדש ("אחוות הטבעת", 1954, "0395489318")); bookList.add (ספר חדש ("שני המגדלים", 1954, "0345339711")); bookList.add (ספר חדש ("שובו של המלך", 1955, "0618129111"));
עבור תרחיש זה נשתמש בעומס יתר הבא של ה- למפות() שיטה:
אַסְפָן toMap (Function keyMapper, Function valueMapper)
עם למפות, אנו יכולים לציין אסטרטגיות כיצד להשיג את המפתח והערך עבור המפה:
רשימת מפות ציבוריתToMap (רשימת ספרים) {return books.stream (). collect (Collectors.toMap (ספר :: getIsbn, ספר :: getName)); }
ונוכל לאמת שזה עובד עם:
@ מבחן ציבורי בטל כאשר ConvertFromListToMap () {assertTrue (convertToMap.listToMap (booklist) .size () == 3); }
3. פתרון עימותים מרכזיים
הדוגמה שלעיל עבדה היטב, אך מה יקרה אם יש מפתח כפול?
בואו נדמיין שקידמנו את שלנו מַפָּה על ידי כל אחד סֵפֶרשנת יציאה:
רשימת מפות ציבוריתToMapWithDupKeyError (רשימת ספרים) {להחזיר books.stream (). collect (Collectors.toMap (ספר :: getReleaseYear, Function.identity ())); }
בהתחשב ברשימת הספרים הקודמת שלנו, נראה IllegalStateException:
@Test (צפוי = IllegalStateException.class) בטל בציבור כאשר MapHasDuplicateKey_without_merge_function_then_runtime_exception () {convertToMap.listToMapWithDupKeyError (booklist); }
כדי לפתור את זה, עלינו להשתמש בשיטה אחרת עם פרמטר נוסף, ה- mergeFunction:
אספן toMap (פונקציית keyMapper, value valueMapper, BinaryOperator mergeFunction)
בואו ונציג פונקציית מיזוג המציינת שבמקרה של התנגשות, אנו שומרים על הערך הקיים:
רשימת מפות ציבוריתToMapWithDupKey (רשימת ספרים) {להחזיר books.stream (). אסוף (Collectors.toMap (ספר :: getReleaseYear, Function.identity (), (קיים, החלפה) -> קיים)); }
או, במילים אחרות, אנו מקבלים התנהגות של זכייה ראשונה:
@Test הציבור בטל כאשר MapHasDuplicateKeyThenMergeFunctionHandlesCollision () {Map booksByYear = convertToMap.listToMapWithDupKey (booklist); assertEquals (2, booksByYear.size ()); assertEquals ("0395489318", booksByYear.get (1954) .getIsbn ()); }
4. סוגי מפות אחרים
כברירת מחדל, א למפות() השיטה תחזיר א מפת גיבוב.
אך האם אנו יכולים לחזור אחרת מַפָּה יישומים? התשובה היא כן:
אספן toMap (פונקציית keyMapper, value valueMapper, BinaryOperator mergeFunction, ספק ספקים)
איפה ה mapSupply היא פונקציה המחזירה חדש, ריק מַפָּה עם התוצאות.
4.1. רשימה ל ConcurrentMap
בוא ניקח את אותה דוגמה כמו לעיל ונוסיף a mapSupply פונקציה להחזרת א ConcurrentHashMap:
רשימת מפות ציבוריתToConcurrentMap (רשימת ספרים) {return books.stream (). collect (Collectors.toMap (Book :: getReleaseYear, Function.identity (), (o1, o2) -> o1, ConcurrentHashMap :: new)); }
נמשיך ונבדוק את הקוד שלנו:
@ מבחן ציבורי בטל כאשרCreateConcurrentHashMap () {assertTrue (convertToMap.listToConcurrentMap (bookList) מופע של ConcurrentHashMap); }
לבסוף, בואו נראה כיצד להחזיר מפה ממוינת. לשם כך נשתמש ב- TreeMap כ mapSupply פָּרָמֶטֶר.
בגלל TreeMap ממוין לפי הסדר הטבעי של המפתחות שלו כברירת מחדל, אנחנו לא צריכים למיין את המפורש ספרים בְּעָצמֵנוּ:
רשימת TreeMap ציבוריתToSortedMap (ספרים ברשימה) {return books.stream () .collect (Collectors.toMap (Book :: getName, Function.identity (), (o1, o2) -> o1, TreeMap :: new)); }
אז במקרה שלנו, החזר TreeMap ימוין לפי סדר האלף-בית לפי שם הספר:
@ מבחן ציבורי בטל כאשר MapisSorted () {assertTrue (convertToMap.listToSortedMap (bookList) .firstKey (). שווה ("אחוות הטבעת")); }
במאמר זה בדקנו את למפות() שיטת ה- אספנים מעמד. זה מאפשר לנו ליצור חדש מַפָּה מ זרם. למדנו גם כיצד לפתור קונפליקטים מרכזיים וליצור יישומי מפות שונים.
כמו תמיד הקוד ניתן להשיג ב- GitHub.