[Java/자바] HashMap 클래스 사용법

HashMap은 Map 인터페이스를 구현하여 Map의 특징 키(key)와 값(value)를 묶어서 하나의 데이터(entry)로 저장한다는 특징을 가집니다.

그리고, 해싱(hashing)을 사용하기 때문에 많은 양의 데이터를 검색하는데 있어서 뛰어난 성능을 보여줍니다.

 

HashMap은 키와 값을 각각 Object타입으로 저장합니다.

즉 (Object, Object)의 형태로 저장하기 때문에 어떤 객체도 저장할 수 있지만, 키는 주로 String을 대문자 또는 소문자로 통일해 사용합니다.

 

키(key) : 컬렉션 내의 키(key) 중에서 유일해야 한다. ( 중복을 허용하지 않는다 )
값(value) : 키(key)와 달리 데이터의 중복을 허용한다.

키만 중복을 왜 허용하지 않는지에 대한 예로, 아이디와 비밀번호를 예로 들 수 있습니다.

사용자ID는 유일해야합니다. 만일, 하나의 사용자ID에 대해서 두 개 이상의 비밀번호를 얻는다면 어떤 비밀번호가 맞는 것인지 알 수 없을것 입니다.

 

HashMap 선언
import java.util.HashMap;

HashMap<타입, 타입> map = new HashMap <>(); // HashMap 생성
HashMap<String, Integer> map2 = new HashMap<>(); // String, Integer 타입의 HashMap 생성
HashMap<String, Integer> map3 = new HashMap<>(map2); // 지정된 map의 모든 요소를 포함하는 HashMap 생성
HashMap<String, Integer> map4 = new HashMap<>(int initialCapacity); // 지정된 값을 초기용량으로 하는 HashMap 생성
HashMap<String, Integer> map5 = new HashMap<>(int initialCapacity, float loadFactor); // 지정된 초기용량과 load facotr의 HashMap 생성

HashMap은 저장공간보다 값이 추가로 들어오면 List처럼 저장공간을 추가로 늘리는데 List처럼 저장공간을 한 칸씩 늘리지 않고 약 두배로 늘립니다.

그렇게 때문에, 과부하가 많이 발생합니다.

초기에 저장할 데이터 개수를 알고 있다면 Map의 초기 용량을 지정해주는 것이 좋습니다. 

 

HashMap 메서드
메서드  반환 타입 설 명
clear() void HashMap에 저장된 모든 객체를제거
clone() Object 현재 HashMap을 복제해서 반환
containsKey(Object key) boolean HashMap에 지정된 키(key)가 포함되어있는지 확인
containsValue(Object value) boolean HashMap에 지정된 값(value)가 포함되어 있는지 확인
entrySet() Set HashMap에 저장된 키와 값을 엔트리(키와 값의 결합)의 형태로 Set에 저장해서 반환
get(Object key) Object 지정된 키(key)의 값(value)를 반환.
못찾으면 null
getOrDefault(Object key, Object defaultValue) Object 지정된 키(key)의 값(객체)를 반환하는데,
키를 못찾으면, 기본 값(defaultValue)로 지정된 객체를 반환
isEmpty boolean HashMap이 비어있는지 확인
keySet() Set HashMap에 저장된 모든 키가 저장된 Set을 반환
put(Object key, Object value) Object 지정된 키와 값을 HashMap에 저장
putAll(Map m) void Map에 저장된 모든 요소를 HashMap에 저장
remove(Object key) Object HashMap에서 지정된 키로 저장된 값(value)를 제거
replace(Object key, Object value) Object 지정된 키의 값을 지정된 객체(value)로 대체
replace(Object key, Object oldValue, Object newValue) boolean 지정된 키와 객체(oldValue)가 모두 일치하는 경우에만 새로운 객체(newValue)로 대체
size() int HashMap에 저장된 요소의 개수를 반환
values() Collection HashMap에 저장된 모든 값을 컬렉션의 형태로 반환.

 


 

id와 password가 맞는지 확인하는 예제

import java.util.HashMap;
import java.util.Scanner;

class HashMapEx1 {
	public static void main(String[] args) {
		HashMap map = new HashMap();
		map.put("hevlog", "1234");
		map.put("gogo", "1111");
		map.put("gogo", "1234");

		Scanner s = new Scanner(System.in);

		while(true) {
			System.out.println("id와 password를 입력해주세요.");
			System.out.print("id :");
			String id = s.nextLine().trim();

			System.out.print("password :");
			String password = s.nextLine().trim();
			System.out.println();

			if(!map.containsKey(id)) {
				System.out.println("입력하신 id는 존재하지 않습니다. 다시 입력해주세요.");
				continue;
			} else {
				if(!(map.get(id)).equals(password)) {
					System.out.println("비밀번호가 일치하지 않습니다. 다시 입력해주세요.");
				} else {
					System.out.println("id와 비밀번호가 일치합니다.");						
					break;
				}
			}
		} 
	} 
}

