[Java] HashMap 초기화, 값 수정, 반복문

pintegral·2023년 1월 14일
1

Java

목록 보기
2/3
post-thumbnail

HashMap을 사용할 때마다 헷갈려서 매번 다시 찾아봤던 자료들을 기반으로 싹 정리해봤다.

I. 다른 Map에 비하여 HashMap의 특징은?

내부적으로 Entry<Key,Value>[] Entry의 array로 되어 있는 HashMap의 인덱스는 내부 해쉬 함수를 통해 계산된다.

String은 sun.misc.Hashing.stringHash32 함수에 의해 계산되고, 일반 Object는 내부 hashcode 함수와 비트연산으로 계산된다.

내부 hash 값에 따라서 키 순서가 정해지므로 특정 규칙없이 출력되기 때문에 입력순으로 저장 순서가 유지되어야 한다면 다른 map을 사용해야 한다.

그럼 HashMap은 어느 상황에 주로 사용되는가?

조회 시간복잡도가 O(1)로 조회 성능이 좋다. 따라서 조회가 잦은 경우, 그리고 특별한 이유가 없다면 HashMap을 사용하는 경우가 많다.

그 외에 key값을 알파벳 순서대로 정렬하려면 내부적으로 RedBlack Tree에 의해 저장되는 TreeMap을,

(단, 랜덤접근에 대해 O(log n) 시간이 걸리므로 데이터 양 많아질 경우 성능 저하)

입력 순서가 유의미하다면 입력순대로 저장되는LinkedHashMap 을 사용하면 된다.

(단, LinkedHashMap 또한 랜덤 접근에 대해 O(n) 시간이 걸리므로 데이터 양 많아질 경우 성능 저하)

II. HashMap 선언과 동시에 초기화하기


public static void main(String args[]) {
  Map<String, Integer> fruits = Stream.of(new Object[][] {
        {"자몽", 1000},
        {"청포도", 2000},
        {"복숭아", 3000}
  }).collect(Collectors.toMap(item -> (String)item[0], item -> (Integer)item[1]));

  System.out.println(hm);
}

III. HashMap 값 수정하기


1. 특정 key 값을 수정

  • replace() : 전달된 key의 value인자로 전달된 value로 value 값 수정
    • 단, key가 존재하지 않는다면 null 리턴
public static void main(String args[]) {
  HashMap<String, Integer> subjects = new HashMap<>();
  subjects.put("React", 1000);

  subjects.replace("React", 5000);
  subjects.replace("Vue JS", 5000); // return null
}

2. 특정 key의 기존값을 기반으로 수정

  • put()get()을 이용
public static void main(String args[]) {
  HashMap<String, Integer> subjects = new HashMap<>();
  subjects.put("React", 1000);

  subjects.put("React" , subjects.get("React") * 10);
}

3. 모든 key의 기존값을 기반으로 수정

1) HashMapentrySet() 메서드를 호출하여 Set으로 변환 후 순회
2) Set의 요소Map.Entry접근
3) Map.EntrysetValue()getValue() 메서드를 사용하여 기존값을 기반으로 수정

public static void main(String args[]) {
  HashMap<String, Integer> subjects = new HashMap<>();
  subjects.put("React", 100);
  subjects.put("VueJS", 200);
  subjects.put("JavaScript", 300);
  subjects.put("TypeScript", 400);
  
  for (Map.Entry<String,Integer> item : subjects.entrySet()){
    item.setValue(item.getValue() * 10);
  }

4. 특정 조건을 만족하는 모든 값 수정

  • replaceAll()
    • replaceAll 사용 가능한 경우
      • 키에 특정 문자열이 포함되는 값만 변경
      • 특정 범위에 속하는 값만 변경
public static void main(String args[]) {
  HashMap<String, Integer> subjects = new HashMap<>();
  subjects.put("React", 100);
  subjects.put("VueJS", 200);
  subjects.put("JavaScript", 300);
  subjects.put("TypeScript", 400);
  
  subjects.replaceAll((key, value) -> {
    if(key.contains("Script")) {
      return value * 10;
    }
    return value;
  });

IV. HashMap 반복문 사용하기


1. key와 value값이 전부 필요할 때 → entrySet

1) Set 객체 생성 : Map.Entry<DataType, Datatype> entry = map.entrySet();
2) Set 객체의 key 값 리턴 : entry.getKey();
3)Set 객체의 value 값 리턴 : entry.getValue();

Map<Integer, Integer> map = new HashMap<Integer, Integer>();

for (Map.Entry<Integer, Integer> entry : map.entrySet()) {
    System.out.println("Key = " + entry.getKey());
    System.out.println("Value = " + entry.getValue());
}

2. key나 value 둘 중에 하나만 필요할 때

  • entrySet을 사용할 때보다 약 10%정도 빠르다
  • key만 필요 → map.KeySet()
  • value만 필요 → map.values()
Map<Integer, Integer> map = new HashMap<Integer, Integer>();
 
//iterating over keys only
for (Integer key : map.keySet()) {
    System.out.println("Key = " + key);
}
 
//iterating over values only
for (Integer value : map.values()) {
    System.out.println("Value = " + value);
}

3. Iterator 사용하여 HashMap 순회하기

1) Iterator 객체 생성 : Iterator<Map.Entry<Integer, Integer>> entries = entrySet().iterator()
2) 읽어올 요소가 남아있는지 체크 : while (entries.hasNext())
3) 데이터 반환 : Map.Entry<Integer, Integer> entry = entries.next();

Map<Integer, Integer> map = new HashMap<Integer, Integer>();
Iterator<Map.Entry<Integer, Integer>> entries = map.entrySet().iterator();

while (entries.hasNext()) {
    Map.Entry<Integer, Integer> entry = entries.next();
    System.out.println("Key = " + entry.getKey() + ", Value = " + entry.getValue());
}

4. [비효율적] key값으로 value 반환

  • 코드상으로는 간단해 보이지만 첫 번째 방법에 비해 성능상 비효율적인 방법이다. key값을 이용해서 value를 찾는 과정에서 시간이 많이 소모되기 때문이다.(1번 방법 대비 20%~200% 성능 저하)
Map<Integer, Integer> map = new HashMap<Integer, Integer>();

for (Integer key : map.keySet()) {
    Integer value = map.get(key);
    System.out.println("Key = " + key + ", Value = " + value);
}

References

profile
문제를 끝까지 해결하려는 집념의 개발자

0개의 댓글