개발/Spring

자바 컬렉션 Map

728x90

자바에서 MAp은 키과 밸류로 이뤄져 있다.

 

Map에서 다른 데이터와 구분하기 위한 값의 이름을 키라고 한다.

 

키과 밸류가 1:1로 저장된다., 그런데 이 키는 해당 Map에서 중복되지 않는다. 만약 키가 다르고, 값이 동일하다면 맵에서는 다른 것으로 간주한다.

 

 

  1. 모든 데이터는 키와 밸류가 존재한다.
  2. 키가 없이 값만 저장될 수 없다.
  3. 값 없이 키만 저장할 수도 없다.
  4. 키는 해당 Map에서 고유해야만 한다
  5. 값은 Map에서 중복되어도 전혀 상관 없다. 

 

Map은 java.util패키지의 Map이라는 인터페이스로 선언되어 있고, 구현해 놓은 클래스들도 많이 있다.

 

  • put : 데이터를 넣을 때
  • get : 데이터를 확인할 때
  • remove : 데이터를 삭제할 때

Map을 구현한 주요 클래스들을 살펴보자

 

Map인터페이스를 구현한 클래스들은 매우 다양하고 많다. 그 중에서 HashMap, TreeMap, LinkedHashMap 등이 가장 유명하고, 개발자들이 애용하는 클래스이다. 그리고 Hashtable이라는 클래스도 있다.

 

Hashtable클래스는 Map 인터페이스를 구현하기는 했지만 일반적인 Map인터페이스를 구현한 클래스들과는 다르다. 이 두 종류의 다른 점을 간단하게 정리하면 아래와 같다

 

  • Map은 컬렉션 뷰를사용하지만, Hashtable은 Enumeration 객체를 통해서 데이터를 관리한다.
  • Map은 키, 값, 키-값 쌍으로 데이터를 순환하여 처리할 수 있지만, Hashtable은 이 중에서 키-값 쌍으로 데이터를 순환하여 처리할 수 없다.
  • Map은 이터레이션을 처리하는 도중에 데이터를 삭제하는 안전한 방법을 제공하지만, Hashtable은 그러한 기능을 제공하지 않는다.

Map 인터페이스와 Hashtable 클래스의 차이는 이 정도다,

그런데, HashMap 클래스와 Hashtable 클래스는 다음과 같으 ㄴ차이가 있다.

 

키나 값에 Null 저장 가능 여부 : HashMap 가능, HashTable 불가능

여러 쓰레드 안전 여부 : HashMap 불가능, HashTable 가능

 

왜 이러한 차이가 발생했을까 ? 자바에 Colllection이라는 인터페이스가 추가된 것은 1.2 부터다, 따라서 HashMap과 TreeMAp이라는 클래스도 이때 만들어져 사용되고 있다. 게다가, LinkedHashMap이라는 클래스는 1,4에서 추가되었다. 그런데 HashTable이라는 클래스는 1.0부터 만들어져 사용된 클래스이기 때문에 Map 인터페이스의 기능을 구현한 것은 JDK 1.2부터이다. 즉 만들어진 Map에 맞추어 보완되었다고 보면 된다.

 

하지만 중요한 것은 각 클래스의 특징이다. 어떤 작업을 할 때 어떤 클래스가 더 유리한지를 알고 사용하는 것이 더 중요하다. 특히, 이 장에서 소개된 클래스 중에서 HashTable을 제외한 Map으로 끝나는 클래스들은 여러 쓰레드에서 동시에 접근하여 처리할 필요가 있을 때에는 다음과 같이 사용해야만 한다.

 

Collections.synchronizedMap

 

추가로 자바 기본 API 중에서 JDK 1.0부터 제공되는 HashTable, Vector는 클래스가 쓰레드에 안전하게 개발되어 있다. 그외에 1.2 부터 제고오디는 대부분의 Collection 관련 클래스들은 이와 같은 처리를 해야하거나 이름에 Concurrent가 포함되어 있어야만 쓰레드에 안전하게 사용할 수 있다. 그리고 이러한 처리가 필요한 클래스의 API에는 반드시 관련 설명이 제공되므로 API를 참고하는 습관을 드리도록 하자.

 

예를 들면 1.5에서 추가된 ConcurrentHashMap, CopyOnWirteArrayList 등이 있으며, java.util.concurrent 패키지 소속이다.

 

 

 

HashMAp 클래스는 다음과 같은 상속 관계를 갖는다

 

java.lang.Object

java.util.AbstractMap<K,V>

java.util.HashMAp<K,V>

 

AbstractMap 이라는 abstract 클래스를 확장했으며, 대부분 주요메소드는 AbstractMap 클래스가 구현해 놓았다.

 

