문홍의 공부장

HashMap 클래스의 개념과 예제 (Hashmap Java example) 본문

개발/Java

HashMap 클래스의 개념과 예제 (Hashmap Java example)

moonong 2020. 1. 14. 19:14
반응형

HashMap의 개념과 특징

HashMapMap을 구현했으므로, Map의 특징인 키와 값을 묶어 하나의 데이터(entry)로 저장한다는 특징을 갖는다. 그렇다면 해시맵은 어떻게 사용하여야 할까?

HashMap을 사용하는 이유를 예를 들어 명확하게 설명해 놓은 포스팅이 있어, 예시를 빌려왔다. 원문은 https://dzone.com/articles/how-to-use-java-hashmap-effectively이다.

여러분이 편의점(원문은 식료품점)을 운영하고 있고, 여러분의 가게에서 많은 종류의 상품을 다루고 있다고 하자. 그 많은 상품들은 각자 이름과 가격이 있다. 이 모든 상품을 모두 기억하고 있는 것은 어려운 일이다. 상품들의 정보를 노트에 기록하는 중에도 상품을 팔아야되며 또 그것들의 가격을 찾는 등의 행위를 해야한다.

만약에 노트에 이름순으로 적어 놓지 않는다면 매번 상품에 대한 정보를 찾는 시간이 오래걸릴 것이다. 알고리즘적으로 표현하자면 O(n)의 복잡도를 가진다고 한다. 하지만 이름순으로 유지가된다면 이진탐색을 할수가 있으므로 (log n)의 시간에 찾기가 가능하다. 즉 O(log n)이다. 알다시피 O(log n)은 O(n)보다 적게 시간이 걸린다.

비록 O(log n) 이 상당히 적은 시간이 소요된다 하더라도 여전히 어느 정도의 시간은 걸린다. 시간이 전혀 걸리지 않는다면 그것이 최선일 것이다. 아마 여러분이 모든 상품의 이름과 가격을 기억할 수 있고 손님이 상품의 이름을 말하는데로 바로 가격을 대답할 수 있는 경우일 것이다.

이 경우에 대한 정확한 해결방법이HashMap을 사용하는 것이다. 상품의 이름과 그것의 가격을HashMap에 넣고 거의 시간이 걸리지 않고 key로써 value를 얻을 수 있다.

HashMap 클래스의 특징은 다음과 같다.

  • key와 value를 하나의 쌍(entry)으로 저장되는 구조이며, 해싱(hashing)을 사용하기 때문에 많은 양의 데이터를 검색하는데 있어 뛰어난 성능을 보인다.
  • 저장되는 key와 value는 null 값을 허용한다. 단, key는 중복 불가하다. (즉, null 을 가지는 key 는 2개일 수 없다)
  • key, value의 쌍으로 관리하므로, Iteration 객체를 사용하지 않고 해당 key에서 데이터의 값을 바로 추출할 수 있다.
  • 동기화가 포함되지 않으므로, 멀티 스레드 환경에서의 구현이 아니라면 HashTable에 비해 처리 속도가 빠르다.
  • List와 달리, Map에는 순서가 없다.
  • 유사한 성격의 클래스로는 HashTable, TreeMap 등이 있다.

HashMap의 주요 메소드

메소드 설명
boolean containsKey(Object key) 지정된 key가 포함되어 있는지 여부를 반환한다.  
boolean containsValue(Object value) 지정된 value가 포함되어 있는지 여부를 반환한다.
Set entrySet() 저장된 키와 값을 엔트리(키와 값의 결합)의 형태로 Set에 저장하여 반환한다. 
Set keySet() 저장된 모든 key를 Set에 저장하여 반환한다. 
void clear() 저장된 모든 객체(key, value)를 제거한다. 
Object remove(Object key) 지정된 key에 해당하는 value를 제거한다. 
Object getOrDefault(Object key, Object defaultValue) 지정된 키의 값을 반환한다. 키가 없을 경우, default Value로 지정된 데이터를 반환한다. 
void putAll(Map map) Map에 저장된 모든 요소를 HashMap에 저장한다. 
Object replace(Object key, Object value) 지정된 키의 값을 지정된 value로 대체한다. 
boolean replace(Object key, Object oldValue, Object newValue) 지정된 키와 값(oldValue)가 모두 일치하는 경우에만 새로운 값으로 대체하며, 일치 여부를 반환한다. 

HashMap 예제 1) put/get

put() 메소드를 이용하여 데이터를 key, value 의 쌍으로 저장하고, get() 메소드를 통해 값을 꺼내올 수 있다. 

1
2
3
4
5
6
7
8
9
10
11
12
13
Map<StringString> map = new HashMap<StringString>();
    
    //add value
    map.put("a""A");
    map.put("a""AA");
    map.put("b""B");
    map.put("c""C");
    map.put(null"NullValue");
    
    //get value
    System.out.println(map.get("a"));
    System.out.println(map.get("d"));
    System.out.println(map.get(null));
cs
출력값:
AA
null
NullValue

HashMap 예제 2) containsKey/containsValue

map 안에 해당 key / value 가 있는지 확인하는 메소드이다. boolean 타입으로 값을 반환한다. 

1
2
3
4
5
6
7
8
9
10
11
12
Map<StringString> map = new HashMap<StringString>();
        
    //add value
    map.put("a""A");
    map.put("a""AA");
    map.put("b""B");
    map.put("c""C");
    map.put(null"NullValue");
        
    //check if key/
    System.out.println(map.containsKey("a"));
    System.out.println(map.containsValue("Z"));
cs
출력값:
true
false

HashMap 예제 3) keySet()/values()/entrySet() 으로 전체출력

