Map Collection

hyekyeong Song·2020년 5월 14일
1

Map Collection

Map 컬렉션은 Key와 Value 쌍으로 구성된 Entry객체를 저장한다. 이때, 키와 값은 모두 객체이며 Key는 중복 저장할 수 없다. 만약 기존에 저장되어 있는 Key값으로 새로운 값을 저장하면 기존 값은 없어지고 새로운 값으로 저장된다.
Map Collection의 구현 클래스 : HashMap, Hashtable, LinkedHashMap, Properties, TreeMap, ..

<Map 컬렉션이 공통적으로 사용할 수 있는 Map인터페이스의 메소드>

K, V : 타입 파라미터로 Map 인터페이스가 제네릭 타입이기 때문에 구체적 타입이 구현 객체 생성시 결정됨

1) 객체 추가

  • V put(K key, V value) : 주어진 키와 값을 저장하고, 저장된 값을 리턴

2) 객체 검색

  • boolean containsKey(Object key) : 주어진 키가 있으면 true, 없으면 false리턴
  • boolean containsValue(Object Value) : 주어진 값이 있으면 true, 없으면 flase리턴
  • Set<Map.Entry<K, V>> entrySet() : 키와 값의 쌍으로 구성된 모든 Map.Entry 객체를 Set에 담아 리턴
  • V get(Object key) : 키의 값을 리턴
  • boolean isEmpty() : 컬렉션이 비어있으면 true, 비어있지 않으면 false리턴
  • Set< K> keySet() : 모든 키를 Set 객체에 담아 리턴
  • int size() : 저장된 키의 개수를 리턴
  • Collection< V> values() : 저장된 모든 값을 Collection에 담아서 리턴

3)객체 삭제

  • void clear() : 전체 Map.Entry(키와 값) 삭제
  • V remove(Object key) : 주어진 키와 일치하는 Map.Entry를 삭제하고 값을 리턴

<전체 객체를 대상으로 값을 가져오는 2가지 방법>

1) keySet() 메소드 사용

Set<String> keySet = hashMap.keySet();
Iterator<String> keyIterator = keySet.iterator();
while(keyIterator.hasNext()) {
      String key = keyIterator.next();
      Integer value = hashMap.get(key);
}

2) entrySet() 메소드 사용
Map.Entry를 Set 컬렉션으로 가져와, 반복자를 사용해서 Map.Entry를 하나씩 얻고 키와 값을 얻는다.

Set<Map.Entry<String, Integer>> entrySet = hashMap.entrySet();
Iterator<Map.Entry<String, Integer>> entryIterator = entrySet.iterator();
while(entryIterator.hashNext()) {
	Map.Entry<String, Integer>> entry = entryIterator.next();
   	String key = entry.getKey();
    	Integer value = entry.getValue();
}

HashMap

HashMap에서 동일한 키가 되는 조건은 hashCode()의 리턴값이 동일하고, equals() 메소드가 true이어야 한다.
키 타입으로 String을 사용할 때, 문자열 내용이 같을 경우 동등 객체가 될 수 있도록 hashCode()와 equals() 메소드가 재정의 되어있다.
만일 HashMap의 키로 사용자 객체를 사용할 경우, hashCode()와 equals() 메소드를 재정의해 동등 객체가 될 조건을 정해야 한다.

1) 생성 방법

//K : 키 타입, V : 값 타입
HashMap<K, V> hashMap = new HashMap<K, V>();

이때, K와 V는 primitive type(byte, short, int, bolean, char, ..)을 사용할 수 없으며 클래스 및 인터페이스 타입만 가능하다.

2) 사용 예시

String[] participant 배열에 이름이 String 타입으로저장되어 있다고 할 경우, 이름 당 사람 수를 구하는 코드.

ex) participant = {"Song", "Kim", "Jun", "Kim"};
일 경우 다음과 같이 hashMap을 저장해야 한다.

