โปรดทราบว่าแผนที่เป็นข้อมูลที่มีโครงสร้างประกอบด้วยชุดของคู่คีย์-ค่า และแต่ละคีย์สามารถใช้ได้เพียงครั้งเดียวในแผนที่เดียวเท่านั้น หัวข้อนี้ครอบคลุมคำถามพื้นฐาน 9 ข้อเกี่ยวกับการใช้Mapใน Java และคลาสที่นำไปใช้งาน เพื่อความง่าย ฉันจะใช้ลักษณะทั่วไป ใน ตัวอย่าง ดังนั้นผมจะเขียนแค่ Map โดยไม่ระบุตัวระบุ Map แต่คุณสามารถสรุปได้ว่าทั้งสองค่าของKและVเทียบเคียงได้ ซึ่งหมายความว่าKจะขยายComparableและVก็จะขยายComparableด้วย
0. การแปลงแผนที่เป็นรายการ
ใน Java อินเทอร์เฟซ แผนที่มีคอลเลกชันสามประเภท: ชุดคีย์ ชุดค่า และชุดคีย์-ค่า ทั้งหมดนี้สามารถเปลี่ยนเป็นListaddAll()
ได้โดยใช้ Constructor หรือเมธอด ข้อมูลโค้ดต่อไปนี้สาธิตวิธีการสร้าง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.EntryMap.entrySet()
ส่งคืนชุดคีย์-ค่า ดังนั้นวิธีที่มีประสิทธิภาพที่สุดในการวนซ้ำค่าทั้งหมดของ Map คือ:
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. การเรียงลำดับแผนที่ด้วยคีย์
การจัดระเบียบแผนที่ด้วยปุ่มเป็นอีกขั้นตอนหนึ่งที่ใช้กันทั่วไป วิธีแรกคือการเพิ่ม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
(ดูด้านล่าง) ปัญหาของโค้ดนี้คือแม้จะประกาศ Map เป็น แต่เรา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 How-to
5. ความแตกต่างระหว่าง HashMap, TreeMap และ Hashtable
มีการใช้งานหลักสามประการของ อินเท อ ร์เฟ ซ Mapใน Java: HashMap , TreeMapและHashtable ความแตกต่างหลักมีดังนี้:- ลำดับของทาง . HashMapและ HashTable ไม่รับประกันการเรียงลำดับของแผนที่ โดยเฉพาะอย่างยิ่งพวกเขาไม่รับประกันว่าคำสั่งซื้อจะยังคงเหมือนเดิมเมื่อเวลาผ่านไป แต่
TreeMap
จะเรียงลำดับค่าทั้งหมดใน "ลำดับตามธรรมชาติ" ของคีย์หรือโดยตัวเปรียบเทียบ - คู่คีย์-ค่าที่ถูกต้อง
HashMap
ช่วยให้คุณมีคีย์ Null และค่า NullHashTable
ไม่อนุญาตให้ใช้คีย์ null หรือค่า null หากTreeMap
ใช้ลำดับตามธรรมชาติหรือตัวเปรียบเทียบไม่อนุญาตให้ใช้คีย์ Null ข้อยกเว้นจะถูกส่งออกไป - การซิงโครไนซ์ ซิงโครไนซ์ เท่านั้น
HashTable
ส่วนที่เหลือไม่ได้ แต่ "หากไม่จำเป็นต้องใช้เธรดที่ปลอดภัย ขอแนะนำให้ใช้"HashMap
แทนHashTable
. | HashMap | HashTable | TreeMap
-------------------------------------------------------
Упорядочивание |нет |нет | да
null в ключ-meaning | да-да | нет-нет | нет-да
синхронизировано | нет | да | нет
производительность | O(1) | O(1) | O(log n)
воплощение | корзины | корзины | красно-чёрное дерево
อ่านเพิ่มเติมเกี่ยวกับHashMap กับ ความสัมพันธ์ ทรีแมป กับ แฮชเทเบิลกับ LinkedHashMap _
6. แผนที่พร้อมการค้นหา/ดูแบบย้อนกลับ
บางครั้งเราต้องการชุดคู่คีย์-คีย์ ซึ่งหมายความว่าค่าจะไม่ซ้ำกันเหมือนกับคีย์ (รูปแบบหนึ่งต่อหนึ่ง) ความสอดคล้องนี้ทำให้คุณสามารถสร้าง "มุมมอง/การค้นหาแบบกลับหัว" บนแผนที่ได้ นั่นคือเราสามารถค้นหาคีย์ได้จากค่าของมัน โครงสร้างข้อมูลนี้เรียกว่าแผนที่แบบสองทิศทางซึ่ง JDK ไม่รองรับ ทั้ง Apache Common Collections และ Guava นำเสนอการใช้งานแผนที่แบบสองทิศทางที่เรียกว่า BidiMap และ BiMap ตามลำดับ ทั้งสองมีข้อจำกัดที่บังคับใช้การแมป 1:1 ระหว่างคีย์และค่า7. สำเนาแผนที่แบบตื้น
Maps ใน Java เกือบทั้งหมด (หรือทั้งหมด) มีตัวสร้างการคัดลอกสำหรับแผนที่อื่น แต่ขั้นตอนการคัดลอกไม่ซิงโครไนซ์ ซึ่งหมายความว่าเมื่อเธรดหนึ่งคัดลอกแผนที่ เธรดอื่นสามารถเปลี่ยนโครงสร้างของมันได้ เพื่อป้องกันการยกเลิกการซิงโครไนซ์การคัดลอกอย่างกะทันหัน ควรใช้หนึ่งในนั้นในกรณีเช่นCollections.synchronizedMap()
นี้
Map copiedMap = Collections.synchronizedMap(Map);
อีกวิธีที่น่าสนใจในการคัดลอกแบบตื้นคือการใช้clone()
. แต่ไม่แนะนำแม้แต่ผู้สร้างเฟรมเวิร์กคอลเลกชัน Java Joshua Bloch ในการอภิปราย " Copy Constructor vs. Cloning " เขาเข้ารับตำแหน่ง: ข้อความอ้างอิง: "ฉันมักจะรวมวิธีการโคลนสาธารณะไว้ในชั้นเรียนที่เป็นรูปธรรมเพราะผู้คนคาดหวังให้พวกเขาอยู่ที่นั่น ... น่าเสียดายที่การโคลนนิ่งใช้งานไม่ได้ แต่ เกิดขึ้น ... การโคลนนิ่งเป็นจุดอ่อนและฉันคิดว่าผู้คนควรได้รับการเตือนเกี่ยวกับข้อจำกัดของมัน" ด้วยเหตุนี้ ฉันจึงไม่แสดงให้คุณเห็นวิธีการclone()
คัดลอกแผนที่ ด้วยซ้ำ
8. สร้างแผนที่เปล่า
หากMap
ไม่เปลี่ยนรูป ให้ใช้:
Map = Collections.emptyMap();
หรือใช้รูปลักษณ์อื่นใด ตัวอย่างเช่น:
Map = new HashMap();
จบ
GO TO FULL VERSION