ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [Java] 컬렉션 프레임워크 - Map 컬렉션
    CSE/Java 2015. 9. 13. 16:30


    컬렉션 프레임 워크는 여러 절로 구성되어 있습니다.



    Intro

    List 컬렉션

    Set 컬렉션

    Map 컬렉션

    검색 기능을 강화시킨 컬렉션

    LIFO와 FIFO 컬렉션

    동기화 & 병렬처리를 위한 컬렉션




    4. Map 컬렉션

     Map 컬렉션은 키(key)와 값(value)으로 구성된 Entry 객체를 저장하는 구조를 가지고 있습니다.


     여기서 키와 값은 모두 객체입니다. 키는 중복될 수 없지만 값은 중복 저장될 수 있습니다.


     만약 기존에 저장된 키와 동일한 키로 값을 저장하면 기존의 값은 없어지고 새로운 값으로 대치됩니다.




     




     Map 컬렉션에는 HashMap, Hashtable, LinkedHashMap, Properties, TreeMap 등이 있습니다.


     다음은 Map 컬렉션에서 공통적으로 사용 가능한 Map 인터페이스의 메소드들입니다. 키로 객체들을 관리하기 때문에 키를 파라미터로 갖는 메소드가 많습니다.








     위 표에서 메소드의 매개 변수 타입과 리턴 타입에 K와 V라는 타입 파라미터가 있는데, 이것은 Map 인터페이스가 제네릭 타입이기 때문입니다. 


     앞에서도 언급했듯이 구체적인 타입은 구현 객체를 생성할 때 결정됩니다.


     객체 추가는 put() 메소드를 사용하고, 키로 객체를 찾아올 때에는 get() 메소드를 사용합니다. 



    1
    2
    3
    4
    5
    6
    7
    Map<String, Integer> map = ...;
     
    map.put("Jackie"30);
    int score = map.get("Jackie");
     
    map.remove("Jackie");
     
    cs



     키를 알고 있다면 get() 메소드로 간단하게 객체를 찾아오면 되지만, 저장된 전체 객체를 대상으로 하나씩 얻고 싶을 경우에는 두 가지 방법을 사용할 수 있습니다.


     첫 번째는 keySet() 메소드로 모든 키를 Set 컬렉션으로 얻은 다음, 반복자를 통해 키를 하나씩 얻고 get() 메소드를 통해 값을 얻으면 됩니다.



    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    Map<K, V> map = ~;
     
    Set<K> keySet = map.keySet();
    Iterator<K> it = keySet.iterator();
     
    while (it.hasNext()) {
        K key = it.next();
        V value = map.get(key);
    }
     
    cs



      두 번째 방법은 entrySet() 메소드로 모든 Map.Entry를 Set 컬렉션으로 얻은 다음, 반복자를 통해 Map.Entry 객체를 하나씩 얻고 getKey()와 getValue() 메소드를 이용해 키와 값을 얻으면 됩니다.



    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    Set<Map.Entry<K, V>> entrySet = map.entrySet();
     
    Iterator<Map.Entry<K, V>> entryIt = entrySet.iterator();
     
    while (entryIt.hasNext()) {
        Map.Entry<K, V> entry = entryIt.next();
     
        K key = entry.getKey();
        V value = entry.getValue();
    }
     
    cs



     



     4.1 HashMap

      HashMap은 Map 인터페이스를 구현한 대표적인 Map 컬렉션입니다.


      HashMap의 키로 사용할 객체는 hashCode()와 equals() 메소드를 재정의해서 동등 객체가 될 조건을 정해야 합니다.


      동등 객체, 즉 동일한 키가 될 조건은 hashCode()의 리턴값이 같아야 하고, equals() 메소드가 true를 리턴해야 합니다.


      주로 키 타입은 String을 많이 사용하는데, String은 문자열이 같을 경우 동등 객체가 될 수 있도록 hashCode()와 equals() 메소드가 재정의되어 있습니다. HashMap을 생성하기 위해서는 키 타입과 값 타입을 파라미터로 주고 기본 생성자를 호출하면 됩니다.










      키와 값의 타입은 기본 타입(byte, short, int, float, double, boolean, char)을 사용할 수 없고 클래스 및 인터페이스 타입만 가능합니다.









      다음 예제는 이름을 키로, 점수를 값으로 저장하는 HashMap 사용 방법을 보여줍니다.



      * HashMapExam.java


    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
     
    package set;
     
    import java.util.HashMap;
    import java.util.Iterator;
    import java.util.Map;
    import java.util.Set;
     
    public class HashMapExam {
     
        public static void main(String[] args) {
            Map<String, Integer> map = new HashMap<String, Integer>();
            
            map.put("Jack"30);
            map.put("Andy"40);
            map.put("John"22);
            map.put("Jolie"10);
            map.put("Exo"50);
            map.put("Tiger"91);
            
            System.out.println("총 Entry 수: " + map.size());
            
            System.out.println("\tJolie" + map.get("Jolie"));
            System.out.println();
            
            // 객체를 하나씩 처리
            Set<String> keySet = map.keySet();
            Iterator<String> it = keySet.iterator();
            
            while (it.hasNext()) {
                String key = it.next();
                Integer value = map.get(key);
                System.out.println("\t" + key + " : " + value);
            }
            
            System.out.println();
            
            // 객체 삭제
            map.remove("Exo");
            System.out.println("총 Entry 수: " + map.size());
            
            map.clear();
            System.out.println("총 Entry 수: " + map.size());
        }
     
    }
     
    cs











     

      다음 예제는 사용자 정의 객체인 Student를 키로하고 점수를 저장하는 HashMap 사용 방법을 보여줍니다.




      * Student.java


    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
     
    package set;
     
    public class Student {
        public int sno;
        public String name;
     
        public Student(int sno, String name) {
            super();
            this.sno = sno;
            this.name = name;
        }
     
        @Override
        public boolean equals(Object obj) {
            if (obj instanceof Student) {
                Student std = (Student) obj;
     
                return (sno == std.sno) && (name == std.name);
            } else {
                return false;
            }
        }
     
        @Override
        public int hashCode() {
            return sno + name.hashCode();
        }
     
    }
     
    cs






      * HashMapExam2.java



    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
     
    package set;
     
    import java.util.HashMap;
    import java.util.Map;
     
    public class HashMapExam2 {
     
        public static void main(String[] args) {
            Map<Student, Integer> map = new HashMap<Student, Integer>();
     
            map.put(new Student(1"Jolie"), 100);
            map.put(new Student(1"Jolie"), 100);
     
            System.out.println("총 Entry 수: " + map.size());
        }
     
    }
     
    cs












     4.2 Hashtable

      Hashtable은 HashMap과 동일한 내부 구조를 가지고 있습니다.


      Hashtable도 키로 사용할 객체는 hashCode()와 equals() 메소드를 재정의해서 동등 객체가 될 조건을 정해야 합니다.


      HashMap과의 차이점은 Hashtable은 동기화된(Synchronized) 메소드로 구성되어 있기 때문에 멀티 스레드가 동시에 이 메소드들을 실행할 수는 없고, 하나의 스레드가 실행을 완료해야만 다른 스레드를 실행할 수 있습니다.


      그래서 멀티 스레드 환경에서 안전하게 객체를 추가, 삭제할 수 있습니다.




     








      Hashtable의 생성 방법은 HashMap과 크게 다르지 않습니다. 키 타입과 값 타입을 지정하고 기본 생성자를 호출하면 됩니다.







      다음은 키보드로 아이디와 비밀번호를 입력받아서, Hashtable에 저장되어 있는 키(아이디)와 값(비밀번호)으로 비교한 후 로그인 여부를 출력하는 예제입니다.



      * HashtableExam.java


    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    package set;
     
    import java.util.Hashtable;
    import java.util.Map;
    import java.util.Scanner;
     
    public class HashtableExam {
     
        public static void main(String[] args) {
            Map<StringString> map = new Hashtable<StringString>();
     
            map.put("ABC""123");
            map.put("DEF""456");
            map.put("GHI""789");
     
            Scanner scan = new Scanner(System.in);
     
            while (true) {
                System.out.println("아이디와 비밀번호를 입력해주세요.");
                System.out.print("아이디: ");
                String id = scan.nextLine();
     
                System.out.print("비밀번호: ");
                String pwd = scan.nextLine();
                System.out.println();
     
                if (map.containsKey(id)) {
                    if (map.get(id).equals(pwd)) {
                        System.out.println("로그인되었습니다.");
                        break;
                    } else {
                        System.out.println("비밀번호가 일치하지 않습니다.");
                    }
                } else {
                    System.out.println("입력하신 아이디가 존재하지 않습니다.");
                }
            }
     
            scan.close();
        }
     
    }
     
     
    cs












     4.3 Properties

      properties는 Hashtable의 하위 클래스이기 때문에 Hashtable의 모든 특징을 그대로 가지고 있습니다.


      차이점은 Hashtable은 키와 값을 다양한 타입으로 지정이 가능한데 비해 Properties는 키와 값을 String 타입으로 제한한 컬렉션입니다.


      Properties는 애플리케이션의 옵션 정보, 데이터베이스 연결 정보 그리고 국제화(다국어) 정보가 저장된 프로퍼티(*.properties) 파일을 읽을 때 주로 사용합니다.


      프로퍼티 파일은 키와 값이 = 기호로 연결외어 있는 텍스트 파일로 ISO 8859-1 문자셋으로 저장됩니다.


      이 문자셋으로 직접 표현할 수 없는 한글은 유니코드로 변환되어 저장됩니다.


      다음은 데이터베이스 연결 정보가 있는 프로퍼티 파일의 내용을 보여줍니다. driver, url, username, password는 키가 되고 그 뒤의 문자열은 값이 됩니다.


    1
    2
    3
    4
    5
     
    driver=oracle.jdbc.OracleDriver
    url=jdbc:oracle:thin:@localhost:1521:orcl
    username=scott
    password=tiger
    cs





      프로퍼티 파일을 읽기위해서는 Properties 객체를 생성하고, load() 메소드를 호출하면 됩니다.


      load()메소드는 프로퍼티 파일로부터 데이터를 읽기 위해 FileReader 객체를 파라미터로 받습니다.


      

    1
    2
    3
    4
    5
    Properties properties = new Properties();
     
    properties.load(new FileReader("C:/~/database.properties"));
     
     
    cs





      프로퍼티 파일은 일반적으로 클래스 파일(*.class)과 함께 저장됩니다. 클래스 파일을 기준으로 상대 경로를 이용해서 프로퍼티 파일을 얻으려면 Class의 getResource() 메소드를 이용하면 됩니다.


      getResource() 는 주어진 파일의 상대 경로를 URL 객체로 리턴하는데, URL의 getPath()는 파일의 절대 경로를 리턴합니다. 다음은 클래스 파일과 동일한 위치에 있는 "database.properties" 파일을 읽고 Properties 객체를 생성하는 코드입니다.


    1
    2
    3
    4
    5
    6
    7
    8
    String path = PropertiesExam.class.getResource("database.properties").getPath();
     
    path = URLDecoder.decode(path, "utf-8");
     
    Properties properties = new Properties();
     
    properties.load(new FileReader(path));
     
    cs


     

      만약 다른 패키지에 프로퍼티 파일이 있을 경우에는 경로 구분자 "/"를 사용합니다. 예를 들어, A.class가 com.mycompany 패키지에 있고, database.properties 파일이 com.mycompany.config 패키지에 있을 경우 프로퍼티 파일의 절대 경로를 다음과 같이 얻을 수 있습니다.


    1
    2
    String path = A.class.getResource("config/database.properties").getPath();
     
    cs




      Properties 객체에서 해당 키의 값을 얻으려면 getProperty() 메소드를 사용합니다. 


      물론 Properties 객체도 Map 컬렉션이므로 get() 메소드로 값을 얻을 수 있습니다. 그러나 get() 메소드는 값을 Object 타입으로 리턴하므로 강제 타입 변환해서 얻어야 하기 때문에 일반적으로 getProperty()를 사용합니다.



      다음은 database.properties 파일로부터 값을 읽어 출력하는 예제입니다.


     

      * PropertiesExam.java



    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
     
    package set;
     
    import java.io.FileReader;
    import java.net.URLDecoder;
    import java.util.Properties;
     
    public class PropertiesExam {
     
        public static void main(String[] args) throws Exception {
            Properties properties = new Properties();
            String path = PropertiesExam.class.getResource("database.properties").getPath();
            path = URLDecoder.decode(path, "utf-8");
            properties.load(new FileReader(path));
     
            String driver = properties.getProperty("driver");
            String url = properties.getProperty("url");
            String username = properties.getProperty("username");
            String password = properties.getProperty("password");
     
            System.out.println("driver: " + driver);
            System.out.println("url: " + url);
            System.out.println("username: " + username);
            System.out.println("password: " + password);
        }
     
    }
     
    cs






     * 이 포스트은 서적 '이것이 자바다' 를 참고하여 작성한 포스트입니다.


    댓글

Designed by Tistory.