본문 바로가기
Android/Java

[Java] Map 인터페이스와 HashMap 구분과 Map 인터페이스를 통해 HashMap을 사용하는 것이 좋은 이유

by quessr 2024. 4. 9.

 

 

자바에서 키와 값의 쌍으로 데이터를 관리할 때, Map 인터페이스가 기본적으로 사용된다.

이 인터페이스는 각 키가 고유한 값을 가지도록 보장하며, 이를 통해 데이터를 효율적으로 저장하고 검색할 수 있게 해 준다.

Map 인터페이스의 여러 구현체 중에서도 HashMap 가장 널리 사용되지만, TreeMap이나 LinkedHashMap 같은 다른 구현체들도 특별한 사용 사례와 이점을 제공한다.

Map interface의 구현체들에 대한 내용은 추후에 공부 후 블로깅 해 보겠다.

 

이번 글에서는 특히, Map 인터페이스를 통해 HashMap 사용하는 것이 가지는 이점에 초점을 맞춰 보겠다.

이러한 접근 방식은 자바 프로그래밍에서 데이터를 효율적으로 관리하는 방법에 도움이 될 것 이.

 

HashMap 직접 사용하는 대신 Map 인터페이스를 사용하는 방식을 선호하는 이유는 주로 자바에서 권장하는 프로그래밍 원칙과 설계 원칙 때문이다.

자바에서는 특정 클래스(: HashMap) 직접 사용하기보다는 상위 인터페이스(: Map) 통해 기능을 사용하는 방식을 권장한다. 이유는 다음과 같은 여러 프로그래밍 원칙과 설계 원칙에 기반하기 때문이다.

 

인터페이스 기반 프로그래밍의 장점

 

1. 추상화와 유연성:
Map
인터페이스를 사용함으로써, 실제 구현체가 HashMap인지, TreeMap인지, 혹은 LinkedHashMap인지에 대한 구체적인 정보를  숨긴다.

이러한 추상화는 나중에 다른 종류의 Map 구현체로 쉽게 바꿀 있는 유연성을 제공한다.
예를 들어, 처음에는 삽입 순서가 중요하지 않아 HashMap 사용했지만, 나중에 요소들의 삽입 순서를 유지해야 경우  LinkedHashMap으로 손쉽게 전환할 있다.

 

2. 코드의 유지보수성 향상:
프로그램의 다른 부분이 Map 인터페이스를 통해 데이터를 다루면, 구현체를 변경하더라도 사용하는 코드를 변경할 필요가 없다.

이는 유지보수 시간과 노력을 줄여준다.
구현체 변경이 필요한 경우, 변경이 인터페이스를 사용하는 코드에 영향을 미치지 않으므로, 코드의 안정성이 보장된다.

import java.util.HashMap;
import java.util.Map;
import java.util.TreeMap;

public class MapExample {
    public static void main(String[] args) {
        // Step 1: 인터페이스를 통해 데이터를 다루기 위한 Map 선언, 초기에는 HashMap 사용
        Map<String, Integer> map = new HashMap<>();

        // 데이터 추가
        map.put("사과", 10);
        map.put("바나나", 5);
        map.put("오렌지", 8);

        printMap(map);

        // 요구사항 변경: 키에 따른 정렬이 필요하다고 가정
        // Step 2: TreeMap으로 변경, 인터페이스 사용 코드는 그대로 유지
        map = new TreeMap<>(map);

        // TreeMap으로 변경 후 데이터 출력
        printMap(map);
    }

    // Map을 출력하는 메서드, Map 인터페이스를 사용하기 때문에 구현체가 변경되어도 메서드는 변경할 필요가 없음
    public static void printMap(Map<String, Integer> map) {
        map.forEach((key, value) -> System.out.println(key + ": " + value));
    }
}

 

예시에서 printMap 메서드는 Map 인터페이스를 파라미터로 받기 때문에, 어떤 Map 구현체(HashMap, TreeMap ) 사용하든 메서드 내부 코드를 변경할 필요가 없다.

처음에 HashMap으로 데이터를 저장했을 때와, 요구사항 변경으로 TreeMap으로 바꾸었을 , printMap 메서드는 그대로 사용할 있다. 이처럼 인터페이스를 사용함으로써 코드의 유지보수성이 향상되며, 구현체 변경이 필요한 경우에도 사용하는 코드에 영향을 주지 않아 코드의 안정성을 유지할 있다.


3. 테스트 용이성:

인터페이스를 사용하면, 실제 운영 환경에서는 HashMap 같은 실제 구현체를 사용하고, 테스트 환경에서는 테스트를 용이하게 만들어

주는 커스텀 Map 구현체나 모의 객체(Mock Object) 사용할 있다. 이는 테스트를 보다 쉽고 효과적으로 만들어준다.

 

4. 느슨한 결합(Loose Coupling):
인터페이스를 사용함으로써 구현체에 대한 의존성을 줄이고, 시스템의 다른 부분들 사이의 결합도를 낮출 있다.
이는 전체 시스템의 유연성과 확장성을 향상시키며, 변경 사항이 부분에 국한되어 다른 부분에 영향을 미치게 한.

// HashMap을 직접 사용하는 경우
HashMap<String, Integer> map = new HashMap<>();

// Map 인터페이스를 통해 HashMap을 사용하는 경우
Map<String, Integer> map = new HashMap<>();

 

Map 인터페이스를 사용하는 두 번째 방법은, 필요에 따라 HashMap이 아닌 다른 Map 구현체로 쉽게 교체할 수 있는 유연성을 제공한다. 예를 들어, 요소들의 순서를 유지해야 하는 경우에는 LinkedHashMap으로, 정렬된 순서를 유지해야 하는 경우에는 TreeMap으로 교체가 가능하다.

 

결론적으로, 자바에서는 이러한 다양한 이점을 제공하기 때문에 Map 인터페이스를 직접 사용하는 것을 선호한다.

이는 단순히 HashMap에만 국한된 것이 아니라, 다양한 경우에 인터페이스를 통한 프로그래밍을 권장하는 자바의 일반적인 설계 원칙이다.