Witam. Ostatnio zastanawiam się jakie korzyści daje nam niemutowalność klucza w mapie. Wszędzie zaleca się aby klucz w mapie był niemutowalny, aby ustrzec się przed błędami. Napisałem taki prosty programik:
class HashKey {
private int keyPartOne;
private int KeyPartTwo;
public HashKey(int keyPartOne, int keyPartTwo) {
this.keyPartOne = keyPartOne;
KeyPartTwo = keyPartTwo;
}
public int getKeyPartOne() {
return keyPartOne;
}
public void setKeyPartOne(int keyPartOne) {
this.keyPartOne = keyPartOne;
}
public int getKeyPartTwo() {
return KeyPartTwo;
}
public void setKeyPartTwo(int keyPartTwo) {
KeyPartTwo = keyPartTwo;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
HashKey hashKey = (HashKey) o;
if (keyPartOne != hashKey.keyPartOne) return false;
return KeyPartTwo == hashKey.KeyPartTwo;
}
@Override
public int hashCode() {
int result = keyPartOne;
result = 31 * result + KeyPartTwo;
return result;
}
}
public class Main {
public static void main(String[] args) {
HashMap<HashKey, String> firstMap = new HashMap<>();
HashKey firstHashKey = new HashKey(1, 1);
firstMap.put(firstHashKey, "text 1");
HashKey secondHashKey = new HashKey(1, 2);
firstMap.put(secondHashKey, "text 2");
System.out.println(firstMap.get(firstHashKey));
secondHashKey.setKeyPartTwo(1);
System.out.println(firstMap.get(secondHashKey));
HashMap<String, String> secondMap = new HashMap<>();
String firstMapElem = "firstKey";
secondMap.put(firstMapElem, "string 1");
String secondMapElem = "secondKey";
secondMap.put(secondMapElem, "string 2");
System.out.println(secondMap.get(firstMapElem));
secondMapElem = "firstKey";
System.out.println(secondMap.get(secondMapElem));
}
}
Jak widać w pierwszym przypadku korzystam z mutowalnego klucza w mapie, czyli obiektu utworzonego przeze mnie na potrzeby przykładu: HashKey. Tworze sobie dwa obiekty, jeden z parametrami 1,1 i tekstem "text 1" a drugi z 1,2 i tekstem "text 2". Wynik uruchomiania programu daje mi:
text 1
text 1
Ponieważ w międzyczasie przed wypisaniem zmodyfikowałem drugi klucz:
HashKey secondHashKey = new HashKey(1, 2);
W drugim przykładzie robię podobnie z tym, że korzystam z niemutowalnego Stringa i dostaję wyniki:
string 1
string 1
W międzyczasie dokonałem przypisania:
secondHashKey.setKeyPartTwo(1);
I tutaj moje pytanie jaką mamy tutaj faktycznie korzyść z niemutowalności tych obiektów? W obu przypadkach możemy zmodyfikować zmienną, którą użyjemy potem do pobrania wartośći z mapy. Jaką robi to nam różnicę czy zrobimy set na mutowalnym obiekcie:
secondMap.put(firstMapElem, "string 1");
czy przypisanie na niemutowalnym stringu:
secondMapElem = "firstKey";
Swoją drogą podobnie można by zrobić jak ze Stringiem jeśli obiekt HashMapKey byłby niemutowalny.
Jaką mamy tutaj korzyść z niemutowalności obiektu skoro wartość zmiennej możemy tak czy inaczej zmodyfikować, czy to przez przypisane nowego obiektu, czy set na mutowalnym obiekcie. Jedyne co mi przychodzi do głowy to to, że przypisanie jawnie nam pokazuje w kodzie, że mamy do czynienia z nowym obiektem klucza, a set robi to w trudniejszy do wychwycenia sposób i przez to łatwiej o późniejsze błędy. Czy mógłby mi ktoś wyjaśnić czy dobrze rozumuję i jakie są prawdziwe zalety takiego niemutowalnego klucza?