Map

TIL·2023년 1월 9일

자료구조

목록 보기
3/5

  • key, value
  • 순서X (인덱스 X), (element의) 중복0 (key의 중복X)
  • 원하는 값으로 키 지정 가능, 키와 값에 null을 허용
  • Collection 인터페이스와 다른 Map 인터페이스



Hash

  • HashSet은 element(저장할 데이터)로 해시코드 생성
    • HashMap(element, dump) => element 중복 불가
  • HashMap은 key로 해시코드 생성 (key, value)
    • HashMap(key, element) => key 중복 불가
    • 같은 value 라도 key 다르게 줄 수 있으므로 충돌 확률이 HashSet 보다 적다
      (HashSet은 같은 value면 충돌)
  • 해시코드 -> home address (hash table)



HashMap

  • Collection 인터페이스 아닌 Map 인터페이스를 구현함 (제너릭 파라미터가 두개 이기 때문) => 메서드 다름

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

        // put(key) : 원소 추가(저장 안된 key) & 수정(저장 되어 있는 key)
        // containsKey() : key 저장 유무
        for (int i = 1; i <= 10 ; i++) {
            if (!hashMap.containsKey(i)) {
                hashMap.put(i, Character.toString((i - 1) + 'a')); // 원소 추가
            } else {
                // 원소 수정
            }
        }
        System.out.println("hashMap = " + hashMap);
        System.out.println("hashMap.size() = " + hashMap.size());
        System.out.println();

        // key = null 가능 (LinkedMap 은 불가)
        hashMap.put(null, "something");
        System.out.println("hashMap = " + hashMap);
        System.out.println("hashMap.size() = " + hashMap.size());
        System.out.println();

        // get(null) 가능
        System.out.println("hashMap.get(null) = " + hashMap.get(null));
        System.out.println();

        // get(저장되지 않은 key) -> null
        System.out.println("hashMap.get(100) = " + hashMap.get(100)); // null

        // get(key) : value 접근
        for (int key = 1; key <= 10; key++) {
            if (hashMap.containsKey(key)) {
                System.out.println("hashMap.get(key) = " + hashMap.get(key));
            }
        }
        System.out.println();

        // repeat(count)
        for (int key = 1; key <= 10; key++) {
            if (hashMap.containsKey(key)) {
                hashMap.put(key, hashMap.get(key).repeat(3));
            }
        }
        System.out.println("hashMap = " + hashMap);
        System.out.println("hashMap.size() = " + hashMap.size());
        System.out.println();

        // replace() : 내부에서 key 유무 체크 후 key 가 있으면 put 을 통해 원소 수정
        hashMap.replace(-1, "a"); // -1과 같은 키는 없기 때문에 아무런 영향이 없음 (추가X) // List 에게 있는 IndexOutOfRangeException 없음
        System.out.println("hashMap = " + hashMap);
        hashMap.replace(1, "abcde!@@");
        System.out.println("hashMap = " + hashMap);
        hashMap.replace(1, "abcde!@@", "abcde");
        System.out.println("hashMap = " + hashMap);
        System.out.println();

        // Map.of(key, value)
        // putAll()
        Map map = Map.of(3, "$$", 4, "!!", 100, "@@");
        hashMap.putAll(map);
        System.out.println("hashMap = " + hashMap);
        System.out.println("hashMap.size() = " + hashMap.size());
        System.out.println();

        // .keySet().iterator()
        // for 대신 iterator() (인덱스 없으므로)
        // keySet() : key를 Set으로 저장 (집합)
        Iterator<Integer> iterator = hashMap.keySet().iterator(); // key가 hashcode 만드므로
//        Iterator<Integer> iterator = hashMap.iterator(); // Collection/Map Interface 다르므로 Set의 iterator() 호출
        while (iterator.hasNext()) {
            Integer i = iterator.next();
            System.out.println("key => " + i + ", value => " + hashMap.get(i));
        }
        System.out.println();

        // entrySet() : Map -> Set 으로 반환 -> Set의 원소 순회
        for (Map.Entry<Integer, String> entry: hashMap.entrySet()) { // hashMap.entrySet(): Set<Map.Entry<>>
            Integer key = entry.getKey();
            String value = entry.getValue();
            System.out.println( "key => " + key + ", value => " + value);
        }

        // keySet()
        System.out.println("hashMap.keySet() = " + hashMap.keySet());
        // values()
        System.out.println("hashMap.values() = " + hashMap.values());

        // containsKey() : 원소 유무 확인
        System.out.println("hashMap = " + hashMap);
        System.out.println("hashMap.containsKey(100) = " + hashMap.containsKey(100));
        System.out.println("hashMap.containsValue(\"aaa\") = " + hashMap.containsValue("aaa"));
        System.out.println();

        // remove(key)
        hashMap.remove(1);
        hashMap.remove(2);
        hashMap.remove(null);
        hashMap.remove(1, "aaa");
        System.out.println("hashMap = " + hashMap);
        System.out.println("hashMap.size() = " + hashMap.size());
        System.out.println();

        // clear()
        hashMap.clear();
        System.out.println("hashMap = " + hashMap);
        System.out.println("hashMap.size() = " + hashMap.size());
        System.out.println();

        // isEmpty()
        System.out.println("hashMap.isEmpty() = " + hashMap.isEmpty());
        System.out.println();


        // Map (컬렉션) -> Array (객체 배열)
        // Object[] / Map.Entry[]
        Map<Integer, String> hashMap1 = new HashMap<>();
        for (int i = 1; i <= 10 ; i++) {
            hashMap1.put(i, Character.toString((i-1) + 'a')); // Character.toString : '' -> ""
        }
        System.out.println("hashMap1 = " + hashMap1);

        // Object[] : keySet().toArray()
        Integer[] keys = hashMap1.keySet().toArray(new Integer[hashMap1.size()]);
        String[] values = hashMap1.values().toArray(new String[hashMap1.size()]);

        // Map.Entry[] :  entrySet().toArray()
        Object[] objects = hashMap1.entrySet().toArray();
        Map.Entry<Integer, String>[] entries = (Map.Entry<Integer, String>[]) hashMap1.entrySet().toArray(new Map.Entry[hashMap1.size()]);

        System.out.println("keys   = " + Arrays.toString(keys)); // Arrays.toString() : 주소 아닌 내용 출력
        System.out.println("values = " + Arrays.toString(values));
        System.out.println("objects = " + Arrays.toString(objects));
        System.out.println("entries = " + Arrays.toString(entries));
        System.out.println();

        // Array (객체 배열) -> Map (컬렉션) : ofEntries()
        Map<Integer, String> hashMap2 = new HashMap<>(Map.ofEntries(entries));
        System.out.println("hashMap2 = " + hashMap2);
    }
}



