استفاده از کلیدهای Mutable یک antipattern است و قطعاً باید از آن اجتناب کنید. عوارض احتمالی آن وحشتناک است: ممکن است محتوای نقشهتان غیرقابل بازیابی شود.
ایجاد یک مثال برای نمایش این موضوع بسیار ساده است. کلاس Key زیر فقط یک wrapper قابل تغییر روی یک String است. توجه کنید متدهای equals() و hashCode() بازنویسی شدهاند.
تا اینجا کد درست عمل میکند:
map.get(one) = one
map.get(two) = two
حال اگر کسی کلید شما را تغییر دهد چه اتفاقی میافتد؟ بستگی به نوع تغییر دارد. مثالهای زیر را ببینید.
در حالت زیر، یکی از کلیدهای موجود با مقداری جدید تغییر میکند که با هیچ کلید موجودی مطابقت ندارد:
نتیجه: دیگر نمیتوانید از کلید برای دریافت مقدار استفاده کنید، حتی با همان شیء. و دریافت مقدار از کلیدی که مقدار اصلی را دارد هم شکست میخورد. این جفت کلید-مقدار از دست رفته است.
map.get(one) = null
map.get(two) = two
map.get(new Key(1)) = null
map.get(new Key(2)) = two
map.get(new Key(5)) = null
اگر کلید را با مقداری تغییر دهید که برای کلید دیگر موجود استفاده میشود، نتیجه متفاوت است:
نتیجه: دریافت مقدار متصل به کلید تغییریافته، مقدار متصل به کلید دیگر را برمیگرداند. و مانند مثال قبلی، دیگر نمیتوانید مقدار متصل به کلید تغییریافته را دریافت کنید.
Map: {1=one, 2=two}
map.get(one) = two
map.get(two) = two
map.get(new Key(1)) = null
map.get(new Key(2)) = two
همانطور که میبینید، حتی در یک مثال بسیار ساده، اوضاع میتواند به شکل وحشتناکی خراب شود: کلید اول دیگر نمیتواند به مقدار درست دسترسی داشته باشد و ممکن است در این فرآیند مقادیر از دست بروند.
بهطور خلاصه: اگر واقعاً نمیتوانید از کلیدهای Mutable اجتناب کنید، آنها را تغییر ندهید. اما بهترین انتخاب استفاده از کلیدهای غیرقابل تغییر (Unmodifiable) است.
شاید سوال پیش بیاید چرا در این بخش دربارهی کلاس HashSet صحبت میکنیم؟ حقیقت این است که HashSet در واقع بر پایهی یک HashMap داخلی ساخته شده است. بنابراین این دو کلاس ویژگیهای مشترکی دارند.
کد متد add(element) کلاس HashSet:
private transient HashMap<E,Object> map;
private static final Object PRESENT = new Object();
public boolean add(E e) {
return map.put(e, PRESENT)==null;
}
همانطور که میبینید، یک hashset اشیاء شما را در یک hashmap ذخیره میکند. اشیای شما کلیدهای این hashmap هستند و مقدار فقط یک placeholder است.
نکتهی مهم: اگر اشیایتان را پس از اضافه کردن به یک Set تغییر دهید، ممکن است با باگهای عجیبی در برنامه مواجه شوید که رفعشان دشوار خواهد بود.
بیایید مثال قبلی را با کلاس Key mutable دوباره ببینیم، این بار با اضافه کردن نمونهها به یک Set:
خروجی:
set = [1, 2]
set.contains(one) = false
addedOne = true
set = [3, 2, 3]
key0 = 3
key2 = 3
key0 == key2 ? true
میبینید اولین و آخرین عنصر مجموعه یکسان هستند. تغییر یک شیء پس از اضافه کردنش به یک Set میتواند منجر به وجود همان شیء بیش از یک بار در مجموعه شود. بهسادگی بگوییم: این کار را نکنید!
این محتوا کاملا رایگان توسط تیم کدلپر ترجمه شده و در اختیار شما کاربران عزیز قرار گرفته است، هر گونه کپی برداری برای مقاصد غیر رایگان و بدون ذکر منبع، مورد پیگیری قانونی قرار میگیرد.
ترجمه شده از منبع: https://dev.java/learn/