KeyValue
Song1
Kim2
Jun1
        HashMap<String, Integer> hashMap = new HashMap<String, Integer>();
        int peopleCnt = 0;
        int i;

        //사람들을 이름당 몇명인지로 저장
        for(i=0; i<participant.length; i++) {
            if(hashMap.containsKey(participant[i])) {   //동일한 이름이 있으면
                peopleCnt = hashMap.get(participant[i]);    //기존 몇명인지 알아내고
                //새로운 값으로 저장
                hashMap.put(participant[i], new Integer(peopleCnt+1));
            } else {    //동일한 이름이 아직 없으면
                hashMap.put(participant[i], new Integer(1));
            }
        }
        
        //이름 당 사람의 수를 출력
        Set<String> keySet = hashMap.keySet();
        Iterator<String> keyIterator = keySet.iterator();
        while(keyIterator.hasNext()) {
            String key = keyIterator.next();
            Integer value = hashMap.get(key);
            System.out.println("Key / Value : " + key + " / " + value);
        }

3) 사용자 정의 객체를 키로 사용하는 방법

이름과 나이를 저장하는 Person 객체를 키로하고, 사람 번호를 value로 저장한다.

import java.util.HashMap;

public class HashMapEx {

    public static class Person {
        public String name;
        public int age;

        public Person(String name, int age) {
            this.name = name;
            this.age = age;
        }

        //이름과 나이가 같으면 true를 리턴하도록 재정의
        @Override
        public boolean equals(Object obj) {
            if(obj instanceof Person) {
                Person person = (Person) obj;
                return (this.age == person.age) && (this.name.equals(person.name));
            } else {
                return false;
            }
        }

        //이름과 나이가 같으면 동일한 값을 리턴하도록 재정의
        @Override
        public int hashCode() {
            return name.hashCode() + age;
        }
    }

    public static void main(String[] args) {
        HashMap<Person, Integer> hashMap = new HashMap<Person, Integer>();

        hashMap.put(new Person("김김김", 24), 1);
        hashMap.put(new Person("김김김", 24), 1);

        System.out.println("Entry 수 : " + hashMap.size());
    }
}

출력 = Entry 수 : 1


Hashtable

HashMap과 동일한 내부 구조를 가지고 있으므로 키로 사용할 객체는 hashCode()와 equals() 메소드를 재정의해 동등 객체가 될 조건을 정해야 한다.

1) 특징

  • Synchronized(동기화된) method : 멀티 스레드가 동시에 이 메소드들을 실행 할 수 없고, 하나의 스레드가 실행을 완료해야 다른 스레드를 실행할 수 있다. 따라서 멀티 스레드 환경에서 안전히 객체를 추가/삭제할 수 있다. -> Thread safe(스레드 안전)

2) 생성 방법

Hashtable<K, V> hashtable = new HashTable<K, V>();

3) 예제 코드

키보드로 아이디와 비밀번호를 입력받아, Hashtable에 저장되어 있는 키(아이디)와 값(비밀번호)를 비교한 후 로그인 여부를 출력

import java.util.Hashtable;
import java.util.Scanner;

public class HashtableEx {
    public static void main(String[] args) {
        Hashtable<String, String> hashtable = new Hashtable<String, String>();

        hashtable.put("apple", "123");
        hashtable.put("grape", "1234");
        hashtable.put("strawberry", "12345");

        Scanner scanner = new Scanner(System.in);

        while(true) {
            System.out.println("아이디와 비밀번호 입력하세요");
            System.out.print("아이디 : ");
            String id = scanner.nextLine();

            System.out.print("비밀번호 : ");
            String password = scanner.nextLine();
            System.out.println();

            if (hashtable.containsKey(id)) {
                if (hashtable.get(id).equals(password)) {
                    System.out.println("로그인 되었습니다.");
                    break;
                } else {
                    System.out.println("비밀번호가 일치하지 않습니다.");
                }
            } else {
                System.out.println("아이디가 존재하지 않습니다.");
            }
        }
    }
}

실행결과

아이디와 비밀번호 입력하세요
아이디 : apple
비밀번호 : 123

로그인 되었습니다.


Properties

Properties는 Hashtable의 하위 클래스로 Hashtable의 모든 특징을 가진다. 반면 Properties는 키와 값을 String 타입으로 제한한 컬렉션이며 애플리케이션의 옵션 정보, 데이터베이스의 연결 정보, 국제화(다국어) 정보가 저장된 (~.properties) 파일을 읽을 때 주로 사용한다.
프로퍼티 파일은 키와 값이 = 기호로 연결되어 있는 텍스트 파일로 ISO 8859-1 문자셋으로 저장되며, 이 문자셋으로 직접 표현할 수 없는 한글은 유니코드로 변환돼 저장된다.

