Difference Between a HashMap and a Dictionary in Java
1. 개요
Java 개발자들은 키-값 쌍 데이터 구조에서HashMap과 Dictionary를 자주 접하게 됩니다. 처음에는 두 개가 서로 바꿔 사용할 수 있는 것처럼 보일 수 있지만, 설계, 성능 및 현대 Java 관행과의 호환성에서 중요한 차이점이 있습니다.
이 튜토리얼에서는 이러한 차이점을 깊이 탐구하고 각 요소를 언제, 왜 사용해야 하는지 명확히 설명하겠습니다.
2. 소개
HashMap과 Dictionary에 대한 간단한 소개로 시작하겠습니다.
2.1. HashMap
HashMap은 Java 2에서 도입되었습니다. Java Collections Framework(JCF)의 일부로, 키-값 쌍을 저장하기 위한 매우 효율적이고 유연한 구현입니다. HashMap은 null 키와 값을 지원하여 현대 애플리케이션에 유용합니다. 이후 섹션에서 이에 대해 더 배울 것입니다.
2.2. Dictionary
Java 1.0의 유물인 Dictionary는 키-값 쌍 저장을 위한 추상 클래스입니다. 초기 Java 프로그램에 기초를 제공했지만, 이제는 구식으로 간주되어 레거시 시스템을 제외하고는 거의 사용되지 않습니다. Collections Framework과 통합되지 않으며 제네릭와 같은 현대적 기능이 부족합니다.
3. 널 처리
가장 눈에 띄는 차이점 중 하나는 null 값을 처리하는 방법입니다. 개발자들은 보통 NullPointerException를 접하게 되므로, Java에서 이를 처리하는 방법을 이해하는 것이 중요합니다. 따라서 HashMap과 Dictionary가 NullPointerException을 처리하는 방식을 살펴보겠습니다.
3.1. HashMap
HashMap에서는 하나의 null 키와 여러 개의 null 값을 가질 수 있습니다. 이 기능은 누락되거나 정의되지 않은 값을 표현해야 하는 상황에 적합합니다.
예를 들어:
HashMap<String, String> map = new HashMap<>();
map.put(null, "NullKeyValue");
map.put("Key1", null);
3.2. Dictionary
Dictionary에서는 null 키와 null 값이 허용되지 않으며, 대부분의 구현(예: Hashtable)에서는 이를 삽입하려고 시도할 때 NullPointerException을 발생시킵니다.
예를 들어:
Dictionary<String, String> dictionary = new Hashtable<>();
dictionary.put(null, "NullKey");
여기서 dictionary.put(null, “NullKey”)는 NullPointerException을 발생시키며, 우리는 null 키나 값을 만날 가능성이 있는 경우 Dictionary를 사용해서는 안 됩니다.
4. 스레드 안전성
스레드 안전성은 멀티스레딩을 다룰 때 또 다른 중요한 개념입니다. 이 섹션에서는 HashMap과 Dictionary가 어떻게 동작하는지 살펴보겠습니다.
4.1. HashMap
HashMap은 기본적으로 동기화되지 않으므로 단일 스레드 환경에서 더 빠릅니다. 스레드 안전성이 필요할 경우, 가장 먼저 사용할 수 있는 방법은 Collections.synchronizedMap()를 사용하는 것입니다:
Map<String, String> synchronizedMap = Collections.synchronizedMap(new HashMap<>());
또 다른 방법은 ConcurrentHashMap을 사용하는 것으로, 이것은 동시 환경에서 더 나은 성능을 제공하는 스레드 안전한 대안입니다.
4.2. Dictionary
Dictionary는 기본적으로 동기화되어 있지만, 이로 인해 성능 비용이 발생합니다. 현대 멀티스레드 애플리케이션에서는 ConcurrentHashMap이 더 나은 선택입니다.
5. 제네릭 지원
5.1. HashMap
HashMap은 제네릭을 완전히 지원하여 타입 안전성을 보장하고 명시적 캐스팅의 필요성을 없앱니다. 이 기능은 런타임 오류를 줄이고 코드 가독성을 개선합니다.
HashMap을 제네릭과 함께 사용하는 방법은 다음과 같습니다:
Map<Integer, String> map = new HashMap<>();
map.put(1, "One");
String value = map.get(1);
HashMap에서 값을 가져오기 위해 캐스팅이 필요하지 않습니다.
5.2. Dictionary
Dictionary는 제네릭이 없기 때문에 Java 5 이전에 도입되었습니다. 값을 가져올 때마다 명시적으로 캐스팅해야 하므로 런타임 오류의 가능성이 높아집니다.
예를 들어:
Dictionary dictionary = new Hashtable();
dictionary.put(1, "One");
String value = (String) dictionary.get(1);
따라서 위 코드에서 보듯이, Dictionary에서 값을 얻기 위해 데이터 타입을 명시적으로 캐스팅해야 합니다.
6. 결론
이 글에서는 HashMap과 Dictionary 사이에 현명한 선택이 있음을 확인했습니다. 현대 Java 개발에서는 HashMap이 명확한 승자입니다. 더 빠르고, 유연하며, 제네릭 및 null 값 지원과 같은 더 나은 기능을 제공합니다.
Dictionary는 Java의 역사에서 그 자리를 차지하고 있지만, 오래된 코드베이스에서 작업하는 경우를 제외하고는 과거에 두는 것이 가장 좋습니다. 다음에 키-값 쌍 데이터 구조를 선택해야 할 때, 우리는 어떤 것을 선택해야 할지 알게 되었습니다!
이 글에 제시된 코드는 GitHub에서 확인하실 수 있습니다.