id: gogo는 키 값으로, 비밀번호 1111을 갖는 gogo와, 1234를 갖는 gogo로 두 번 중복됩니다.

key는 중복된 값을 허용하지 않기 때문에, 마지막에 추가된 gogo - 1234 의 값이 기존의 gogo -1111 값을 덮어썼습니다.


시험참가자들의 총점, 평균 점수 구하는 예제

import java.util.*;

class HashMapEx2 {
	public static void main(String[] args) {
		HashMap<String, Integer> map = new HashMap<>();
		map.put("김자바", 90);
		map.put("김자바", 100);
		map.put("이자바", 100);
		map.put("강자바", 80);
		map.put("안자바", 90);

		Set set = map.entrySet();
		Iterator it = set.iterator();

		while(it.hasNext()) {
			// Iterator 조상타입 -> Map.Entry 자손 타입의 형변환 ( 다운 캐스팅 )
			Map.Entry e = (Map.Entry)it.next();
			System.out.println("이름 : "+ e.getKey() + ", 점수 : " + e.getValue());
		}

		set = map.keySet();
		System.out.println("참가자 명단 : " + set);

		Collection values = map.values();
		it = values.iterator();

		int total = 0;

		while(it.hasNext()) {
			Integer i = (Integer)it.next();
			total += i.intValue();
		}

		System.out.println("총점 : " + total);
		System.out.println("평균 : " + (float)total/set.size());
		System.out.println("최고점수 : " + Collections.max(values));
		System.out.println("최저점수 : " + Collections.min(values));
	}
}


빈도수 계산 예제

import java.util.*;

class HashMapEx4 {
	public static void main(String[] args) {
		String[] data = { "A","K","A","K","D","K","A","K","K","K","Z","D" };

		HashMap<String, Integer> map = new HashMap<>();

		for(int i=0; i < data.length; i++) {
			if(map.containsKey(data[i])) {
				Integer value = map.get(data[i]);
				map.put(data[i], (value.intValue() + 1));
			} else {
				map.put(data[i], 1);			
			}
		}

		Iterator it = map.entrySet().iterator();

		while(it.hasNext()) {
			// Iterator 조상타입 -> Map.Entry 자손 타입의 형변환 ( 다운 캐스팅 )
			Map.Entry<String, Integer> entry = (Map.Entry)it.next();
			int value = (entry.getValue()).intValue();
			System.out.println(entry.getKey() + " : " + printBar('#', value) + " " + value );
		}
	}

	// 입력받은 value의 값만큼 ch를 출력하는 메서드
	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);
	}
}

 

 


그룹을 지정하여 그룹별로 번호를 저장하는 예제

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();
	}

	// 그룹을 추가하는 메서드
	static void addGroup(String groupName) {
		if(!phoneBook.containsKey(groupName))
			 // HashMap phoneBook안에 HashMap group을 추가 - 2차원 배열과 같은 개념
			phoneBook.put(groupName, new HashMap());
	}

	// 그룹에 전화번호를 추가하는 메서드
	static void addPhoneNo(String groupName, String name, String tel) {
		addGroup(groupName);
		HashMap<String, String> group = (HashMap)phoneBook.get(groupName);
		group.put(tel, name);	// 이름은 중복될 수 있으니 전화번호를 key로 저장한다.
	}

	static void addPhoneNo(String name, String tel) {
		addPhoneNo("기타", name, tel);
	}

	// 전화번호부 전체를 출력하는 메서드
	static void printList() {
		System.out.println("폰북 : " + phoneBook);
		Set set = phoneBook.entrySet();
		System.out.println("셋 : " + set);
		Iterator it = set.iterator();	

		while(it.hasNext()) {
			// Iterator 조상타입 -> Map.Entry 자손 타입의 형변환 ( 다운 캐스팅 )
			Map.Entry e = (Map.Entry)it.next();

			// Map.Entry 조상 타입 -> HashMap 자손 타입으로 형변환 ( 다운 캐스팅 )
			Set subSet = ((HashMap)e.getValue()).entrySet(); // group 키와 값들을 뽑는다.
			Iterator subIt = subSet.iterator();	
			System.out.println(" * "+e.getKey()+"["+subSet.size()+"]");

			while(subIt.hasNext()) {
				// Iterator 조상타입 -> Map.Entry 자손 타입의 형변환 ( 다운 캐스팅 )
				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();
		}
	} 
}

위 예제는 이차원 배열처럼 HashMap안에 HashMap이 들어가 다음과 같이 그룹별로 저장된 번호목록을 출력합니다.

자세한 내용들을 주석을 하나씩 읽어보시면 이해가 되실 겁니다.


참고자료 : 자바의 정석3