به یاد بیاورید که نقشه دادههای ساختاری است که از مجموعهای از جفتهای کلید-مقدار تشکیل شده است و هر کلید فقط یک بار در یک نقشه واحد قابل استفاده است. این مبحث 9 سوال اساسی در مورد استفاده از Map در جاوا و کلاس های پیاده سازی شده آن را پوشش می دهد. برای سادگی، از تعمیم در مثال ها استفاده می کنم . بنابراین، بدون تعیین مشخص کننده Map، به سادگی Map را می نویسم. اما شما می توانید فرض کنید که هر دو مقدار K و V قابل مقایسه هستند، به این معنی که K ، Comparable را گسترش می دهد و V نیز قابل مقایسه است .
0. تبدیل نقشه به فهرست
در جاوا، رابط نقشه سه نوع مجموعه ارائه می دهد: مجموعه کلید، مجموعه ارزش و مجموعه کلید-مقدار. همه آنها را می توان با استفاده از سازنده یا متد به لیست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. تمام مقادیر موجود در Map را حلقه بزنید
قدم زدن در میان هر جفت کلید-مقدار ابتدایی ترین و اساسی ترین روش برای قدم زدن در نقشه است. در جاوا، هر جفت در یک فیلد 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. سفارش نقشه توسط کلید
سازماندهی نقشه ها بر اساس کلیدها یکی دیگر از روش های رایج است. اولین راه این است که 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 را داشته باشند یا توسط مقایسه کننده پذیرفته شوند. یکی از کلاس های پیاده سازی شده TreeMapSortedMap
است . سازنده آن مقایسه کننده را می پذیرد. کد زیر نحوه تبدیل یک نمونه معمولی به یک سفارش داده شده را نشان می دهد. 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");
. بنابراین تغییر ناپذیری واقعی نیست. برای ایجاد یک نقشه تغییرناپذیر با استفاده از یک اولیه ساز استاتیک، به یک کلاس فوق ناشناس نیاز داریم که در آخرین مرحله اولیه سازی، آن را به نقشه تغییرناپذیر اضافه می کنیم. لطفا به قسمت دوم کد نگاه کنید. هنگامی که اگر اجرا کنید UnsupportedOperationExceptionTest.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
سه پیاده سازی اصلی رابط نقشه در جاوا وجود دارد : HashMap ، TreeMap و Hashtable . تفاوت های اصلی به شرح زیر است:- ترتیب عبور . HashMap و HashTable ترتیب نقشه را تضمین نمی کنند. به ویژه، آنها تضمین نمی کنند که سفارش در طول زمان ثابت بماند. اما
TreeMap
تمام مقادیر را به "ترتیب طبیعی" کلیدها یا توسط یک مقایسه کننده ترتیب می دهد. - جفت های کلید-مقدار معتبر.
HashMap
به شما امکان می دهد یک کلید تهی و یک مقدار تهی داشته باشید.HashTable
اجازه کلید تهی یا مقدار تهی را نمی دهد. اگرTreeMap
از ترتیب طبیعی استفاده شود یا مقایسه کننده اجازه یک کلید تهی را ندهد، یک استثنا ایجاد می شود. - هماهنگ سازی . فقط
HashTable
هماهنگ شده، بقیه نیستند. اما، "اگر نیازی به پیاده سازی ایمن برای رشته نیست، توصیه می شود بهHashMap
جای آن از " استفاده کنیدHashTable
.
. | HashMap | HashTable | TreeMap
-------------------------------------------------------
Упорядочивание |нет |нет | да
null в ключ-meaning | да-да | нет-нет | нет-да
синхронизировано | нет | да | нет
производительность | O(1) | O(1) | O(log n)
воплощение | корзины | корзины | красно-чёрное дерево
درباره رابطه HashMap در مقابل رابطه بیشتر بخوانید . نقشه درختی در مقابل Hashtable در مقابل LinkedHashMap .
6. نقشه با جستجوی معکوس / مشاهده
گاهی اوقات، ما به مجموعهای از جفتهای کلید-کلید نیاز داریم، به این معنی که مقادیر به اندازه کلیدها منحصر به فرد هستند (الگوی یک به یک). این سازگاری به شما امکان می دهد یک "نما/جستجوی معکوس" روی نقشه ایجاد کنید. یعنی می توانیم یک کلید را با مقدار آن پیدا کنیم. این ساختار داده نقشه دو طرفه نامیده می شود که متأسفانه توسط JDK پشتیبانی نمی شود. هر دو Apache Common Collections و Guava به ترتیب پیاده سازی نقشه دو طرفه به نام BidiMap و BiMap را ارائه می دهند. هر دو محدودیتی را معرفی می کنند که نگاشت 1:1 بین کلیدها و مقادیر را اعمال می کند.7. کپی کم عمق نقشه
تقریباً همه، اگر نه همه، نقشههای جاوا حاوی یک سازنده کپی برای نقشه دیگر هستند. اما روند کپی هماهنگ نیست. به این معنی که وقتی یک رشته نقشه را کپی می کند، رشته دیگر می تواند ساختار آن را تغییر دهد. برای جلوگیری از همگام سازی ناگهانی کپی، در چنین مواردی باید از یکی از آنها استفاده شودCollections.synchronizedMap()
.
Map copiedMap = Collections.synchronizedMap(Map);
یکی دیگر از راه های جالب برای کپی کردن سطحی، استفاده از clone()
. اما حتی توسط خالق چارچوب مجموعه های جاوا، Joshua Bloch، توصیه نمی شود. در بحث « سازنده کپی در مقابل شبیهسازی »، او این موضع را اتخاذ میکند: نقل قول: «من اغلب یک روش کلون عمومی را در کلاسهای بتن ارائه میدهم، زیرا مردم انتظار دارند که در آنجا حضور داشته باشند... شرم آور است که کلونینگ شکسته شده است، اما اتفاق افتاد... شبیه سازی نقطه ضعفی است و به نظر من باید در مورد محدودیت های آن به مردم هشدار داد." clone()
به همین دلیل، من حتی نحوه استفاده از روش کپی نقشه را به شما نشان نمی دهم
8. یک نقشه خالی ایجاد کنید
اگرMap
تغییر ناپذیر است، استفاده کنید:
Map = Collections.emptyMap();
یا از هر تجسم دیگری استفاده کنید. مثلا:
Map = new HashMap();
پایان
GO TO FULL VERSION