HashMap을 사용할 때마다 헷갈려서 매번 다시 찾아봤던 자료들을 기반으로 싹 정리해봤다.
내부적으로 Entry<Key,Value>[] Entry의 array로 되어 있는 HashMap의 인덱스는 내부 해쉬 함수를 통해 계산된다.
String은 sun.misc.Hashing.stringHash32 함수에 의해 계산되고, 일반 Object는 내부 hashcode 함수와 비트연산으로 계산된다.
내부 hash 값에 따라서 키 순서가 정해지므로 특정 규칙없이 출력되기 때문에 입력순으로 저장 순서가 유지되어야 한다면 다른 map을 사용해야 한다.
그럼 HashMap은 어느 상황에 주로 사용되는가?
조회 시간복잡도가 O(1)로 조회 성능이 좋다. 따라서 조회가 잦은 경우, 그리고 특별한 이유가 없다면 HashMap을 사용하는 경우가 많다.
그 외에 key값을 알파벳 순서대로 정렬하려면 내부적으로 RedBlack Tree에 의해 저장되는 TreeMap
을,
(단, 랜덤접근에 대해 O(log n) 시간이 걸리므로 데이터 양 많아질 경우 성능 저하)
입력 순서가 유의미하다면 입력순대로 저장되는LinkedHashMap
을 사용하면 된다.
(단, LinkedHashMap 또한 랜덤 접근에 대해 O(n) 시간이 걸리므로 데이터 양 많아질 경우 성능 저하)
public static void main(String args[]) {
Map<String, Integer> fruits = Stream.of(new Object[][] {
{"자몽", 1000},
{"청포도", 2000},
{"복숭아", 3000}
}).collect(Collectors.toMap(item -> (String)item[0], item -> (Integer)item[1]));
System.out.println(hm);
}
replace()
: 전달된 key의 value를 인자로 전달된 value로 value 값 수정public static void main(String args[]) {
HashMap<String, Integer> subjects = new HashMap<>();
subjects.put("React", 1000);
subjects.replace("React", 5000);
subjects.replace("Vue JS", 5000); // return null
}
put()
과 get()
을 이용public static void main(String args[]) {
HashMap<String, Integer> subjects = new HashMap<>();
subjects.put("React", 1000);
subjects.put("React" , subjects.get("React") * 10);
}
1) HashMap에 entrySet()
메서드를 호출하여 Set으로 변환 후 순회
2) Set의 요소를 Map.Entry
로 접근
3) Map.Entry
의 setValue()
와 getValue()
메서드를 사용하여 기존값을 기반으로 수정
public static void main(String args[]) {
HashMap<String, Integer> subjects = new HashMap<>();
subjects.put("React", 100);
subjects.put("VueJS", 200);
subjects.put("JavaScript", 300);
subjects.put("TypeScript", 400);
for (Map.Entry<String,Integer> item : subjects.entrySet()){
item.setValue(item.getValue() * 10);
}
replaceAll()
public static void main(String args[]) {
HashMap<String, Integer> subjects = new HashMap<>();
subjects.put("React", 100);
subjects.put("VueJS", 200);
subjects.put("JavaScript", 300);
subjects.put("TypeScript", 400);
subjects.replaceAll((key, value) -> {
if(key.contains("Script")) {
return value * 10;
}
return value;
});
1) Set 객체 생성 : Map.Entry<DataType, Datatype> entry = map.entrySet();
2) Set 객체의 key 값 리턴 : entry.getKey();
3)Set 객체의 value 값 리턴 : entry.getValue();
Map<Integer, Integer> map = new HashMap<Integer, Integer>();
for (Map.Entry<Integer, Integer> entry : map.entrySet()) {
System.out.println("Key = " + entry.getKey());
System.out.println("Value = " + entry.getValue());
}
map.KeySet()
map.values()
Map<Integer, Integer> map = new HashMap<Integer, Integer>();
//iterating over keys only
for (Integer key : map.keySet()) {
System.out.println("Key = " + key);
}
//iterating over values only
for (Integer value : map.values()) {
System.out.println("Value = " + value);
}
1) Iterator 객체 생성 : Iterator
<Map.Entry<Integer, Integer>> entries = entrySet().iterator()
2) 읽어올 요소가 남아있는지 체크 : while (entries.hasNext()
)
3) 데이터 반환 : Map.Entry<Integer, Integer> entry = entries.next();
Map<Integer, Integer> map = new HashMap<Integer, Integer>();
Iterator<Map.Entry<Integer, Integer>> entries = map.entrySet().iterator();
while (entries.hasNext()) {
Map.Entry<Integer, Integer> entry = entries.next();
System.out.println("Key = " + entry.getKey() + ", Value = " + entry.getValue());
}
Map<Integer, Integer> map = new HashMap<Integer, Integer>();
for (Integer key : map.keySet()) {
Integer value = map.get(key);
System.out.println("Key = " + key + ", Value = " + value);
}