1. Map 인터페이스
- 키(Key)와 값(Value)으로 구성된 Entry 객체를 저장하는 구조
- 키와 값은 모두 객체입니다.
- 키는 중복 저장될 수 없지만 값은 중복 저장될 수 있습니다.
- 이미 저장된 키와 동일한 키로 값을 저장하게 되면 기존의 값은 없어지고 새로운 값으로 변경됩니다.
- 구현 클래스로는 HashMap, Hashtable, LinkedHashMap, Properties, TreeMap이 있습니다.
2. Map 인터페이스 주요 기능
[객체 추가]
V put(K key, V value) → 주어진 키와 값을 추가합니다.
[객체 검색]
boolean containsKey(Object key) → 주어진 키가 존재하는지 여부
boolean containsValue(Object value) → 주어진 값이 존재하는지 여부
Set<Map.Entry<K,V>> entrySet() → 키와 값의 쌍으로 구성된 모든 Map.Entry 객체를 Set에 담아서 리턴
V get(Object key) → 주어진 키가 있는 값을 리턴
boolean isEmpty() → 컬렉션이 비어 있는지 여부
Set<K> keySet() → 모든 키를 Set 객체에 담아서 리턴
int size() → 저장된 키의 총 수를 리턴
Collection<V> values() → 저장된 모든 값을 Collection에 담아서 리턴
[객체 삭제]
void clear() → 모든 Map.Entry를 삭제
V remove(Object key) → 주어진 키와 일치하는 Map.Entry를 삭제
3. HashMap
- 키의 순서가 보장되지 않습니다.
- HashMap의 키로 사용할 객체는 hashCode()와 equals() 메소드를 오버로딩해서 객체를 비교(동등 조건 비교)할 조건을 정해야합니다.
예시 (String key, String Value)
// HashMap 생성
Map<String, String> hashMap = new HashMap();
// 객체 추가
hashMap.put("lee", "Incheon");
hashMap.put("jang", "Seoul");
hashMap.put("kim", "Jeju");
// 객체 검색
System.out.println(hashMap.get("lee"));
// 루핑 (foreach)
for(String k : hashMap.keySet()) {
System.out.println(k + " : " + hashMap.get(k));
}
// 루핑 (lambda)
hashMap.forEach((k,v) -> {
System.out.println(k + " : " + k);
});
// 객체 삭제
hashMap.remove("kim");
// 주어진 키가 존재하는지 확인
System.out.println(hashMap.containsKey("kim"));
4. LinkedHashMap
HashMap과 거의 동일하나 LinkedHashMap은 Key의 순서를 보장합니다.
예시(HashMap vs LinkedHashMap)
Map<Integer, String> hashMap = new HashMap();
hashMap.put(3,"jang");
hashMap.put(2,"lee");
hashMap.put(4,"kim");
hashMap.put(1,"kim");
hashMap.forEach((k,v) -> {
System.out.println(k + " : " + v);
});
/**
* result
* 1 : kim
* 2 : lee
* 3 : jang
* 4 : kim
*/
System.out.println("------");
Map<Integer, String> linkedHashMap = new LinkedHashMap<>();
linkedHashMap.put(3,"jang");
linkedHashMap.put(2,"lee");
linkedHashMap.put(4,"kim");
linkedHashMap.put(1,"kim");
linkedHashMap.forEach((k,v) -> {
System.out.println(k + " : " + v);
});
/**
* result
* 3 : jang
* 2 : lee
* 4 : kim
* 1 : kim
*/
5. Hashtable
- Hashtable 또한 HashMap과 동일한 내부 구조를 가지고 있습니다. (HashCode(), equals())
- HashMap과의 차이점은 Hashtable은 동기화된(synchronized) 메소드로 구성되어 있어 멀티 스레드 환경에서 안전합니다. (Thread Safe)
6. Properties
- Hashtable의 하위 클래스이므로 Hashtable의 모든 특징을 가지고 있습니다.
- Properties는 키와 값을 String으로 제한합니다.
- ~.properties 파일을 읽을 때 주로 사용합니다.
- 스프링 부트 프레임워크에서 더 편리한 방법들을 제공하므로 생략합니다.
7. TreeMap
- 이진트리를 기반으로 한 Map 컬렉션입니다.
- 키와 값이 저장된 Map.Entry를 저장합니다.
- TreeMap에 객체를 저장하면 자동으로 정렬됩니다. (오름차순)
- 부모 노드의 키값과 비교하여 키 값이 작은 것은 왼쪽 자식 노드, 키 값이 큰 것은 오른쪽 자식 노드에 객체를 저장합니다.
[이진트리]
- 여러 개의 노드가 트리 형태로 연결된 구조
- 루트 노드에서부터 시작해 각 노드 최대 2개의 노드를 연결할 수 있는 구조
- 위아래로 연결된 두 노드 = 부모-자식 관계 (부모 노드, 자식 노드)
- 하나의 부모 노드는 최대 두 개의 자식 노드와 연결될 수 있습니다.
- 부모 노드의 값 보다 작은 노드는 왼쪽
- 부모 노드의 값 보다 큰 노드는 오른쪽
- 왼쪽 마지막 노드가 제일 작은 값
- 오른쪽 마지막 노드가 가장 큰 값
- 오름차순(왼쪽 마지막 노드에서부터 오른쪽 마지막 노드까지 [왼쪽]→[부모]→[오른쪽] 순으로 읽음)
- 내림차순(오른쪽 마지막 노드에서부터 왼쪽 마지막 노드까지 [오른쪽]→[부모]→[왼쪽] 순으로 읽음)
- 그룹핑에 매우 유리합니다.
TreeMap 기능
TreeMap 같은 경우엔 Map 인터페이스 타입에 대입해서 사용해도 되지만 TreeMap 타입으로 대입해야 TreeMap이 가지고 있는 검색 관련 기능들을 사용할 수 있습니다.
TreeMap<String, Integer> treeMap = new TreeMap<>();
[검색 관련 기능]
Map.Entry<K,V> firstEntry() → 제일 작은 객체를 반환
Map.Entry<K,V> lastEntry() → 제일 큰 객체를 반환
Map.Entry<K,V> lowerEntry(K key) → 주어진 객체보다 작은 데이터 중 최댓값 반환(주어진 객체보다 바로 아래 객체를 반환)
Map.Entry<K,V> higherEntry(K key) → 주어진 객체보다 큰 데이터 중 최솟값 반환(주어진 객체보다 바로 위 객체를 반환)
Map.Entry<K,V> floorEntry(K key) → 주어진 객체와 같은 값이 있으면 반환, 없다면 주어진 객체보다 작은 데이터 중 최댓값 반환
Map.Entry<K,V> ceilingEntry(K key) → 주어진 객체와 같은 값이 있으면 반환, 없다면 주어진 객체보다 큰 데이터 중 최솟값 반환
Map.Entry<K,V> pollFirstEntry() → 제일 작은 객체를 반환하고 컬렉션에서 제거
Map.Entry<K,V> pollLastEntry() → 제일 큰 객체를 반환하고 컬렉션에서 제거
// 키(cm), 이름을 저장
TreeMap<Integer, String> treeMap = new TreeMap<>();
treeMap.put(172,"kim");
treeMap.put(160,"lee");
treeMap.put(180,"jang");
treeMap.put(175,"shin");
treeMap.put(185,"choo");
System.out.println(treeMap.firstEntry()); // 160=lee
System.out.println(treeMap.lastEntry()); // 185=choo
System.out.println(treeMap.lowerEntry(180)); // 175=shin
System.out.println(treeMap.higherEntry(180)); // 185=choo
System.out.println(treeMap.floorEntry(165)); // 160=lee
System.out.println(treeMap.ceilingEntry(165)); // 172=kim
System.out.println(treeMap.pollFirstEntry()); // 160=lee
System.out.println(treeMap.pollLastEntry()); // 185=choo
[정렬 관련 기능]
NavigableSet<K> descendingKeySet() → 내림차순으로 정렬된 키의 NavigableSet을 리턴
NavigableMap<K,V> descendingMap() → 내림차순으로 정렬된 Map.Entry의 NavigableMap을 리턴
※ 오름차순으로 정렬하고 싶으면 descendingMap() 메소드를 두 번 호출합니다.
// 키(cm), 이름을 저장
TreeMap<Integer, String> treeMap = new TreeMap<>();
treeMap.put(172,"kim");
treeMap.put(160,"lee");
treeMap.put(180,"jang");
treeMap.put(175,"shin");
treeMap.put(185,"choo");
// 내림차순
NavigableMap<Integer, String> navigableMapDesc = treeMap.descendingMap();
navigableMapDesc.forEach((k,v) -> {
System.out.println(k + " : " + v);
});
// 오름차순
NavigableMap<Integer, String> navigableMapAsc = navigableMapDesc.descendingMap();
navigableMapAsc.forEach((k,v) -> {
System.out.println(k + " : " + v);
});
[범위 검색 관련 기능]
NavigableMap<K,V> headMap(E toElement, boolean inclusive)
→ 주어진 객체보다 작은 객체들을 NavigableMap으로 반환, 주어진 객체 포함 여부는 두 번째 매개 값으로 설정
NavigableMap<K,V> tailMap(E fromElement, boolean inclusive)
→ 주어진 객체보다 큰 객체들을 NavigableMap으로 반환, 주어진 객체 포함 여부는 두 번째 매개 값으로 설정
NavigableMap<K,V> subMap(E fromElement, boolean fromInclusive, E toElement, boolean toInclusive)
→ 시작과 끝으로 주어진 객체 사이의 객체들을 NavigableMap으로 반환, 시작과 끝 객체의 포함 여부는 두 번째 네 번째 매개 값으로 설정
// 키(cm), 이름을 저장
TreeMap<Integer, String> treeMap = new TreeMap<>();
treeMap.put(172,"kim");
treeMap.put(160,"lee");
treeMap.put(180,"jang");
treeMap.put(175,"shin");
treeMap.put(185,"choo");
// 180(key) 보다 작은 Entry 반환(180 포함)
NavigableMap<Integer, String> headMap1 = treeMap.headMap(180, true);
headMap1.forEach((k,v) -> {
System.out.println(k + " : " + v);
});
System.out.println("-----------------------------------");
// 180(key) 보다 작은 Entry 반환(180 미포함)
NavigableMap<Integer, String> headMap2 = treeMap.headMap(180, false);
headMap2.forEach((k,v) -> {
System.out.println(k + " : " + v);
});
System.out.println("-----------------------------------");
// 160 ~ 185 (160, 180 포함)
NavigableMap<Integer, String> subMap1 = treeMap.subMap(160, true, 185, true);
subMap1.forEach((k,v) -> {
System.out.println(k + " : " + v);
});
System.out.println("-----------------------------------");
// 160 ~ 185 (160, 180 미포함)
NavigableMap<Integer, String> subMap2 = treeMap.subMap(160, false, 185, false);
subMap2.forEach((k,v) -> {
System.out.println(k + " : " + v);
});
'Backend > Java' 카테고리의 다른 글
[Java] 자바 컬렉션 멀티 스레드 환경에서 안전하게 작업(synchronizedList, synchronizedMap, synchronizedSet) (0) | 2022.02.22 |
---|---|
[Java] LIFO 스택, FIFO 큐 (Stack, Queue) (0) | 2022.02.11 |
[Java] Set 인터페이스 특징 및 구현체 (HashSet, LinkedHashSet, TreeSet) (0) | 2022.02.10 |
[Java] List 인터페이스 특징 및 구현체 (ArrayList, LinkedList, Vector) (0) | 2022.02.09 |
[Java] 자바 컬렉션 프레임워크 소개 (List, Set, Map) (0) | 2022.02.08 |