Serialzable -> 원격으로 객체를 전송하거나 파일을 저장할 수 있음을 지정

Cloneable -> Object 클래스의 clone)0 메소드가 제대로 수행될 수 있음을 지정, 즉, 복제가 가능한 객체임을 의미한다.

Map<E> -> 맵의 기본 메소드를 지정

 

지금까지 살펴본 셋, 큐에 비하면 매우 간단하게 되어 있다. 

 

 

 

HashMap을 위한 생성자는 4개가 있다.

 

HashMap -> 16개의 저장 공간을 갖는 객체는 생성한다.

HashMap int initalCapacity 매개 변수만큼의 저장공간을 갖는 객체를생성한다.

HashMap int initalCapacity, float loadFactor 첫 매개ㅂㄴ수의 저장공간을 갖고, 두 번째 매개변수의 로드팩터를 갖는 객체를 생성한다 

HashMap Map<?extends K, ?extends V> m -> 매개변수로 넘어온 Map을 구현한 객체에 있는 데이터를 갖는 객체를 생성한다.

 

대부분 객체를 생성할 때 매개변수가 없는 생성자를 사용한다. 하지만, HashMap에 담을 데이터의 갯수가 많은 경우에는 초기 크기를  지정 해주는 것을 권장한다.

 

 

추가로 키가 HashMap의 객체를 직접 만들었을 때에는 유의해야할 점이 있다. 키에 들어가는 값은 기본 자료형과 참조 자료형이 모두 될 수 있다.

 

그래서 보통 int나, long과 같은 숫자나 String 클래스를 키로 많이 사용한다.

 

 

어떤 클래스를 만들어 그 클래스를 키로 사용할 때에는 Object 클래스의 hashCode() 메소드와 equals()메소드를 잘 구현해 놓아야만 한다.

 

HashMap에 객체가 들어가면 hashCode(객체의 유일한 int 값을 리턴하는 함수) 메소드의 결과 값에 따른 버킷이라는 목록 형태의 바구니가 만들어진다. 만약 서로 다른 키가 저장되었는데, hashCode 메소드의 결과가 동일하다면 이 버켓에 여러 개의 값이 들어갈 수 있다.

 

따라서 get 메소드가 호출되면 hashCode의 결과를 확인하고, 버켓에 들어간 목록에 데이터가 여러개일 경우 equals 메소드를 호출하여 동일한 값을 찾게 된다.  따라서 키가 되는 객체를 직접 작성할 때에는 개발툴에서 제공하는 hashCode, equals를 자동 생성해주는 기능을 사용하여 해당 메소드를 꼭 구현해놓도록 하자.

 

 

HashMap에 있는 주요 메소드는 대부분 Map인터페이스에 정의 되어 있다.

 

Collection에 데이터를 추가하는 것은 add메소드이다. 말 그대로 데이터가 추가되어서 add이다. 하지만 맵에서는 추가한다고 표현을 안하고 데이터를 넣는다고 표현한다. 따라서 put이라는 메소드를 사용한다 

 

 

ArrayList 클래스는 추가할 때 add, 수정할 때에는 set을 사용했다. 하지만 HashMap과 같은 Map 관련 클래스에서는 새로운 값을 추가하거나, 기존 값을 수정할 때 모두 put 메소드를 사용한다.

 

 

HashMap 객체의 값을 확인하는 다른 방법들을 알아보자.

 

어떤 키가 들어있는지 확인하려면 어떻게 해야할까? 그럴 때에는 keySet()이라는 메소드를 사용하면 된다. get 이라는 데이터를 조회하는 메소드를 사용하려면 어떤 키들이 있는지 확인해야 하므로 Map을 사용할 때에는 이 메소드를 꼭 알고 있어야만 한다. 메소드 이름에서 알 수있듯이 keySet의 리턴 타입은 set이다.

 

Set의 제네릭 타입은 키의 제네릭 타입과 동일하게 지정해주면 된다.

 

 

자바의 자료 구조 중에서 젖아순서가 중요한 것은 List와 Queue 뿐이다. Set, Map은 데이터 추가 순서는 중요하지 않다.

 

Set은 데이터가 중복되지 않는 것이 중요하고, Map은 키가 중복되지 않는 것이 중요하다. 따라서 데이터를 저장한 순서대로 결과가 출력되지는 않는다.

 

값들 만 가져올 대는 values라는 메소드를 통해 Collection 타입의 목록으로 리턴해준다. 

 

Map에 저장되어 있는 모든 값을 출력할 때에는 values메소드를 사용하는 것이간편하다. 

 

