Be ready to study forever - 개발자 꿈나무
[JAVA 문법] Collection Framework - Map 본문
Collection Framework – Map
1.HashMap
HashMap은 Key와 Value가 하나의 데이터(entry)로 묶여 저장되는 특징이 있다. 해싱기법을 사용해서 많은 양의 정보를 검색하는데 성능이 좋다. 키 값은 중복이 불가능 하지만 벨류 값은 중복이 허용된다. 또한, 저장되는 순서가 없는 것이 특징이다. HashMap은 put()메서드로 중복된 키값을 저장하려 하면 기존에 있던 키 값의 벨류 값을 덮어 쓰기하는 방식으로 작동하기 때문에 주의해야 한다. HashMap은 null값을 허용하기 때문에 주의할 것.
*HashSet은 add()메서드로 저장하려 할 경우 값을 저장하지 않고 false를 반환함으로써 저장 실패를 알린다.
1.1. HashMap의 Entry
HashMap은 Entry라는 내부의 클래스를 정의하고 Entry타입의 배열을 선언하여 배열안에 함께 Key와 Value가 체인된 상태로 저장이 된다.
1.2. HashMap의 메서드
1.3. HashMap의 중첩
위에 언급한 바와 같이 HashMap은 Entry안에 Object타입으로 모든 키와 값을 저장하기 때문에 Value값으로 HashMap을 다시 지정할 수 있다. 이렇게 할 경우 한 개의 Key값에 여러 개의 Value값을 매핑하는 것이 가능하다.
import java.util.*;
class HashMapEx3 {
static HashMap phoneBook = new HashMap();
public static void main(String[] args) {
addPhoneNo("친구", "이자바", "010-111-1111");
addPhoneNo("친구", "김자바", "010-222-2222");
addPhoneNo("친구", "김자바", "010-333-3333");
addPhoneNo("회사", "김대리", "010-444-4444");
addPhoneNo("회사", "김대리", "010-555-5555");
addPhoneNo("회사", "박대리", "010-666-6666");
addPhoneNo("회사", "이과장", "010-777-7777");
addPhoneNo("세탁", "010-888-8888");
printList();
} // main
// 그룹을 추가하는 메서드
static void addGroup(String groupName) {
if(!phoneBook.containsKey(groupName))
phoneBook.put(groupName, new HashMap());
}
// 그룹에 전화번호를 추가하는 메서드
static void addPhoneNo(String groupName, String name, String tel) {
addGroup(groupName);
HashMap group = (HashMap)phoneBook.get(groupName);
group.put(tel, name); // 이름은 중복될 수 있으니 전화번호를 key로 저장한다.
}
static void addPhoneNo(String name, String tel) {
addPhoneNo("기타", name, tel);
}
// 전화번호부 전체를 출력하는 메서드
static void printList() {
Set set = phoneBook.entrySet();
Iterator it = set.iterator();
while(it.hasNext()) {
Map.Entry e = (Map.Entry)it.next();
Set subSet = ((HashMap)e.getValue()).entrySet();
Iterator subIt = subSet.iterator();
System.out.println(" * "+e.getKey()+"["+subSet.size()+"]");
while(subIt.hasNext()) {
Map.Entry subE = (Map.Entry)subIt.next();
String telNo = (String)subE.getKey();
String name = (String)subE.getValue();
System.out.println(name + " " + telNo );
}
System.out.println();
}
} // printList()
} // class
1.4. Hashing과 해시함수
Hashing이란 해시 함수를 이용해서 데이터를 해시테이블에 저장하고 검색하는 기법이다. 해시함수는 데이터가 저장되는 곳을 알려주기 때문에 다량의 데이터 중에서도 원하는 데이터를 빠르게 찾을 수 있다. 해싱을 구현한 클래스로는 HashSet, HashMap등이 있다. 해싱에 사용되는 자료구조는 Array와 LinkedList의 조합으로 되어있다.
Array LinkedList LinkedList
HashMap에서 해싱은 저장할 데이터의 Key값을 해시함수에 넣으면 해시 값과 배열의 한 요소를 얻게 되고 다시 그곳에 연결된 LinkedList에 저장되게 된다.
반대로 해싱한 데이터를 찾을때는
1. 검색하고자 하는 Key를 해시함수에 넣는다
2. 해싱한 값과 일치하는 값을 배열에서 찾는다.
3. LinkedList를 타고 가서 일치하는 Key의 값을 찾아낸다.
이와깉은 방법으로 해싱한 값을 찾아내기 때문에 한 배열(HashCode값이 같은)에 너무 많은 LinkedList가 몰려있으면 속도가 떨어지므로 잘 분산하는 해시함수를 짜는 것이 성능향상에 중요하다.
2. TreeMap
TreeMap은 이진 검색 트리의 행태이지만 키값과 밸류값을 가지는 데이터 컬랙션으로서, 데이터 저장에 순서가 없고, 키값은 중복이 허용 안되지만 벨류값은 중복이 허용된다. 대부분의 경우는 HashMap이 성능이 더 좋지만, 범위검색이나 정렬에는 TreeMap이 더 성능이 좋다.
2.1. TreeMap메서드
메소드 |
설명 |
Map.Entry<K, V> ceilingEntry(K key) |
해당 맵에서 전달된 키와 같거나, 전달된 키보다 큰 키 중에서 가장 작은 키와 그에 대응하는 값의 엔트리를 반환함. 만약 해당하는 키가 없으면 null을 반환함. |
K ceilingKey(K key) |
해당 맵에서 전달된 키와 같거나, 전달된 키보다 큰 키 중에서 가장 작은 키를 반환함. 만약 해당하는 키가 없으면 null을 반환함. |
void clear() |
해당 맵(map)의 모든 매핑(mapping)을 제거함. |
boolean containsKey(Object key) |
해당 맵이 전달된 키를 포함하고 있는지를 확인함. |
boolean containsValue(Object value) |
해당 맵이 전달된 값에 해당하는 하나 이상의 키를 포함하고 있는지를 확인함. |
NavigableMap<K, V> descendingMap() |
해당 맵에 포함된 모든 매핑을 역순으로 반환함. |
Set<Map.Entry<K, V>> entrySet() |
해당 맵에 포함된 모든 매핑을 Set 객체로 반환함. |
Map.Entry<K, V> firstEntry() |
해당 맵에서 현재 가장 작은(첫 번째) 키와 그에 대응하는 값의 엔트리를 반환함. |
K firstKey() |
해당 맵에서 현재 가장 작은(첫 번째) 키를 반환함. |
Map.Entry<K, V> floorEntry(K key) |
해당 맵에서 전달된 키와 같거나, 전달된 키보다 작은 키 중에서 가장 큰 키와 그에 대응하는 값의 엔트리를 반환함. 만약 해당하는 키가 없으면 null을 반환함. |
K floorKey(K key) |
해당 맵에서 전달된 키와 같거나, 전달된 키보다 작은 키 중에서 가장 큰 키를 반환함. 만약 해당하는 키가 없으면 null을 반환함. |
V get(Object key) |
해당 맵에서 전달된 키에 대응하는 값을 반환함. 만약 해당 맵이 전달된 키를 포함한 매핑을 포함하고 있지 않으면 null을 반환함. |
SortedMap<K, V> headMap(K toKey) |
해당 맵에서 전달된 키보다 작은 키로 구성된 부분만을 반환함. |
Map.Entry<K, V> higherEntry(K key) |
해당 맵에서 전달된 키보다 작은 키 중에서 가장 큰 키와 그에 대응하는 값의 엔트리를 반환함. 만약 해당하는 키가 없으면 null을 반환함. |
K higherKey(K key) |
해당 맵에서 전달된 키보다 작은 키 중에서 가장 큰 키를 반환함. 만약 해당하는 키가 없으면 null을 반환함. |
Set<K> keySet() |
해당 맵에 포함되어 있는 모든 키로 만들어진 Set 객체를 반환함. |
Map.Entry<K, V> lastEntry() |
해당 맵에서 현재 가장 큰(마지막) 키와 그에 대응하는 값의 엔트리를 반환함. |
K lastKey() |
해당 맵에서 현재 가장 큰(마지막) 키를 반환함. |
Map.Entry<K, V> lowerEntry(K key) |
해당 맵에서 전달된 키보다 큰 키 중에서 가장 작은 키와 그에 대응하는 값의 엔트리를 반환함. 만약 해당하는 키가 없으면 null을 반환함. |
K lowerKey(K key) |
해당 맵에서 전달된 키보다 큰 키 중에서 가장 작은 키를 반환함. 만약 해당하는 키가 없으면 null을 반환함. |
Map.Entry<K, V> pollFirstEntry() |
해당 맵에서 현재 가장 작은(첫 번째) 키와 그에 대응하는 값의 엔트리를 반환하고, 해당 엔트리를 맵에서 제거함. |
Map.Entry<K, V> pollLastEntry() |
해당 맵에서 현재 가장 큰(마지막) 키와 그에 대응하는 값의 엔트리를 반환하고, 해당 엔트리를 맵에서 제거함. |
V put(K key, V value) |
해당 맵에 전달된 키에 대응하는 값으로 특정 값을 매핑함. |
V remove(Object key) |
해당 맵에서 전달된 키에 대응하는 매핑을 제거함. |
boolean remove(K key, V value) |
해당 맵에서 특정 값에 대응하는 특정 키의 매핑을 제거함. |
V replace(K key, V value) |
해당 맵에서 전달된 키에 대응하는 값을 특정 값으로 대체함. |
boolean replace(K key, V oldValue, V newValue) |
해당 맵에서 특정 값에 대응하는 전달된 키의 값을 새로운 값으로 대체함. |
int size() |
해당 맵의 매핑의 총 개수를 반환함. |
SortedMap<K, V> subMap(K fromKey, K toKey) |
해당 맵에서 fromKey부터 toKey까지로 구성된 부분만을 반환함. 이때 fromKey는 포함되나, toKey는 포함되지 않음. |
SortedMap<K, V> tailMap(K fromKey) |
해당 맵에서 fromKey와 같거나, fromKey보다 큰 키로 구성된 부분만을 반환함. |
TreeMap예제코드
import java.util.*;
class TreeMapEx1 {
public static void main(String[] args) {
String[] data = { "A","K","A","K","D","K","A","K","K","K","Z","D" };
TreeMap map = new TreeMap();
for(int i=0; i < data.length; i++) {
if(map.containsKey(data[i])) {
Integer value = (Integer)map.get(data[i]);
map.put(data[i], new Integer(value.intValue() + 1));
} else {
map.put(data[i], new Integer(1));
}
}
Iterator it = map.entrySet().iterator();
System.out.println("= 기본정렬 =");
while(it.hasNext()) {
Map.Entry entry = (Map.Entry)it.next();
int value = ((Integer)entry.getValue()).intValue();
System.out.println(entry.getKey() + " : " + printBar('#', value) + " " + value );
}
System.out.println();
// map을 ArrayList로 변환한 다음에 Collectons.sort()로 정렬
Set set = map.entrySet();
List list = new ArrayList(set); // ArrayList(Collection c)
// static void sort(List list, Comparator c)
Collections.sort(list, new ValueComparator());
it = list.iterator();
System.out.println("= 값의 크기가 큰 순서로 정렬 =");
while(it.hasNext()) {
Map.Entry entry = (Map.Entry)it.next();
int value = ((Integer)entry.getValue()).intValue();
System.out.println(entry.getKey() + " : " + printBar('#', value) + " " + value );
}
} // public static void main(String[] args)
static class ValueComparator implements Comparator {
public int compare(Object o1, Object o2) {
if(o1 instanceof Map.Entry && o2 instanceof Map.Entry) {
Map.Entry e1 = (Map.Entry)o1;
Map.Entry e2 = (Map.Entry)o2;
int v1 = ((Integer)e1.getValue()).intValue();
int v2 = ((Integer)e2.getValue()).intValue();
return v2 - v1;
}
return -1;
}
} // static class ValueComparator implements Comparator {
public static String printBar(char ch, int value) {
char[] bar = new char[value];
for(int i=0; i < bar.length; i++) {
bar[i] = ch;
}
return new String(bar);
}
}
3. Properties
Properties는 HashMap의 구버전인 Hashtable을 상속받아 구현한 것으로 HashMap이나 Hashtable이 키와 벨류값을 Object로 저장하는 반면에 Properties는 키와 벨류값을 모두 String으로 저장한다. 주로 환경설정과 관련된 속성을 저장하는데 사용된다.
3.1. Properties메서드
4.Collections클래스
Arrays클래스가 배열관 관련된 메서드들은 제공한다면, Collections클래스 역시 데이터콜랙션과 관련된 메서드를 제공한다.
*Collection은 인터페이스 이고 Collections는 클래스이다. 또한 Arrays클래스와 같이 모두 static메서드이다.
4.1.컬랙션 동기화
멀티쓰레드 프로그래밍을 할 경우 여러 쓰레드가 동시에 동일한 객체에 접근할 수 있기 때문에 데이터의 일관성을 유지하기 위해서 공유되는 객체에 동기화가 필요하다. 하지만 동기화는 싱글쓰레드일 경우 불필요한 분이기 때문에 따로 떼어내서 필요시에만 java.util.Collections클래스의 동기화 메서드를 이용하여 처리하고 있다.
4.2. 변경 불가능한 컬렉션 만들기
때에 따라서는 데이터가 삭제되거나 수정되지 않도록 변경이 불가능한 컬렉션을 만들 필요가 있다. 이를 위해서 unmodifiedXXX메서드를 이용하면 가능하다.
4.3. 싱글톤
컬렉션 만들기
단 하나의 객체만을 저장하는 컬렉션을 만들어야 할 때가 있다. 이럴 때에 사용하는 메서드이다.
4.4. 한종류의 객체만 담는 컬렉션
기본적으로 컬렉션은 어떠한 오브젝트던지 담을 수 있지만 때에 따라서는 특정한 종류의 객체만 담을 필요성이 있다.
컬렉션 프레임워크를 마치며
'Programming > JAVA' 카테고리의 다른 글
[JAVA 문법] Enums - 열거형 (0) | 2020.07.29 |
---|---|
[JAVA 문법] 12. Generics (0) | 2020.07.29 |
[JAVA 문법] Collection Framework - Set (0) | 2020.07.28 |
[JAVA 문법]Collection Framework - Lists (0) | 2020.07.28 |
[JAVA 문법] java.lang패키지 - Math클래스, Wrapper클래스 (0) | 2020.07.25 |