본문 바로가기

기술 서적/자바의 정석

[자바의 정석] ch11-3.컬렉션 프레임워크 : HashMap/TreeMap / Collections

1. HashMap 

더보기

- Map 인터페이스를 구현

- key와 value를 하나로 묶어서 하나의 데이터(entry)로 저장

- 순서를 유지하려면 LinkedHashMap클래스를 사용

 

=> Entry라는 내부 클래스를 정의하고, Entry 타입의 배열을 선언하고 있음

비 객체지향적 객체지향적 코드
Object [] key;
Object [] value;
Entry [] table;

class Entry{
    Object key;
    Object value;
}

=> (key, value) 를 (Object, Object)형태로 저장

 

>>메서드

- entry값 : entrySet => Set

- key 값 : keySet => Set

- value값 : values() =>Collection 반환

 

 

ex1) 같은 키를 대상으로 하는 put은 덮어써짐

package ch11;

import java.util.*;
public class HashMapEx1 {
    public static void main(String[] args) {
        HashMap map = new HashMap();
        map.put("myId", "1234");
        map.put("asdf", "1111");
        map.put("asdf", "1234"); //덮어써짐

        Scanner s= new Scanner(System.in);

        while(true){
            System.out.println("id와 password를 입력해주세요.");
            System.out.print("id : ");
            String id = s.nextLine().trim();

            System.out.print("password : ");
            String password= s.nextLine().trim();
            System.out.println();

            if(!map.containsKey(id)){
                System.out.println("입력하신 id는 존재하지 않습니다.");
                continue;
            }
            if(!map.get(id).equals(password)){
                System.out.println("비밀번호가 일치하지 않습니다!");
            }
            else{
                System.out.println("id와 비밀번호가 일치합니다.");
                break;
            }
        }
    }
}

 

 

ex2) keySet/EntrySet은 Set을 Values는 Collection을 반환함

public class HashMapEx2 {
    public static void main(String[] args) {
        HashMap map = new HashMap();

        map.put("김자바",100);
        map.put("이자바",100);
        map.put("강자바",80);
        map.put("안자바",90);

        Set set = map.entrySet();
        Iterator it= set.iterator();

        while(it.hasNext()){
            Map.Entry e= (Map.Entry) it.next();
            System.out.println("이름 : "+ e.getKey()+" 점수 : "+ e.getValue());
        }

        set = map.keySet();
        System.out.println("참가자 명단 : "+set);

        Collection values = map.values();
        it= values.iterator();

        int total=0;

        while(it.hasNext()){
            Integer i= (Integer) it.next();
            total+=i.intValue();
        }
        System.out.println("총점 : "+ total);
        System.out.println("평균 : "+ (float)total/set.size());
        System.out.println("최고점수 : " + Collections.max(values));
        System.out.println("최저점수 : " + Collections.min(values));
    }
}


>>실행결과
이름 : 안자바 점수 : 90
이름 : 김자바 점수 : 100
이름 : 강자바 점수 : 80
이름 : 이자바 점수 : 100
참가자 명단 : [안자바, 김자바, 강자바, 이자바]
총점 : 370
평균 : 92.5
최고점수 : 100
최저점수 : 80

 

 

ex3) Hashmap안에 Hashmap

package ch11;

import java.util.*;
public class HashMapEx3 {
    static HashMap phoneBook = new HashMap();

    public static void main(String[] args) {
        addPhoneNo("친구", "이자바", "010-111-1111");
        addPhoneNo("친구", "김자바", "010-222-2222");
        addPhoneNo("친구", "김자바", "010-333-3333");
        addPhoneNo("회사", "김대리", "010-444-4444");
        addPhoneNo("회사", "김대리", "010-555-5555");
        addPhoneNo("회사", "박대리", "010-666-6666");
        addPhoneNo("회사", "이과장", "010-777-7777");
        addPhoneNo("세탁", "010-888-8888");

        printList();
    }


    static void addPhoneNo(String group, String name, String phoneNum) {
        if (phoneBook.containsKey(group)) {
            HashMap map = (HashMap) phoneBook.get(group);
            map.put(phoneNum, name);
        } else {
            phoneBook.put(group, new HashMap());
            HashMap map = (HashMap) phoneBook.get(group);
            map.put(phoneNum, name);
        }
    }

    static void addPhoneNo(String name, String phoneNum){
        addPhoneNo("기타",name, phoneNum);
    }
    static void printList(){
        Set s = phoneBook.entrySet();
        Iterator it= s.iterator();
        while(it.hasNext()){
            Map.Entry e= (Map.Entry)it.next();
            Set subSet= ((HashMap)e.getValue()).entrySet();
            Iterator subit = subSet.iterator();

            System.out.println("* "+e.getKey()+"["+subSet.size()+"]");

            while(subit.hasNext()){
                Map.Entry sub= (Map.Entry)subit.next();
                String phoneNum= (String)sub.getKey();
                String name= (String) sub.getValue();
                System.out.println(name +" "+ phoneNum);
            }
            System.out.println();
        }
        
    }
}

