(1) Map 인터페이스
- Map은 키-값 (key-value) 쌍을 저장하는 자료 구조 형태를 정의한 인터페이스
key | value |
---|---|
이름 | 김덕배 |
출생 | 캘리포니아 |
모국 | 파푸아뉴기니 |
key-value 대응 관계 예시
package java.util;
public interface Map<K, V> {
// 기본 동작
int size();
boolean isEmpty();
boolean containsKey(Object key);
boolean containsValue(Object value);
V get(Object key);
V put(K key, V value);
V remove(Object key);
void putAll(Map<? extends K, ? extends V> m);
void clear();
// 조회 관련
Set<K> keySet();
Collection<V> values();
Set<Map.Entry<K, V>> entrySet();
// 기본 메서드 (Java 8+)
default V getOrDefault(Object key, V defaultValue) {
V v;
return (((v = get(key)) != null) || containsKey(key)) ? v : defaultValue;
}
default void forEach(BiConsumer<? super K, ? super V> action) {
for (Map.Entry<K, V> entry : entrySet()) {
action.accept(entry.getKey(), entry.getValue());
}
}
default void replaceAll(BiFunction<? super K, ? super V, ? extends V> function) {
for (Map.Entry<K, V> entry : entrySet()) {
entry.setValue(function.apply(entry.getKey(), entry.getValue()));
}
}
// 내부 인터페이스
interface Entry<K, V> {
K getKey();
V getValue();
V setValue(V value);
boolean equals(Object o);
int hashCode();
// 기본 메서드 (Java 8+)
public static <K extends Comparable<? super K>, V> Comparator<Entry<K, V>> comparingByKey() { ... }
public static <K, V extends Comparable<? super V>> Comparator<Entry<K, V>> comparingByValue() { ... }
}
}
java.util.Map 인터페이스 요약본 (Java 8)
위의 Map 인터페이스 요약본에서 변수의 타입이 K 또는 V로 되어있는 것이 있다.
K는 Key를 의미하고, V는 Value를 의미하는 *Generic이다.
무슨 예약어 같은 것이 아니라, 무슨 용도인지를 알파벳 한 글자로 변수 명에 나타낸 것이다.
*Generic: 클래스 내부에서 사용할 타입을 외부에서 지정하는 기법이다.
(2) Map 주요 메서드
메서드 | 설명 |
put(K, V) | K에 해당하는 값 저장하며 기존 K와 중복될 경우, V를 덮어씌움 |
get(Object) | 해당 K에 대한 V를 가져옴 |
remove(Object) | K에 해당하는 항목 제거 |
keySet() | K만 모아놓은 Set 반환 |
values() | V만 모아놓은 Collection 반환 |
entrySet() | K-V 쌍을 Map.Entry로 묶은 Set 반환 |
getOrDefault() | K가 없으면 기본값 반환 |
forEach() | 모든 K-V 쌍에 대한 람다 실행 |
replaceAll() | V를 일괄적으로 변경 |
K는 Key, V는 Value
(3) Map.Entry
Map 인터페이스 내부에 Entry<K, V>라는 인터페이스가 중첩 선언되어있다.
이는 Map의 key-value 쌍 하나를 표현한 객체이다.
그리고 Map.Entry는 Map 객체에 entrySet() 메서드를 이용해 반환받을 수 있다.
이는 주로 Map을 반복할 때 사용된다.
// Map으로 선언된 값을 반복하여 순회
Map<String, Integer> map = new HashMap<>();
map.put("kim", 20);
map.put("park", 22);
// entrySet()를 이용해 한 쌍의 Map을 각각 Map.Entry로 반환받아 사용
for(Map.Entry<String, Integer> entry : map.entrySet()) {
System.out.println("key: " + entry.getKey());
System.out.println("value: " + entry.getValue());
}
위 예시와 같이, Map에 저장된 여러 개의 key-value 쌍에서
하나의 key-value 쌍을 꺼내올 수 있다.
물론, Map.Entry로 반환받지 않아도 각 Map 항목의 key-value 값에 접근할 순 있다.
아래 코드를 보자.
// Map으로 선언된 값을 반복하여 순회
Map<String, Integer> map = new HashMap<>();
map.put("kim", 20);
map.put("park", 22);
// keySet()를 이용해 Map 요소의 각 key 값을 반환받음
// 반환받은 key를 이용해 map.get(key)와 같은 형태로 value에 접근
for(String key : map.keySet()) {
System.out.println("key: " + key);
System.out.println("value: " + map.get(key));
}
위와 같이 key-value에 접근할 수 있지만,
Map.Entry로 반환받으면, 한 번에 key와 value에 접근할 수 있다.
물론, 필요하다면 setValue() 메서드로 value 값 수정도 가능하다.
이러한 Map.Entry 인터페이스의 주요 메서드는 아래와 같다.
메서드 | 설명 |
K getKey() | Entry의 K 반환 |
V getValue() | Entry의 V 반환 |
V setValue(V value) | 현재 Entry의 V를 새로운 값으로 변경 |
boolean equals(Object o) | 현재 Entry와 다른 Entry가 같은지 비교 |
int hashCode() | Entry의 해시코드 반환 |
K는 Key, V는 Value
(4) HashMap
- 기본적인 Map 인터페이스 구현체로, 빠르고 효율적
- 입력 순서 보장 X
- null 값 key 1개 허용
- 단일 스레드에서 주로 사용
Map<String, String> map = new HashMap<>();
map.put(null, "value"); // OK
(5) LinkedHashMap
- 입력 순서 유지
- null 값 key 1개 허용
- 캐시 구현(순서 기반)에 주로 사용
Map<String, String> map = new LinkedHashMap<>();
map.put("A", "Apple");
map.put("B", "Banana");
// A, B 순서 유지
(6) TreeMap
- key 기준 자동 정렬 (오름차순)
- 숫자일 경우 값, 문자열일 경우 유니코드 정렬
- null 값 key 비허용
- 일반적으로 Map으로서 HashMap보다 성능 떨어짐
- 내부적으로 *Red-Black Tree 사용
- 정렬된 상태 유지 및 정렬 데이터에 대한 범위 검색에 효율적
Map<String, Integer> map = new TreeMap<>();
map.put("banana", 2);
map.put("apple", 1);
// 자동 정렬: apple → banana
*Red-Black Tree: 부모 노드보다 작은 값을 가진 노드는 왼쪽 자식, 큰 값을 가진 노드는 오른쪽 자식에 배치하는 구조
(7) HashTable
- 모든 메서드가 synchronized
- 스레드 환경에서 안전
- null 값 key, value 비허용
- 레거시한 구조
Map<String, String> map = new Hashtable<>();
map.put(null, "value"); // 예외 발생
(8) ConcrurrentHashMap
- 멀티 스레드 환경에서 안전
- 동기화를 하지만, 부분 동기화이므로 성능 좋음 (부분적으로 lock 사용)
- null 값 key, value 비허용
- 실시간 서비스 등에 사용
(9) Map 인터페이스 구현체 정리
구현체 | 정렬 | 동기화 | null 허용 | 사용처 |
HashMap | X | X | key에 null 1개 허용 value에 다수 null 허용 |
많이 사용되며, 빠르고 유연 |
LinkedHashMap | 입력 순서 유지 | X | key에 null 1개 허용 value에 다수 null 허용 |
순서 유지가 필요할 때 |
TreeMap | key 기준 자동 정렬 | X | X (value에 다수 null 허용 ) |
key 기준 자동 정렬이 필요할 때 |
HashTable | X | 전체 동기화 | X | 레거시 코드 |
ConcrurrentHashMap | X | 부분 동기화 | X | 멀티 스레드 환경 |
'Language > Java' 카테고리의 다른 글
[Java] 자바 연산자 (Java Operator) (0) | 2024.04.23 |
---|