[Java] Map.computeIfAbsent(K key, Function)

2024. 8. 22. 14:26Language/Java

 해당 메서드는 데이터를 특정 값에 따라 각각의 그룹으로 분류하고자 사용하게 되면서 이렇게 학습한 내용을 정리하게 되었다. 당시 상황은 그룹을 특정할 만한 데이터들과 해당 데이터를 통해 식별가능한 데이터들이 준비된 상태였다. 간단하게 설명하면 집합 '[1,2,3,4,5,6]' 가 있을 때 '1 = [1,2,6], 2 = [3,4,5]' 그룹으로 나누어 데이터를 저장하고 꺼내야 하는 상황인 것이다. 이 때, 'Map.computeIfAbsent()' 메서드를 알게 되었고 문제 해결을 할 수 있었다.

 

1. Map.computeIfAbsent( ) ?

 Java 의 Map 클래스 설명에 따르면 지정된 키 값이 아직 연결되지 않은 경우(또는 null 에 매핑된 경우) 지정된 매핑 함수를 사용해 해당 값을 연산을 시도하는, Map 클래스에 구현된 메서드이다.

 

 주의 사항으로는 매핑 함수의 반환 값이 null 이면 매핑이 되지 않으며, 매핑 함수 자체적으로 확인되지 않은 예외가 발생해도 매핑이 되지 않는 점이다.

 

 

2. 선언 방법

// key 하나에, 하나의 값을 저장하는 경우
map.computeIfAbsent(key, k -> new Value(f(k)));

// key 하나에, 여러 값을 저장하는 경우
map.computeIfAbsent(key, k -> new HashSet<V>()).add(v);

 

 기본적인 선언 방법은 2가지를 설명하고 있었다. 하나의 키에 하나의 값을 지정해 저장하는 경우와 하나의 키에 여러 값을 지정하는 경우였다. 전자의 경우 가장 일반적인 선언이라 후자에 대해 이야기하면, 해당 경우는 하나의 키에 여러 값을 갖는 Collection 객체가 연결(지정)되어 저장되는 경우를 말한다.

 

 위에서 부터 계속해서 언급되는 '매핑 함수' 는 만약 현재 생성한 Map 객체에 입력받은 'key' 가 없다면 수행되는 함수이다. 해당 함수를 통해서 입력된 'key' 에 해당하는 값을 생성하고 그 결과(값 또는 객체)를 'key' 연결해 Map 객체에 저장하는 역할을 하는 것이다. 반대로 'key' 값이 있는 경우 단일 값 매핑은 '매핑 함수' 수행을 하지 않으며 다수의 값 매핑은 똑같이 '매핑 함수' 를 수행하지 않는 건 같지만, 해당 'key' 에 연결된 Collection 에 값(value)을 추가한다.

 

 

3. 사용 예시

3-1. 단일 값 매핑

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

// keyAndValue[i][0] = key, keyAndValue[i][1] = value
int[][] keyAndValue = {{1, 100}, {2, 200}, {1, 300}, {3, 2000}};

for (int[] e : keyAndValue) {
	testMap.computeIfAbsent(e[0], k -> e[1]);
}

{1=100, 2=200, 3=2000}	// 결과 출력

 

 위 설명이 너무 길고 복잡해보여 간단하게 예시 코드를 작성해 보았다. 각 'keyAndValue[i]' 가 'computeIfAbsent()' 를 만나면 어떻게 흘러갈까? 일단 확실한 건 Map 에 존재하지 않는 'key' 를 만난다면 매핑 함수를 수행해 특정 값을 매핑해 Map 에 저장한다는 것이다. 출력된 결과를 보면 '반복문(for)' 중간에 'key = 1' 인 경우를 한 번 더 마주하는데, 해당 경우 이미 존재하는 'key' 이므로 매핑 함수가 수행되지 않아 과정이 무시되어 '300' 이란 값은 Map 에 반영되지 않는 것이다.

 

3-2. 다수의 값 매핑

Map<Integer, Queue<Integer>> testMap = new HashMap<>();

// keyAndValue[i][0] = key, keyAndValue[i][1] = value
int[][] keyAndValue = {{1, 100}, {2, 200}, {1, 300}, {3, 2000}};

for (int[] e : keyAndValue) {
	testMap.computeIfAbsent(e[0], k -> new PriorityQueue<>())
    		.offer(e[1]);
}

{1=[100, 300], 2=[200], 3=[2000]}	// 결과 출력

 

 다수의 값을 매핑하는 경우에는 어떨까? 말을 바꿔말하면 매핑되는 값이 다수의 값을 갖는 Collection 같은 경우이다. 이 경우 존재하지 않는 'key' 가 넘어오면 값을 저장할 Collection 을 새로 생성해 주어야 하고, 추가적으로 'add' 나 'offer' 를 사용해 매핑할 값을 Collection 에 추가해 주어야 한다.

 

추가한 메서드('add()' or 'offer()')의 경우 매핑 함수에 포함되는 것이 아니기에 단일 값의 경우와 다른 동작을 수행하게 된다. 다수의 값인 경우 'key' 가 존재하지 않아 새로 매핑하는 것과 매핑 함수를 수행하지 않는 것은 같지만 만약 'key' 존재한다면 해당 'key' 에 연결된 Collection 에 지정 값이 추가가 된다.

 

예시코드를 보면 단일 값일 경우와 다른 점이 바로 눈에 띈다. 단일 값에서 무시되었던 '300' 이라는 값이 'key =1' 인 Collection 에 추가가 되어있다. 이는 다수의 값일 경우에는 'key' 가 없다면 Collection 을 생성해 값을 추가하고, 있다면 기존 Collection 에 값을 추가한다고 볼 수 있다.

'Language > Java' 카테고리의 다른 글

[Java] Map.getOrDefault(K key, V default-value)  (0) 2024.08.25
[Java] Map.entrySet()  (0) 2024.08.25
[Java] PriorityQueue  (0) 2024.08.10