프로퍼티 파일 읽는 방법
Properties 객체를 생성하고, load() 메소드를 호출한다.
load() 메소드는 프로퍼티 파일로부터 데이터를 읽기 위해 FileReader 객체를 파라미터로 받는다.

Properties properties = new Properties();
properties.load(new FileReader("C:/~/database.properties"));

Properties 객체에서 키의 값을 읽는 방법
Properties 객체에서 해당 키의 값을 읽으려면 getProperty() 메소드를 사용한다.

String value = properties.getProperty("key");

TreeMap

TreeMap은 이진 트리를 기반으로 한 Map 컬렉션이다.

1) 특징

: TreeMap은 키와 값이 저장된 Map.Entry를 저장한다. 저장 시, 키 값을 기준으로 자동 정렬해 저장하는데 부모 키값을 기준으로 키 값이 낮은(작은) 것은 왼쪽 자식에, 키 값이 높은(큰) 것은 오른쪽 자식 노드에 저장한다.
따라서 특정 객체를 찾거나 범위 검색 시 매우 유용하다.

2) TreeMap의 검색 관련 메소드

Return typeMethod설명
Map.Entry<K, V>firstEntry()제일 낮은(작은) Map.Entry 리턴
Map.Entry<K, V>lastEntry()제일 높은(큰) Map.Entry 리턴
Map.Entry<K, V>lowerEntry(K key)주어진 키보다 바로 아래의 Map.Entry 리턴
Map.Entry<K, V>higherEntry(K key)주어진 키보다 바로 위 Map.Entry 리턴
Map.Entry<K, V>floorEntry(K key)주어진 키와 같은 키가 있으면 해당 Map.Entry를 리턴하고, 없으면 주어진 키 바로 아래의 Map.Entry를 리턴
Map.Entry<K, V>ceilingEntry(K key)주어진 키와 같은 키가 있으면 해당 Map.Entry를 리턴하고, 없으면 주어진 키 바로 위의 Map.Entry를 리턴
Map.Entry<K, V>pollFirstEntry()제일 낮은 Map.Entry를 꺼내고 컬렉션에서 제거
Map.Entry<K, V>pollLastEntry()제일 높은 Map.Entry를 꺼내고 컬렉션에서 제거

2) 정렬 관련 메소드

Return typeMethod설명
NavigableSet< K>descendingKeySet()내림차순으로 정렬된 키의 NavigableSet 리턴
NavigableMap<K, V>descendingMap()내림차순으로 정렬된 Map.Entry의 NavigableMap을 리턴

만일 오름차순으로 정렬하고 싶을 경우 descendingMap() 메소드를 두 번 호출해서 사용할 수 있다.

NavigableMap<K, V> descendingMap = treeMap.descendingMap();
NavigableMap<K, V> ascendingMap = descendingMap.descendingMap();

3) 범위 검색 관련 메소드

  • 주어진 키보다 낮은 Map.Entry들을 NavigableMap으로 리턴한다.
NavigableMap<K, V> headMap(K toKey, boolean inclusive)

inclusive가 true일 경우 : 찾는 Map.Entry <= 끝 Map.Entry
inclusive가 flase일 경우 : 찾는 Map.Entry < 끝 Map.Entry

  • 주어진 키보다 높은 Map.Entry들을 NavigableMap으로 리턴한다
NavigableMap<K, V> tailMap(K fromKey, boolean inclusive)

inclusive가 true일 경우 : 시작 Map.Entry <= 찾는 Map.Entry
inclusive가 flase일 경우 : 시작 Map.Entry < 찾는 Map.Entry

  • 시작과 끝으로 주어진 키 사이의 Map.Entry들을 NavigableMap으로 리턴한다.
NavigableMap<K, V> subMap(K fromKey, boolean fromInclusive, K toKey, boolean toInclusive)

fromInclusive : true일 경우 시작 Map.Entry 포함
toInclusive : true일 경우 끝 Map.Entry 포함

profile
안녕하세요😀😀

0개의 댓글