HashTable

HashMap과 HashTable

  • JDK1.0+
  • 메서드 동일
  • synchronized -> 속도 느림 (레거시)
  • 대신 synchronizedMap, concurrentHashMap 사용
synchronizedHashMap = Collections.synchronizedMap(new HashMap<String, String>());
concurrentHashMap = new ConcurrentHashMap<String, String>();



LinkedHashMap

  • HashMap + LinkedList(들어간 순서) => 삽입 순서 유지
  • 메서드 동일



TreeMap

  • 크기의 순서 유지
    • Key, Value 중 무엇 으로 비교?? -> Key
    • vs. TreeSet : element로 비교. TreeSet도 내부적으로 Map 이용 (element가 key 됨)
  • private final Comparator<? super K> comparator; // TreeMap.java
    • 특정 key 이상만 comparator 생성 가능
    • Pen 을 Item 의 productNo 으로 sort 가능
  • 레드-블랙 트리 (self-balancing binary search tree)
    • 검색/정렬 👍🏻, 추가/삭제 👎🏻

public class TreeMapExample {
    public static void main(String[] args) {
        Map<Integer, String> treeMap = new TreeMap<>();

        // 크기의 순서 유지 : 10 ~ 1 -> 1 ~ 10
        for (int i = 10; i >= 1 ; i--) {
            if (!treeMap.containsKey(i)) {
                treeMap.put(i, Character.toString((i - 1) + 'a'));
            }
        }
        System.out.println("treeMap = " + treeMap);
        System.out.println("treeMap.size() = " + treeMap.size());
        System.out.println();

        // null 추가 불가 (크기가 없음)
//        treeMap.put(null, "something");
//        System.out.println("treeMap = " + treeMap);
//        System.out.println("treeMap.size() = " + treeMap.size());
//        System.out.println();
 
          ...
          
          // Key 객체가 implements Comparable<Key> 하지 않으면 ClassCastException
        // serialNo 의 역순 저장 : 0001 ~ 0004 -> 0004 ~ 0001
        Map<Key, Pen> penMap = new TreeMap<>();
        penMap.put(new Key("0001", "QS8879921031"), new Pen("0001", "파카", "red"));
        penMap.put(new Key("0002", "NS1230910000"), new Pen("0002", "빅", "black"));
        penMap.put(new Key("0003", "KS0000123123"), new Pen("0003", "파카", "blue"));
        penMap.put(new Key("0004", "SS1123124123"), new Pen("0004", "제브라", "red"));

        System.out.println("penMap = " + penMap);
        System.out.println("penMap.size() = " + penMap.size());
        System.out.println();

        // key 아닌 value 크기 유지 되도록 저장하기
        // TreeMap 의 value 모아서 따로 Collection<>, List<>, Set<> 에 저장하여 정렬
        Collection<String> collection = treeMap.values();
        System.out.println(collection);

        //
        Iterator<Integer> iterator1 = treeMap.keySet().iterator();
        while (iterator1.hasNext()) {
            Integer i = iterator1.next();
            System.out.println("key => " + i + ", value => " + treeMap.get(i));
        }
        System.out.println();
        
        ...
}



Map

  • 정적인 데이터 저장
  • 검색, 출력은 가능
public class MapExample {
    public static void main(String[] args) {
        // Map은 인터페이스이기 때문에 객체 생성이나 추가, 삭제, 수정 연산 불가능 (UnsupportedOperationException)
        // Map은 인덱스가 없기 떄문에 인덱스가 필요한 메소드 호출 불가

//        Map<Integer, String> map = new Map<>(); // 불가능

        Map<Integer, String> streamMap = Stream.of(new Object[][] {
                { 1, "Java" },
                { 2, "JSP" },
                { 3, "Servlet" },
                { 4, "Spring" },
        }).collect(Collectors.toMap(data -> (Integer) data[0], data -> (String) data[1]));
        System.out.println("streamMap = " + streamMap);

        Map<String, String> streamMap2 = Stream.of(new String[][] {
                { "a", "Java" },
                { "b", "JSP" },
                { "c", "Servlet" },
                { "d", "Spring" },
        }).collect(Collectors.toMap(data -> data[0], data -> data[1]));
        System.out.println("streamMap2 = " + streamMap2);
        System.out.println();

        Map<Integer, String> map = Map.of(1, "a", 2, "b", 3, "c", 4, "d", 5, "e");
        
        ...
        
}

0개의 댓글