1. Map
1) 키(key)와 값(value)로 구성 된 쌍으로 이루어진 객체를 저장하는 구조.
2) 순서는 유지되지 않으며, 키는 중복 저장될 수 없지만, 값은 중복 저장될 수 있음.
ex) 우편번호, 지역번호, 아이디와 패스워드
3) 구현 클래스
- HashMap
- Hashtable
- LinkedHashMap
- Properties
- TreeMap
4) 주요 메서드
기능 | 메서드 | 설명 |
객체 추가 | V put(K key, V value) | 주어진 키와 값을 추가, 저장이 되면 값을 리턴 |
void putAll(Map t) | 지정된 Map의 모든 key-value쌍을 추가 | |
객체 검색 | boolean containsKey(Object key) | 주어진 키가 있는지 여부 |
boolean containsValue(Object value) | 주어진 값이 있는지 여부 | |
int size() | 저장된 키의 총 수를 리턴 | |
V get(Object key) | 주어진 키의 값을 리턴 | |
boolean isEmpty() | 컬렉션이 비어있는지 여부 | |
Set<K> keySet() | 모든 키를 Set 객체에 담아서 리턴 | |
Set<Map.Entry<K,V>> entrySet() | 키와 값의 쌍으로 구성된 모든 Map.Entry 객체를 set 에 담아서 리턴 | |
Collection<V> values() | 저장된 모든 값 Collection에 담아서 리턴 | |
객체 삭제 | void clear() | 모든 Map.Entry(키와 값)를 삭제 |
V remove(Object key) | 주어진 키와 일치하는 Map.Entry 삭제, 삭제가 되면 값을 리턴 |
- 객체 추가, 찾기, 삭제
Map<String.Integer> map = ~;
map.put("홍길동", 30); //객체 추가
int score = map.get("홍길동"); //객체 찾기
map.remove("홍길동"); //객체 삭제
- 전체 객체를 대상으로 반복해서 얻기
//첫번째 방법
Map<K,V> map = ~;
Set<K> keySet = map.KeySet(); //map컬렉션에서 key의 값만 모아서 Set컬렉션을 만듦.
Iterator<K> keyIterator = keySetIterator(); //keySet의 반복자를 호출해서, key의 반복자를 얻어냄
while(keyIterator.hasNext()) { //실제 map 컬렉션의 있는 key의 수만큼 반복함.
K key = keyIterator.next(); //반복 중에 key를 얻어내서 저장
V value = map.get(key); //반복 중에 key의 값을 얻어내서 저장. KeySet만 만들었기 때문에,
} //값을 얻기 위해서는 map.컬렉션에서 얻어내야 함.
//두번째 방법
Set<Map.Entry<K,V>> entrySet = map.entrySet(); //MapEntry를 저장하는 Set 컬렉션을 만듦.
//Set 컬렉션에서 반복자를 호출, 반복자의 개체를 얻어냄.
Iterator<Map.Entry<K,V>> entryIterator = entrySet.iterator();
while(entryIterator.hasNext()) {
Map.Entry<K,V> entry = entryiterator.next(); //Map.Entry<K,V> 객체를 얻어냄
K key = entry.getKey() //얻어낸 것에서 key를 얻어내서 저장
V value = entry.getValue(); //얻어낸 것에서 key의 값을 얻어내서 저장
}
2. HashMap
1) Map 인터페이스를 구현한 대표적인 컬렉션 클래스
- 순서를 유지하려면 LinkedHashMap 클래스를 사용하면 됨.
2) 구조
Map<K, V> map = new HashMap<K, V>();
3) 키 객체는 hashCode()와 equals()를 재정의해 동등 객체가 될 조건을 정해야 함.
- 키(Key) : 컬렉션 내의 키 중에서 유일해야 함.
- 값(Value) : 키와 달리 데이터의 중복을 허용함.
4) 키 타입은 String 을 많이 사용
- String은 문자열이 같을 경우 동등 객체가 될 수 있도록 hashCode()와 equals() 메서드가 재정의되어 있기 때문.
5) HashMap 예시 1
import java.util.HashMap;
import java.util.Scanner;
public class HashMapTest {
public static void main(String[] args) {
HashMap map = new HashMap<>();
map.put("myId", "1234");
map.put("yourId", "1111");
Scanner sc = new Scanner(System.in);
while(true) {
System.out.println("id와 password를 입력해주세요. id는 대소문자를 구분합니다.");
System.out.print("id : ");
String id = sc.nextLine().trim(); //trim() 문자열 앞뒤 공백 제거
System.out.println();
System.out.print("password : ");
String password = sc.nextLine().trim(); //trim() 문자열 앞뒤 공백 제거
System.out.println();
if(!map.containsKey(id)) {
System.out.println("입력하신 id는 존재하지 않습니다. 다시 입력해주세요.");
continue;
}
if(!(map.get(id)).equals(password)) {
System.out.println("비밀번호가 일치하지 않습니다. 다시 입력해주세요.");
} else {
System.out.println("id와 password가 일치합니다.");
break;
}
}
sc.close();
}
}
출력 화면
id와 password를 입력해주세요. id는 대소문자를 구분합니다.
id : myId //입력한 키
password : 1234 //입력한 값
id와 password가 일치합니다.
6) HashMap 예시 2
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
public class HashMapTest2 {
public static void main(String[] args) {
HashMap map = new HashMap<>();
map.put("김자바", 90);
map.put("이자바", 100);
map.put("강자바", 100);
map.put("박자바", 85);
Set set = map.entrySet(); //키와 값이 묶인 entrySet을 set에 반환.
Iterator it = set.iterator();
while(it.hasNext()) {
Map.Entry e = (Map.Entry)it.next(); //set 에 저장되어 있었기 때문에 Map.Entry로 형변환
System.out.println("이름 : " +e.getKey()+ ", 점수 : " +e.getValue());
}
System.out.println();
set = map.keySet(); //이름만 출력하고 싶을 때는 키 set을 가져오면 됨.
System.out.println("참가자 명단 : " +set);
System.out.println();
Collection values = map.values(); //값만 출력하고 싶을 때는 values를 가져오면 됨.
it = values.iterator();
int total = 0;
while(it.hasNext()) { //값이 있는지 여부를 조회한 후,
int i = (int)it.next(); //값을 하나씩 읽어옴.
total += i;
}
System.out.println("총점 : " +total);
//총점 나누기 set의 크기로 평균 내기. //float로 형변환 해주지 않으면 정수형으로 출력됨.
System.out.println("평균 : " +(float)total/set.size());
System.out.println("최고 점수 : " +Collections.max(values));
System.out.println("최저 점수 : " +Collections.min(values));
}
}
출력 화면
이름 : 김자바, 점수 : 90
이름 : 박자바, 점수 : 85
이름 : 강자바, 점수 : 100
이름 : 이자바, 점수 : 100
참가자 명단 : [김자바, 박자바, 강자바, 이자바]
총점 : 375
평균 : 93.75
최고 점수 : 100
최저 점수 : 85
3. Hashtable
1) HashMap과 동일한 내부 구조.
Map<K, V> map = new Hashtable<K, V>();
2) Hashtable도 키 객체는 hashCode()와 equals() 를 재정의해 동등 객체가 될 조건을 정해야 함.
3) HashMap과의 차이점은 Hashtable은 동기화된 메소드로 구성되어 있기 때문에 멀티 스레드가 동시에 이 메소드들을 실행할 수 없음.
- 멀티 스레드 환경에서 안전하게 객체를 추가, 삭제 할 수 있음.
- 멀티 스레드 환경이 아니라면 Hashtable보다는 HashMap 사용이 성능이 더 좋음.
4. Properties
1) Hashtable의 하위 클래스이기 때문에 Hashtable의 모든 특징을 가지고 있음.
2) 차이점은 Properties는 키와 값을 String으로 제한한 컬렉션.
3) (~.properties) 파일을 읽을 때 사용한다.
4) (~.properties) 파일이란>
- " 키 = 값 " 으로 구성되어 있는 텍스트 파일이며, ISO 8859-1 문자셋으로 저장됨. (한글은 유니코드로 변환되어 저장)
- 옵션 정보, 데이터 베이스 연결 정보, 국제화(다국어) 정보를 기록한 텍스트 파일로 활용.
- 어플리케이션에서 주로 변경이 잦은 문자열을 저장해서 유지 보수를 편리하게 만들어 줌.
5) Properties 객체 생성
- 파일 시스템 경로를 이용
Properties properties = new Properties();
properties.load(new FileReader("C:/~/database.properties")); //properties 파일 경로을 읽어들임
- ClassPath 를 이용 (~.class 가 있는 디렉토리에 ~.properties 파일이 존재한다면)
//~.class 파일 기준으로 상대 경로를 이용해 properties 파일의 경로를 얻어 파일 읽기
//getResource()는 주어진 파일에 상대경로 URL 객체로 리턴
String path = 클래스명.class.getResource("이름.properties").getPath();
//URL의 getPath()는 파일의 절대 경로 리턴. 경로에 한글이 있을 경우 한글로 복원
path = URLDecoder.decode(path, "utf-8");
Properties properties = new Properties();
properties.load(new FileReader(path));
//~.class 파일 안에 다른 파일, 예를 들어 config 파일이 있고, 그 파일 안에 properties 파일이 있는 경우
//슬래시 표시를 해줘야 함
String path = 클래스명.class.getResource("config/이름.properties").getPath();
6) Properties 객체 생성한 후, 객체의 값 읽기 (" 키 = 값 ")
// Properties 객체의 해당 키에서 값을 읽을 때
String value = properties.getProperty("key");
4. TreeMap
1) 범위 검색과 정렬에 유리한 컬렉션 클래스. HashMap 보다 데이터 추가, 삭제에 시간이 더 걸림.
2) 객체 생성 구조
TreeMap<K, V> treeMap = new TreeMap<K, V)();
3) 이진 트리를 기반으로 한 Map 컬렉션
4) TreeSet과의 차이점은 키와 값이 저장된 Map.Entry를 저장한다는 점임.
5) TreeMap에 객체를 저장하면 부모 키 값과 비교해 자동으로 정렬되고 Map.Entry 객체를 저장함.
6) 주요 메서드
- 단일 노드 객체를 찾는 메서드 : firstEntry(), lastEntry(), lowerEntry(), higherEntry(), floorEntry(), ceilingEntry(),
pollFirstEntry(), pollLastEntry()
- 정렬 메서드 : descendingKetSet(), descendingMap()
- 범위 검색 메서드 : headMap(), tailMap(), subMap()
7) 메서드 구현
- 단일 노드 객체를 찾는 메서드 : firstEntry(), lastEntry(), lowerEntry(), higherEntry(), floorEntry(), ceilingEntry(),
pollFirstEntry(), pollLastEntry() 활용
public class TreeMapExample1 {
public static void main(String[] args) {
TreeMap<Integer, String> scores = new TreeMap<Integer, String>();
scores.put(87, "홍길동");
scores.put(98, "김자바");
scores.put(75, "이동수");
scores.put(95, "박철수");
scores.put(80, "최수진");
Map.Entry<Integer, String> entry = null;
entry = scores.firstEntry(); //가장 값이 적은 왼쪽 노드의 entry 검색
System.out.println("가장 낮은 점수 : " + entry.getKey()+ " -> " + entry.getValue());
entry = scores.lastEntry(); //가장 값이 높은 오른쪽 노드의 entry 검색
System.out.println("가장 높은 점수 : " + entry.getKey()+ " -> " + entry.getValue());
System.out.println();
entry = scores.lowerEntry(95); //95보다 적은 키를 찾아서 그 엔트리 리턴
System.out.println("95점 바로 아래 점수 : " + entry.getKey()+ " -> " + entry.getValue());
entry = scores.higherEntry(95); //95보다 높은 키를 찾아서 그 엔트리 리턴
System.out.println("95점 바로 위의 점수 : " + entry.getKey()+ " -> " + entry.getValue());
entry = scores.floorEntry(95); //95가 있으면 95 엔트리 리턴, 95가 없으면 95 바로 아래의 엔트리 리턴
System.out.println("95점이거나 바로 아래 점수 : " + entry.getKey()+ " -> " + entry.getValue());
entry = scores.ceilingEntry(96); //95가 있으면 95 엔트리 리턴, 95가 없으면 95 바로 아래의 엔트리 리턴
System.out.println("95점이거나 바로 위의 점수 : " + entry.getKey()+ " -> " + entry.getValue());
System.out.println();
while(!scores.isEmpty()) {
entry = scores.pollFirstEntry(); //제일 왼쪽에 있는 엔트리 가져오고 삭제함.
System.out.println(entry.getKey()+" -> "+entry.getValue()+" 빼면 남는 객체 수 : "+scores.size());
}
}
}
출력 화면
가장 낮은 점수 : 75 -> 이동수
가장 높은 점수 : 98 -> 김자바
95점 바로 아래 점수 : 87 -> 홍길동
95점 바로 위의 점수 : 98 -> 김자바
95점이거나 바로 아래 점수 : 95 -> 박철수
95점이거나 바로 위의 점수 : 98 -> 김자바
75 -> 이동수 빼면 남는 객체 수 : 4
80 -> 최수진 빼면 남는 객체 수 : 3
87 -> 홍길동 빼면 남는 객체 수 : 2
95 -> 박철수 빼면 남는 객체 수 : 1
98 -> 김자바 빼면 남는 객체 수 : 0
- 정렬 메서드 : descendingMap() 활용
public class TreeMapExample1 {
public static void main(String[] args) {
TreeMap<Integer, String> scores = new TreeMap<Integer, String>();
scores.put(87, "홍길동");
scores.put(98, "김자바");
scores.put(75, "이동수");
scores.put(95, "박철수");
scores.put(80, "최수진");
//descendingMap : 키와 값이 같이 저장되는 map을 가져옴.
NavigableMap<Integer, String> descendingMap = scores.descendingMap();
//entrySet을 호출하면 Map.Entry<K,V> 를 가지고 있는 Set 컬렉션이 생성됨.
Set<Map.Entry<Integer, String>> descendingEntrySet = descendingMap.entrySet();
//for문을 이용하여 Map.Entry<K,V>를 하나씩 가져와서 저장.
for(Map.Entry<Integer, String> entry : descendingEntrySet); {
System.out.println(entry.getKey()+ " - " +entry.getValue()+" ");
}
}
}
출력 화면
//내림차순으로 Map.Entry<K,V> 가 정렬됨
98-김자바
95-박철수
87-홍길동
80-최수진
75-이동수
- 범위 검색 메서드 : headMap(), tailMap(), subMap() 활용
public class TreeMapExample3 {
public static void main(String[] args) {
TreeMap<String, Integer> treeMap = new TreeMap<String, Integer>();
treeMap.put("apple", 10);
treeMap.put("forever", 60);
treeMap.put("description", 40);
treeMap.put("ever", 50);
treeMap.put("zoo", 10);
treeMap.put("base", 20);
treeMap.put("guess", 70);
treeMap.put("cherry", 30);
System.out.println("[c~f 사이의 단어 검색]");
//시작하는 값, 유무 여부, 끝나는 값, 유무 여부 확인해서 정렬해주는 subMap()메서드
NavigableMap<String, Integer> rangeMap = treeMap.subMap("c", true, "f", true);
//rangeMap 에서 entrySet을 얻어냄
for(Map.Entry<String, Integer> entry : rangeMap.entrySet()) {
System.out.println(entry.getKey()+" - "+ entry.getValue()+ "페이지");
}
}
}
출력 화면
[c~f 사이의 단어 검색]
cherry - 30페이지
description - 40페이지
ever - 50페이지
참고 : [한빛미디어] 이것이 자바다 (신용권의 Java 프로그래밍 정복) Chapter 15.컬렉션 프레임워크
참고 : [도우출판] JAVA의 정석(3ND EDITION)-자바의 정석 최신 Java 8.0 포함 Chapter 11.컬렉션 프레임워크
'JAVA' 카테고리의 다른 글
오버로딩(Overloading), 오버라이딩(Overriding) (0) | 2022.09.09 |
---|---|
인터페이스 (Interface) (0) | 2022.09.02 |
Set 컬렉션 (HashSet, TreeSet) (0) | 2022.08.28 |
List 컬렉션 (0) | 2022.08.28 |
컬렉션 프레임워크 (0) | 2022.08.28 |
댓글