זכור כי מפה היא נתונים מובנים המורכבים מקבוצה של צמדי מפתח-ערך, וניתן להשתמש בכל מפתח רק פעם אחת במפה אחת. נושא זה מכסה 9 שאלות בסיסיות על שימוש במפה ב-Java ובמחלקות המיושמות שלה. למען הפשטות, אשתמש בהכללות בדוגמאות . לכן, אני אכתוב פשוט Map, מבלי לציין את מפרט המפה. אבל אתה יכול להניח ששני הערכים של K ו- V ברי השוואה, כלומר K מרחיב Comparable ו- V מרחיב גם Comparable .
0. המרת מפה לרשימה
ב-Java, ממשק המפה מציע שלושה סוגים של אוספים: ערכת מפתחות, ערכת ערכים וערכת מפתח-ערך. ניתן להפוך את כולם לרשימה באמצעות הבנאי או השיטהaddAll()
. קטע הקוד הבא מדגים כיצד ליצור ArrayList ממפה.
// list of keys
List keyList = new ArrayList(Map.keySet());
//list of values
List valueList = new ArrayList(Map.valueSet());
//list key-value
List entryList = new ArrayList(Map.entrySet());
1. עברו בלולאה בין כל הערכים במפה
מעבר על כל זוג מפתח-ערך הוא ההליך הבסיסי והבסיסי ביותר להליכה במפה. ב-Java, כל זוג מאוחסן בשדה Map בשם Map.Entry .Map.entrySet()
מחזירה קבוצה של ערכי מפתח, כך שהדרך היעילה ביותר לחזור על כל הערכים של מפה תהיה:
for(Entry entry: Map.entrySet()) {
//get the key
K key = entry.getKey();
//get value
V value = entry.getValue();
}
אנחנו יכולים גם להשתמש ב- Iterator
, במיוחד בגרסאות צעירות מ-JDK 1.5
Iterator itr = Map.entrySet().iterator();
while(itr.hasNext()) {
Entry entry = itr.next();
//get the key
K key = entry.getKey();
//get value
V value = entry.getValue();
}
2. הזמנת מפה לפי Keys
ארגון מפות לפי מקשים הוא הליך נפוץ נוסף. הדרך הראשונה היא להוסיף את Map.Entry לרשימה, ולמיין באמצעות משווה שממיין לפי ערכים.List list = new ArrayList(Map.entrySet());
Collections.sort(list, new Comparator() {
@Override
public int compare(Entry e1, Entry e2) {
return e1.getKey().compareTo(e2.getKey());
}
});
דרך נוספת: השתמשו ב- SortedMap , שבנוסף לכך, גם מסדרת את המפתחות שלה לפי הסדר. אבל, כל המפתחות חייבים לכלול Comparable או להיות מקובלים על ידי המשווה. אחת המחלקות המיושמות SortedMap
היא TreeMap . הקונסטרוקטור שלו מקבל משווה. הקוד הבא מראה כיצד להפוך אחד רגיל Map
למסודר.
SortedMap sortedMap = new TreeMap(new Comparator() {
@Override
public int compare(K k1, K k2) {
return k1.compareTo(k2);
}
});
sortedMap.putAll(Map);
3. הזמינו מפה לפי ערכים
הוספת מפה לרשימה ולאחר מכן מיון שלה עובד במקרה זה, אבל הפעם אתה צריך להשתמשEntry.getValue()
. הקוד למטה כמעט זהה לקודם.
List list = new ArrayList(Map.entrySet());
Collections.sort(list, new Comparator() {
@Override
public int compare(Entry e1, Entry e2) {
return e1.getValue().compareTo(e2.getValue());
}
});
אנחנו עדיין יכולים להשתמש בו SortedMap
במקרה זה, אבל רק אם הערכים הם ייחודיים. במקרה זה, תוכל להפוך את צמד המפתח-ערך לערך-מפתח. לפתרון זה יש מגבלות חמורות ואינו מומלץ על ידי.
4. אתחול מפה סטטית/בלתי ניתנת לשינוי
כאשר אתה רוצה שמפה תישאר בלתי ניתנת לשינוי, דרך טובה היא להעתיק אותה למפה בלתי ניתנת לשינוי. טכניקת תכנות הגנתי זו תעזור לך ליצור מפה שהיא לא רק בטוחה לשימוש, אלא גם בטוחה לשרשור. כדי לאתחל מפה סטטית/בלתי ניתנת לשינוי, אנו יכולים להשתמש באתחולstatic
(ראה להלן). הבעיה עם הקוד הזה היא שלמרות שהמפה הוכרזה כ- static final
, אנחנו עדיין יכולים לעבוד איתו לאחר האתחול, למשל Test.Map.put(3,"three");
. אז זה לא חוסר שינוי אמיתי. כדי ליצור מפה בלתי ניתנת לשינוי באמצעות אתחול סטטי, אנו זקוקים למחלקה סופר אנונימית, אותה נוסיף למפה הניתנת לשינוי בשלב האתחול האחרון. נא להסתכל על החלק השני של הקוד. כאשר UnsupportedOperationException ייזרק אם תפעיל את Test.Map.put(3,"three");
.
public class Test {
private static final Map Map;
static {
Map = new HashMap();
Map.put(1, "one");
Map.put(2, "two");
}
}
public class Test {
private static final Map Map;
static {
Map aMap = new HashMap();
aMap.put(1, "one");
aMap.put(2, "two");
Map = Collections.unmodifiableMap(aMap);
}
}
ספריית Guava תומכת גם בדרכים שונות לאתחול אוספים סטטיים ובלתי ניתנים לשינוי. למידע נוסף על היתרונות של כלי השירות לאוספים בלתי ניתנים לשינוי של Guava, עיין בסעיף אוספים בלתי ניתנים לשינוי במדריך ה-Guava .
5. ההבדל בין HashMap, TreeMap ו-Hashtable
ישנם שלושה יישומים עיקריים של ממשק Map ב-Java: HashMap , TreeMap ו- Hashtable . ההבדלים העיקריים הם כדלקמן:- סדר המעבר . HashMap ו- HashTable אינם מבטיחים את הזמנת המפה; במיוחד, הם לא מבטיחים שההזמנה תישאר זהה לאורך זמן. אבל
TreeMap
זה יסדר את כל הערכים ב"סדר הטבעי" של המפתחות או לפי משווה. - צמדי מפתח-ערך חוקיים.
HashMap
מאפשר לך לקבל מפתח null וערך null.HashTable
אינו מאפשר מפתח null או ערך null. אםTreeMap
נעשה שימוש בסדר טבעי או שהמשווה אינו מאפשר מפתח null, ייגרם חריג. - סנכרון . רק
HashTable
מסונכרן, השאר לא. אבל, "אם אין צורך ביישום בטוח בשרשור, מומלץ להשתמש ב "HashMap
במקום זאתHashTable
.
. | HashMap | HashTable | TreeMap
-------------------------------------------------------
Упорядочивание |нет |нет | да
null в ключ-meaning | да-да | нет-нет | нет-да
синхронизировано | нет | да | нет
производительность | O(1) | O(1) | O(log n)
воплощение | корзины | корзины | красно-чёрное дерево
קרא עוד על מערכת היחסים HashMap לעומת מערכת היחסים. TreeMap לעומת Hashtable לעומת LinkedHashMap .
6. מפה עם חיפוש הפוך/תצוגה
לפעמים, אנחנו צריכים קבוצה של צמדי מפתח-מפתח, מה שאומר שהערכים הם ייחודיים כמו המפתחות (דפוס אחד לאחד). עקביות זו מאפשרת לך ליצור "תצוגה/חיפוש הפוך" במפה. כלומר, אנו יכולים למצוא מפתח לפי ערכו. מבנה נתונים זה נקרא מפה דו-כיוונית , שלמרבה הצער אינה נתמכת על ידי ה-JDK. גם Apache Common Collections וגם Guava מציעים יישומי מפה דו-כיוונית הנקראים BidiMap ו-BiMap, בהתאמה. שניהם מציגים אילוץ האוכף מיפוי 1:1 בין מפתחות וערכים.7. עותק רדוד של המפה
כמעט כל, אם לא כולם, מפות ב-Java מכילות בונה העתקה עבור מפה אחרת. אבל הליך ההעתקה אינו מסונכרן. מה שאומר שכשרשור אחד מעתיק מפה, שרשור אחר יכול לשנות את המבנה שלו. כדי למנוע ביטול סנכרון פתאומי של העתקה, יש להשתמש באחד מהם במקרה כזהCollections.synchronizedMap()
.
Map copiedMap = Collections.synchronizedMap(Map);
דרך מעניינת נוספת להעתיק בצורה רדודה היא להשתמש ב- clone()
. אבל זה לא מומלץ אפילו על ידי היוצר של מסגרת אוספי Java, ג'ושוע בלוך. בוויכוח " Copy Constructor vs. Cloning ", הוא נוקט בעמדה: ציטוט: "לעיתים קרובות אני מספק שיטת שיבוט ציבורי בשיעורי בטון כי אנשים מצפים שהם יהיו שם... חבל שהשיבוט מקולקל, אבל זה קרה... שיבוט הוא נקודת תורפה, ואני חושב שצריך להזהיר אנשים לגבי המגבלות שלו". מסיבה זו, אני אפילו לא מראה לך כיצד להשתמש בשיטה clone()
להעתקת מפה
8. צור מפה ריקה
אםMap
ניתן לשינוי, השתמש ב:
Map = Collections.emptyMap();
לחלופין, השתמש בכל התגלמות אחרת. לדוגמה:
Map = new HashMap();
סוֹף
GO TO FULL VERSION