1. 소개
우리는 이미 ArrayList가 스스로 커지는 “무한 배열”이라는 것을 알고 있습니다. 하지만 하나의 제약이 있습니다. 요소에 접근할 때 번호(인덱스)로만 접근한다는 점입니다. 예를 들어 천 명의 사람이 있는 리스트에서 알리사의 전화번호를 찾고 싶다면, 그녀의 인덱스를 알고 있거나 전부를 순회해야 합니다.
실생활에서는 데이터를 고유한 식별자로 찾을 때가 많습니다:
- 이름으로 전화번호를 찾고,
- 여권 번호로 소유자를 찾고,
- 로그인으로 비밀번호를 찾고,
- id로 데이터베이스에서 객체를 찾습니다.
이를 위해서는 “키를 받으면 → 바로 값을 찾는” 구조가 필요합니다. Java에서는 HashMap<K,V>가 이 일을 담당합니다.
비유:
보통 종이 사전을 떠올려 보세요. “house”라는 단어의 번역을 찾을 때 모든 페이지를 처음부터 끝까지 넘길 필요가 없습니다. 곧바로 “H” 섹션으로 가면 됩니다. HashMap도 마찬가지로 작동합니다. 키(단어)로 값을(번역) 즉시 얻습니다.
사전 생성
사전을 만들려면 어떤 타입이 키이고 어떤 타입이 값인지 지정해야 합니다.
import java.util.HashMap;
HashMap<String, String> phonebook = new HashMap<String, String>();
설명:
- String(첫 번째 타입)은 키의 타입(사람 이름)입니다.
- String(두 번째 타입)은 값의 타입(전화번호)입니다.
이제 phonebook은 실제 전화번호부와 같습니다.
다른 예시:
HashMap<String, Integer> grades = new HashMap<String, Integer>(); // 이름 → 점수
HashMap<Integer, String> users = new HashMap<Integer, String>(); // id → 이름
HashMap<String, Boolean> flags = new HashMap<String, Boolean>(); // 키 → 불리언 값
ArrayList와 달리, 사전에는 add() 메서드가 없지만 그 못지않게 유용한 자체 메서드들이 있습니다.
2. 메서드 put(key, value) — 쌍 추가
HashMap이 배열이나 리스트와 다른 가장 큰 점은, 단순한 값의 모음이 아니라 키–값 쌍을 저장한다는 것입니다. 이는 실제 사전과 비슷합니다. 각 단어에는 번역이 있고, 각 이름에는 전화번호가 있으며, 각 로그인에는 비밀번호가 있습니다.
예:
phonebook.put("알리사", "+380501112233");
phonebook.put("밥", "+380671234567");
이제 전화번호부에는 다음이 저장되어 있습니다:
- 키 "알리사"는 값 "+10501112233"와 연결되어 있고,
- 키 "밥"은 값 "+10671234567"과 연결되어 있습니다.
즉, 값을(전화번호) 얻으려면 키(이름)만 알면 됩니다.
중요: 키는 고유합니다. 이미 존재하는 키로 새 값을 넣으면 기존 값이 덮어써집니다.
phonebook.put("알리사", "+10999999999");
이제 알리사에게는 새 번호만 남고, 이전 번호는 사라집니다.
요약: put은 항목을 추가하거나 갱신하는 메서드입니다. 키가 새롭다면 항목이 생성되고, 이미 있다면 값이 갱신됩니다.
3. 메서드 get(key) — 값 가져오기
값을 찾으려면 키를 알아야 합니다. 이것이 HashMap의 핵심입니다. 키로 검색하는 작업은 매우 빠르며, 항목이 천 개든 백만 개든 거의 즉시 동작합니다.
예:
System.out.println(phonebook.get("알리사"));
출력:
+10501112233
해당 키가 없으면 get은 null을 반환합니다:
System.out.println(phonebook.get("찰리")); // null
즉: “키 "찰리"는 사전에 없다”는 뜻입니다.
4. 메서드 containsKey(key) — 존재 여부 확인
null을 피하려면, 먼저 사전에 키가 있는지 확인하는 것이 좋습니다.
예:
System.out.println(phonebook.containsKey("찰리"));
출력:
false
따라서 미리 다음을 판단할 수 있습니다:
- 키가 없으면 — 새 항목을 생성하고,
- 키가 있으면 — 값을 갱신합니다.
자주 쓰는 패턴:
if (phonebook.containsKey("알리사"))
{
System.out.println("알리사의 번호가 이미 있습니다!");
}
else
{
phonebook.put("알리사", "+10111111111");
}
5. 메서드 remove(key) — 항목 삭제
삭제도 간단합니다. 키만 알면 됩니다.
phonebook.remove("밥");
System.out.println(phonebook.get("밥"));
출력:
null
이제 키 "밥"에 해당하는 항목은 사전에 존재하지 않습니다.
6. 모든 쌍 순회
특정 키로만 값을 얻는 것이 아니라, 사전 전체를 출력해야 할 때도 있습니다. 이때 entrySet() 메서드를 사용합니다.
for (var entry : phonebook.entrySet()) {
System.out.println(entry.getKey() + " -> " + entry.getValue());
}
예시 출력:
알리사 -> +10501112233
이렇게 하면 키(entry.getKey())와 값(entry.getValue())에 동시에 접근할 수 있습니다.
7. 실습: 단어 개수 세기
텍스트에서 단어가 몇 번 등장하는지 세는 고전적인 문제를 살펴봅시다. HashMap의 필요성을 가장 잘 보여 주는 예시입니다.
String text = "java java core java";
HashMap<String, Integer> freq = new HashMap<String, Integer>();
for (String w : text.split(" "))
{
Integer old = freq.get(w);
freq.put(w, (old == null) ? 1 : old + 1);
}
System.out.println(freq);
출력:
{core=1, java=3}
여기서 일어나는 일을 자세히 보면:
- 문자열 "java java core java"를 단어로 분리합니다.
- 각 단어에 대해 이미 사전에 있는지 확인합니다(freq.get(w)).
- 없다면(null) 첫 등장이므로 1을 넣습니다.
- 있다면 이미 등장했으니 값을 1 증가시킵니다.
실전 활용:
- API 호출 횟수 집계,
- 텍스트에서 단어 빈도 통계,
- 창고 재고 수량 관리.
8. 실습: 전화번호부
좀 더 큰 예제를 만들어 봅시다.
import java.util.HashMap;
import java.util.Scanner;
public class PhonebookApp {
public static void main(String[] args)
{
HashMap<String, String> phonebook = new HashMap<String, String>();
Scanner console = new Scanner(System.in);
while (true)
{
System.out.print("이름을 입력하세요(종료하려면 빈 줄): ");
String name = console.nextLine();
if (name.isEmpty()) break;
System.out.print("번호를 입력하세요: ");
String phone = console.nextLine();
phonebook.put(name, phone);
}
System.out.println("전화번호부:");
for (var entry : phonebook.entrySet())
{
System.out.println(entry.getKey() + " -> " + entry.getValue());
}
}
}
이 프로그램은 미니 안내서처럼 동작합니다. 이름과 전화번호를 입력하면 HashMap에 저장됩니다. 마지막에 전체 목록을 출력할 수 있습니다. 사전(맵)은 실제 프로젝트에서 매우 자주 사용됩니다.
GO TO FULL VERSION