이렇게 데이터를 꺼내는 방법 외에는 entrySet이라는 메소드를 사용할 수도 있다. 메소드를 사용하면 Map에 선언된 Entry 라는 타입의 객체를 리턴한다. 이 Entry에는 단 하나의 키와 값만이 저장된다. 

 

위처럼 Map에서 데이터를 꺼낼 때에는 목적에 맞는 메소드를 적절히 선택하는 것이 중요하다. 이번에는 Map에 어떤 키나 값이 존재하는 지를 containsKey()와 containsValue() 메소드에 대해서 알아보자

 

그냥 존재 여부를 확인하고 싶을 때에는 위 메소드가 효과적이다.

 

 

정렬된 키의 목록을 원한다면 TreeMap을 사용하자.

 

이 클래스는 저장하면서, 키를 정렬한다. 정렬되는 기본적인 순서는 숫자 > 알파벳 대문자 > 알파벳 소문자 > 한글 순이다.

 

이 순서는 String과 같은 문자열이 저장되는 순서를 말하는 것이며, 객체가 저장되거나 숫자가 저장될 때에는 그 순서가 달라진다.

 

매우 많은 데이터를 저장할 때에는 HashMap보다는 느릴 것이다. 왜냐하면 키가 정렬되기 때문이다.

 

100, 1000건 정도이고 정렬할 필요가 있다면 TreeMap을 사용하는 것이좋다.

 

TreeMap이 키를 정렬하는 것은 SortedMap이라는 인터페이스를 구현했기 때문이다.

 

SortedMap은 모두 키가 정렬되어있어야만 한다. 키가 정렬되어 있을 때의 장점은 가장 앞에 있는 키, 가장 뒤에 있는 키 특정 키 뒤에 있는 키, 앞에 있는키 등을 알 수 있는 메소드를 제공해 준다는 것이다. 

 

Map을 구현한 Properties 클래스는 알아두면 편리하다.

 

System 클래스에 , Properties라는 클래스가 있다.

 

이 클래스는 HashTable을 확장하였다. 따라서 Map 인터페이스에서 제공하는 모든 메소드를 이용할 수 있다. 기본적으로 자바에서는 시스템의 속성을 이 클래스를 사용하여 제공한다.

 

 

 

System 클래스는 static으로 선언되어 있는 getProperties 메소드를 호출하면 Properties 타입의 객체를 리턴한다.

 

Properties 클래스의 객체에 시스템 속성만 지정할 수 있는 것은 아니다. 앱에서 사용할 여러 속성값들을 Properties 클래스를 사용하여 데이터를 넣고, 빼고, 저장하고, 읽어드릴 수 있다. 만약 이 클래스가 없다면, 직접 파일을 읽고 메소드를 만들고 파일에 쓰는 메소드도 만들어야만 한다.

 

 

정리하자면 Collection을 구현한 것은 List, Set, Queue이며, Map은 별도의 인터페이스로 되어 있다.

 

배열 처럼 목록을 처리하기 위한 List의 대표적인 클래스로는 ArrayList, LinkedList가 있고 보통은 ArrayList를 많이 사용한다.

 

List 처럼 목록을 처리하기는 하지만, 데이터의 중복은 없고 순서가 필요없는 Set의 대표적인 클래슨느 HashSet, TreeSet,LinkedHashSet이 있다.

 

데이터가 들어온 순서대로 처리하기 위해서 사용하는 Queue의 대표적인 클래스는 LinkedList, PrioitryQueue 등이 있으며, LinkedList는 List에도 속하고 Queue에도 속하는 특이한 클래스이다.

 

Map의 대표적인 클래스에는 HashMAp, TreeMap, LinkedHashMap이 있으며, 사용 용도에 따라 다르지만 보통 HashMap을 사용한다.

 

키의 목록은 keySet로 Set타입의 데이터를 얻을 수 있고, 값 목록은 values메소드를 통해서 Collection의 타입의 데이터를 얻을 수 있다.

 

데이터를 처리하기 위해서는 for 루프를 사용할 수 있지만, iterator 메소드를 통하여 Iterator 객체를 얻어 각 데이터를 처리할 수도 있다.

 

 

어떤 클래스는 보다 빠르게 데이터를 처리할 수 있지만, 여러 쓰레드에서 접근할 때 안전하지 않고, 어떤 클래스는 그와 반대인 경우도 있다. 따라서 용도에 맞는 클래스를 선택하는 것은 매우 중요하다.

 

 

'개발 > Spring' 카테고리의 다른 글

자바 배열  (0) 2021.04.05
자바 소켓  (0) 2021.03.21
자바 문자열 String  (0) 2021.03.18
자바 컬렉션 Set  (0) 2021.03.15
스프링 입문을 위한 자바 객체지향 원리와 이해 - 1장  (0) 2021.03.15