>>실행결과
* 기타[1]
세탁 010-888-8888

* 친구[3]
이자바 010-111-1111
김자바 010-222-2222
김자바 010-333-3333

* 회사[4]
이과장 010-777-7777
김대리 010-444-4444
김대리 010-555-5555
박대리 010-666-6666

 

=> 형변환에 주의 

=> get을 통해 가져온 반환값은 (Object)

 

>>해싱

- 해시함수로 해시테이블에 데이터를 저장하고 검색하는 기법

- 배열과 링크드 리스트가 결합된 것

1) 키로 해시함수를 호출해서 해시코드를 얻음

2) 해시코드에 대응하는 링크드 리스트를 배열에서 찾음

3) 링크드리스트에서 키와 일치하는 데이터를 찾음

== 같은 키에 대해 항상 같은 해시코드 반환

== 서로 다른 키더라도 같은 해시코드를 반환할 수 있음

 

 

>> 두 객체가 같음을 판단하는 기준

: equals()의 결과가 true

: 반환되는 hasCode()가 같음

 


2. TreeMap

더보기

- 이진 검색 트리 구조로 키-값의 쌍으로 이루어진 데이터

- TreeSet처럼 데이터를 정렬해서 저장 => 저장시간이 김

- 다수의 데이터에서 개별검색은 TreeSet보다 HashMap이 빠르다

- 정렬이나 범위검색에 유용하다

 

>>생성자

메서드 설명
TreeMap() TreeMap 객체를 생성
TreeMap(Comparator c) 지정된 Comparator를 기준으로 정렬하는 TreeMap 객체를 생성
TreeMap(Map m)
TreeMap(SortedMap m) 
주어진 Map에 저장된 모든 요소를 포함하는 TreeMap생성

 

>>메서드

메서드 설명
Map.Entry ceilingEntry(Object key) 반올림한 키와 값의 쌍을 반환. 없으면 null반환
Object ceilingKey(Object key) 반올림한 키 반환
Map.Entry floorEntry(Object key) 반올림한 키와 값의 쌍을 반환. 없으면 null반환
Object floorKey(Object key) 반올림한 키 반환
Object higherEntry(Object key) 올림한 Entry 반환
Object higherKey(Object key) 올림한 키 반환
Object lowerEntry(Object key) 내림한 Entry반환
Object lowerKey(Object key) 내림한 키 반환
Map.Entry firstEntry() 첫번째 Entry반환(루트)
Object firstKey() 첫번째 key반환
Map.Entry lastEntry() 첫번째 key반환
Object lastKey() 마지막 key반환
Map.Entry pollFristEntry() 첫번째 Entry반환
Map.Entry pollLastEntry() 마지막 Entry반환
SortedMap headMap(Object toKey)

NavigableMap headMap(Object toKey, boolean inclusive)
TreeMap에 저장된 첫번재 요소부터 지정된 범위에 속한 모든 요소가 담긴SortedMap반환

inclusive가 true면 toKey도 포함
SortedMap tailMap(Object fromKey)

NavigableMap tailMap(Object toKey, boolean inclusive)
TreeMap에 저장된 지정된 키부터 마지막 요소의 범위에 속한 요소가 담긴 SortedMap을 반환

지정된 키부터 마지막 요소 범위에 속한 요소가 담긴 NavigableMap을 반환. inclusive가 true면 toKey포함
void clear() Treemap에 저장된 모든 객체를 제거
Object clone() 현재 TreeMap을 복제해서 반환
Comparator comparator() 정렬기준이 되는 comparator 반환
boolean containsKey(Object key) TreeMap에 지정된 값이 포함되어 있는지 알려줌
boolean containsValue(Object value) TreeMap에 지정된 값이 포함되어 있는지 알려줌
Object put(Object key, Object value) key-value를 저장
void putAll(Map map) map에 있는 모든 요소를 저장
Object get(Object key) 지정된 키의 값을 반환
Set entrySet() 키-값을 엔트리 형태로 Set에 저장해서 반환
Set keySet() TreeMap에 저장된 모든 키가 저장된 Set을 반환
boolean isEmpty() TreeMap이 비어있는지 알려줌
NavigableSet descendingKeySet() 내림차순 정렬된 NavigableSet반환
NavigableSet navigableKeySet() navigableSet 반환
isEmpty() 비었는지 확인
Object remove(Object key) key값을 찾아 제거
Object replace(Object k, Object v)
Object replace(Object key, Object oldvalue, Object newValue)
k를 사용해 저장된 값을 v로 바꿈

key를 사용해 저장된 값 중 oldvalue인 것을 newvalue로 바꿈
Collection values() 값을 컬렉션 형태로 반환
NavigableMap subMap(Object fromKey, boolean frominclusive, Object toKey, boolean toinclusive)

