백엔드/JAVA
[Java] 맵(Map)
mike705114
2024. 12. 4. 19:56
Map은 Java의 컬렉션 프레임워크에서 키-값(key-value) 쌍으로 데이터를 저장하고 관리하는 인터페이스입니다. 데이터 조회, 삽입, 삭제가 효율적이며, List와 달리 순서를 보장하지 않는 것이 특징입니다. Map의 주요 구현체로는 HashMap, LinkedHashMap, TreeMap, Hashtable 등이 있습니다.
1. Map의 특징
- Key-Value 구조:
- key는 고유하며, 중복을 허용하지 않습니다.
- value는 중복이 가능합니다.
- null 허용 여부:
- 대부분의 구현체(HashMap 등)는 null 키와 다수의 null 값을 허용합니다.
- 단, TreeMap과 같은 일부 구현체는 null 키를 허용하지 않습니다.
- 순서 보장 여부:
- HashMap: 삽입 순서를 보장하지 않음.
- LinkedHashMap: 삽입 순서를 보장.
- TreeMap: 키를 정렬된 순서로 저장.
2. 주요 메서드
메서드 | 설명 |
put(K key, V value) | 키와 값을 추가하거나, 기존 키에 대해 값을 업데이트합니다. |
get(Object key) | 키에 해당하는 값을 반환합니다. 값이 없으면 null을 반환합니다. |
remove(Object key) | 특정 키-값 쌍을 제거합니다. |
containsKey(Object key) | 특정 키가 존재하는지 확인합니다. |
containsValue(Object value) | 특정 값이 존재하는지 확인합니다. |
size() | Map에 저장된 키-값 쌍의 개수를 반환합니다. |
keySet() | 모든 키를 Set으로 반환합니다. |
values() | 모든 값을 Collection으로 반환합니다. |
entrySet() | 모든 키-값 쌍을 Set<Map.Entry<K, V>>로 반환합니다. |
clear() | 모든 데이터를 삭제합니다. |
isEmpty() | Map이 비어 있는지 확인합니다. |
3. Map의 주요 구현체 비교
구현체 | 순서보장 | 정렬기준 | 동기화 여부 | 특이점 |
HashMap | 보장하지 않음 | 없음 | 비동기 | 가장 일반적으로 사용, 빠른 성능. |
LinkedHashMap | 삽입 순서를 유지 | 없음 | 비동기 | 순서를 유지하면서도 성능이 우수. |
TreeMap | 키의 정렬된 순서 유지 | 키의 자연 순서 또는 Comparator |
비동기 | NavigableMap 인터페이스를 구현. |
Hashtable | 보장하지 않음 | 없음 | 동기화 | 레거시 클래스, 동기화를 제공. |
ConcurrentHashMap | 보장하지 않음 | 없음 | 동기화 (고성능) | 병렬 처리를 위해 최적화된 Map. |
4. 예제 코드
(1) 기본적인 HashMap 사용
import java.util.HashMap;
import java.util.Map;
public class HashMapExample {
public static void main(String[] args) {
Map<String, Integer> map = new HashMap<>();
// 데이터 추가
map.put("Alice", 25);
map.put("Bob", 30);
map.put("Charlie", 35);
// 데이터 조회
System.out.println("Bob's Age: " + map.get("Bob"));
// 데이터 삭제
map.remove("Alice");
// 모든 키 출력
for (String key : map.keySet()) {
System.out.println("Key: " + key);
}
// 모든 값 출력
for (Integer value : map.values()) {
System.out.println("Value: " + value);
}
}
}
(2) 정렬된 키를 유지하는 TreeMap 사용
import java.util.TreeMap;
public class TreeMapExample {
public static void main(String[] args) {
TreeMap<String, Integer> treeMap = new TreeMap<>();
treeMap.put("Banana", 20);
treeMap.put("Apple", 30);
treeMap.put("Cherry", 10);
// 키의 자연 순서로 출력
for (String key : treeMap.keySet()) {
System.out.println(key + ": " + treeMap.get(key));
}
}
}
(3) 동기화가 필요한 경우 ConcurrentHashMap
import java.util.concurrent.ConcurrentHashMap;
public class ConcurrentHashMapExample {
public static void main(String[] args) {
ConcurrentHashMap<String, Integer> concurrentMap = new ConcurrentHashMap<>();
concurrentMap.put("Thread1", 1);
concurrentMap.put("Thread2", 2);
concurrentMap.forEach((key, value) ->
System.out.println(key + ": " + value));
}
}
5. Map 사용 시 유용한 팁
- 기본적으로 HashMap 사용:
- 속도와 메모리 효율이 우수.
- 순서를 보장해야 한다면 LinkedHashMap 사용.
- 동기화 필요 시:
- 동기화가 필요한 경우 ConcurrentHashMap 사용.
- Collections.synchronizedMap()으로 간단히 동기화 가능.
- 정렬된 데이터가 필요하다면 TreeMap:
- 정렬이 필요하다면 TreeMap을 고려하되 성능 저하를 주의.
- 람다식과 Stream 활용:
- entrySet(), keySet(), values()와 Stream API를 활용해 간결하고 가독성 있는 코드를 작성.
6. Map이 자주 쓰이는 경우
1. 빈도수 계산
- 문제 유형: 문자열이나 배열에서 특정 요소의 등장 횟수를 계산해야 할 때.
- 예제:
- 문자열에서 각 문자의 빈도를 계산 (문자열 압축, 애너그램 확인).
- 배열에서 등장 횟수가 가장 많은 요소 찾기.
import java.util.HashMap;
public class FrequencyCounter {
public static void main(String[] args) {
String input = "aabbbc";
HashMap<Character, Integer> frequencyMap = new HashMap<>();
for (char c : input.toCharArray()) {
frequencyMap.put(c, frequencyMap.getOrDefault(c, 0) + 1);
}
System.out.println(frequencyMap); // {a=2, b=3, c=1}
}
}
2. 애너그램 확인
- 문제 유형: 두 문자열이 같은 문자의 조합인지 확인.
- 설명: 각 문자의 빈도를 Map에 저장하고 비교.
import java.util.HashMap;
public class AnagramCheck {
public static boolean isAnagram(String s1, String s2) {
if (s1.length() != s2.length()) return false;
HashMap<Character, Integer> charCount = new HashMap<>();
for (char c : s1.toCharArray()) {
charCount.put(c, charCount.getOrDefault(c, 0) + 1);
}
for (char c : s2.toCharArray()) {
if (!charCount.containsKey(c) || charCount.get(c) == 0) {
return false;
}
charCount.put(c, charCount.get(c) - 1);
}
return true;
}
public static void main(String[] args) {
System.out.println(isAnagram("listen", "silent")); // true
System.out.println(isAnagram("hello", "world")); // false
}
}
3. 중복 요소 확인
- 문제 유형: 배열이나 문자열에 중복된 요소가 있는지 확인.
- 설명: Map으로 각 요소를 저장하면서 중복 여부를 체크.
import java.util.HashMap;
public class DuplicateChecker {
public static boolean hasDuplicate(int[] nums) {
HashMap<Integer, Boolean> map = new HashMap<>();
for (int num : nums) {
if (map.containsKey(num)) {
return true;
}
map.put(num, true);
}
return false;
}
public static void main(String[] args) {
int[] nums = {1, 2, 3, 4, 2};
System.out.println(hasDuplicate(nums)); // true
}
}
맵이 필요한 경우 정리
- 빠른 조회가 필요:
- 특정 값을 빠르게 찾거나 확인해야 할 때.
- 예: 빈도수 계산, 두 수의 합 문제.
- 키-값 관계로 데이터를 저장:
- 그룹화, 매핑 작업이 필요할 때.
- 예: 데이터를 특정 조건에 따라 그룹화.
- 효율적인 중복 체크:
- 중복된 요소를 효율적으로 찾고 관리해야 할 때.
- 누적 합 문제:
- 부분 배열 합 문제처럼 중간 결과를 저장하고 활용할 때.
Map은 O(1)에 가까운 조회 성능을 제공하므로, 코딩 테스트에서 시간을 절약하고 효율적으로 문제를 해결하는 데 매우 유용합니다!