keySet()은 map에서 key 만을 가져올 때, valuse()는 value 만을 가져올 때,
그리고 entrySet()은 키와 값을 모두 가져올 때 사용한다. 주로 반복문을 돌려 전체 출력/검색 시에 사용한다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
Map<StringString> map = new HashMap<StringString>();
        
    //add value        
    map.put("a""A");
    map.put("a""AA");
    map.put("b""B");
    map.put("c""C");
    map.put(null"NullValue");
    
    //iteration 
    for (String key : map.keySet()) {
        System.out.print(map.get(key) + "/");
    }
        
    for (Map.Entry<StringString> entry : map.entrySet()) {
        System.out.print(entry + "/");
    }
cs
출력값:
NullValue/AA/B/C/
null=NullValue/a=AA/b=B/c=C/

HashMap 예제 4) replace() - 값 변경

map에 담겨있는 데이터의 값을 변경할 때 사용한다. replace(key, value) 메소드로는 해당 key 에 해당하는 값을 바로 바꾸어주며, replace(key, oldValue, newValue) 메소드는 해당 key에 oldValue 값이 있을 때에만 값을 대체한다. 

1
2
3
4
5
    //replace
    System.out.println("map_before: "+ map);        
    System.out.println(map.replace("a""AA""Z"));
    System.out.println("map_after: "+ map);
 
cs
출력값:
map_before: {null=NullValue, a=AA, b=B, c=C}
true
map_after: {null=NullValue, a=Z, b=B, c=C}

HashMap 예제 5) getOrDefault(), putIfAbsent(), computeIfAbesent(), computeIfPresent()

표로 정리된 메소드와 더불어, 몇 가지 더 추가 정리하겠다.

  • getOrDefault(): key 값이 없다면 입력 시 설정한 default 값을 반환. 단, 해당 값이 map에 저장되지는 않는다.
  • putIfAbsent(): 해당 key가 있으나 없으나 get한다. (key 값이 없다면 입력 된 key와 value 를 입력, 해당 key가 존재하면 입력 되었던 값 반환).
  • computeIfAbsent(): 해당 key가 있으면 get 하고, 없으면 put 한다.
  • computeIfPresent(): 해당 key가 있으면 해당 메소드를 호출하여 (값을 변경, 변경된 value 값으로) 다시 put 한다. 키가 없으면 메소드를 호출하지 않는다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
Map<StringString> map = new HashMap<StringString>();
        map.put("apple""apple");
        map.put("banana""banana");
        map.put("mango""mango");
        
        //getOrDefault(): key가 없으면 default로 설정한 값을 출력
        System.out.println("getOrDefault(): " + map.getOrDefault("apple""lemon"));
        System.out.println("getOrDefault(): " + map.getOrDefault("lemon""lemon"));
        System.out.println("values in map: "+ map);
        
        //putIfAbsent(): 값이 비어있으면 해당 메소드의 value("lemon")을 put 함. 단, 이전 값이 존재하지 않기 때문에 null 반환
        map.putIfAbsent("lemon""lemon");
        System.out.println("values in map: "+ map);
        
        //key로 된 값이 없을 때 put 하는 것이기 때문에 이미 값이 있을 경우 value("orange")로 대체하지 않음. 
        map.putIfAbsent("lemon""orange");        
        System.out.println("values in map: "+ map);
cs
출력값:
getOrDefault(): apple
getOrDefault(): lemon
values in map: {banana=banana, apple=apple, mango=mango}
values in map: {banana=banana, apple=apple, lemon=lemon, mango=mango}
values in map: {banana=banana, apple=apple, lemon=lemon, mango=mango}


computeIfAbsent() 는 key값이 없을 때 메소드를 호출하며, 이미 존재하면 해당 메소드를 호출하지 않는다. 하지만, putIfAbsent()는 key값의 존재 여부와 상관없이 메소드를 호출한다. computeIfPresent() 는 key값이 존재할 때 메소드를 호출하며, 그렇지 않으면 해당 메소드를 호출하지 않는다. computeIfPresent 메서드는 key와 remapping function 두개의 인자를 갖는다. 그래서 key가 있을 때만 value를 변환한다.

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
Map<StringString> map = new HashMap<StringString>();
        map.put("apple""apple");
        map.put("banana""banana");
        map.put("mango""mango");
        
        //computeIfAbsent(): key값이 없을 때 메소드를 호출한다.         
        map.computeIfAbsent("kiwi", key -> pm.setFruit(key));
        System.out.println("values in map: "+ map);
        
        //putIfAbsent(): key값이 이미 존재해도 메소드는 호출된다. 단, 이 경우 apple 이라는 키에는 이미 값이 있기 때문에, value가 변경되지 않는다. 
        map.putIfAbsent("apple", pm.setFruit("red apple"));
        System.out.println("values in map: "+ map);
 
        //computeIfPresent(): key값이 존재할 때 메소드를 호출한다.  
        map.computeIfPresent("kiwi", (String key, String value) -> "gold "+value);
        System.out.println("values in map: "+ map);
cs

 

위 예제의 setFruit()은 key 값을 리턴하는 간단한 메소드이다. computeIfAbsent() / computeIfPresent() 메소드가 실행될 경우, map에 데이터가 저장되는 것을 확인할 수 있다.

출력값:
values in map: {banana=banana, apple=apple, kiwi=kiwi, lemon=lemon, mango=mango}
values in map: {banana=banana, apple=apple, kiwi=kiwi, lemon=lemon, mango=mango}
values in map: {banana=banana, apple=apple, kiwi=gold kiwi, lemon=lemon, mango=mango}
반응형