SortedMap subMap(Object fromKey, Object toKey)
지정된 두개의 키 사이에 있는 모든 요소가 담긴 NavagableMap을 반환

지정된 두개의 키 사이에 있는 모든 요소들이 담긴 SortedMap을 반환. tokey는 포함 x

 

>>Treemap 예시

: 기존 -- 키의 오름차순

: Comparator 구현을 통해 값들을 비교

package ch11;

import java.util.*;
public class TreeMapEx1 {
    public static void main(String[] args) {
        String [] data= {"A", "K", "A", "K", "D", "K", "A", "K", "K", "K", "Z", "D"};

        TreeMap map= new TreeMap();

        //데이터 저장
        for (int i = 0; i < data.length; i++) {
            if(map.containsKey(data[i])){
                map.put(data[i], (Integer)map.get(data[i])+1);
            }
            else{
                map.put(data[i], 1);
            }
        }

        //기본정렬
        Set set=map.entrySet();
        Iterator it= set.iterator();

        while(it.hasNext()){
            Map.Entry e= (Map.Entry)it.next();
            int value= (Integer)e.getValue();
            System.out.println(e.getKey()+" : "+printBar('#', value)+ " "+value);
        }
        System.out.println();

        set= map.entrySet();
        List list = new ArrayList(set);
        Collections.sort(list, new ValueComparator());
        it = list.iterator();

        while(it.hasNext()){
            Map.Entry e= (Map.Entry)it.next();
            int value= (Integer)e.getValue();
            System.out.println(e.getKey()+" : "+printBar('#', value)+ " "+value);
        }

    }


    static class ValueComparator implements Comparator{
        public int compare(Object o1, Object o2){
            if(o1 instanceof Map.Entry && o2 instanceof Map.Entry){
                Map.Entry e1=(Map.Entry)o1;
                Map.Entry e2=(Map.Entry)o2;
                int v1= ((Integer) e1.getValue()).intValue();
                int v2= ((Integer)e2.getValue()).intValue();

                return v2-v1;
            }
            return -1;
        }
    }

    public static String printBar(char c, int value){
        char [] arr= new char[value];
        Arrays.fill(arr, c);
        return new String(arr);
    }
}

>>실행결과
A : ### 3
D : ## 2
K : ###### 6
Z : # 1

K : ###### 6
A : ### 3
D : ## 2
Z : # 1

3. Collections

더보기

1. 컬렉션 메소드들

: 채우기 - fill()

: 복사 - copy()

: 정렬 - sort()

: 검색 - binarySearch() 등

 

2. 컬렉션 동기화 : synchronized

: 하나의 공유자원에 동시접속을 막는 것

: 데이터 일관성을 유지

 

3. 변경불가(readOnly) : unmodifiable 

 

4. 싱글톤 : singleton

: 하나의 객체만을 저장하는 컬렉션

 

5. 한 종류이 객체만 저장하는 컬렉션 : checked(컬렉션, class type)

=> 지네릭스로 대체 가능

 

ex) Collection 예시

package ch11;
import java.util.*;
import static java.util.Collections.*;
public class CollectionEx {
    public static void main(String[] args) {
        List list = new ArrayList();
        System.out.println(list);

        addAll(list, 1,2,3,4,5);
        System.out.println(list);

        rotate(list, 2);
        System.out.println(list);

        swap(list, 0,2);
        System.out.println(list);

        shuffle(list);
        System.out.println(list);

        sort(list, reverseOrder());
        System.out.println(list);

        sort(list);
        System.out.println(list);

        int idx= binarySearch(list, 3);
        System.out.println("index of 3="+idx);

        System.out.println("max = "+max(list));;
        System.out.println("min = "+min(list));;
        System.out.println("min = "+max(list, reverseOrder()));;

        fill(list, 9);
        System.out.println(list);

        List newList= nCopies(list.size(), 2); //list.size()만큼 새로운 배열 생성 ->2로 채움
        System.out.println("newList = "+ newList); 

        System.out.println(disjoint(list, newList)); // 공통요소 있는지 판단
        copy(list, newList);
        System.out.println("newList = "+ newList);
        System.out.println("List = "+ list);

        replaceAll(list, 2,1);
        System.out.println("List = "+ list);

        Enumeration e= enumeration(list); //listiterator
        ArrayList list2= list(e);

        System.out.println("list2="+ list2);
    }
}


>>실행결과
[]
[1, 2, 3, 4, 5]
[4, 5, 1, 2, 3]
[1, 5, 4, 2, 3]
[2, 1, 3, 4, 5]
[5, 4, 3, 2, 1]
[1, 2, 3, 4, 5]
index of 3=2
max = 5
min = 1
min = 1
[9, 9, 9, 9, 9]
newList = [2, 2, 2, 2, 2]
true
newList = [2, 2, 2, 2, 2]
List = [2, 2, 2, 2, 2]
List = [1, 1, 1, 1, 1]
list2=[1, 1, 1, 1, 1]