Java 컬렉션을 사용하다 보면 한 번쯤 마주치는 두 메서드가 있다.
- getOrDefault(key, defaultValue)
- computeIfAbsent(key, mappingFunction)
둘 다 “key가 없을 때 기본 값을 어떻게 처리할 것인가”라는 공통 목적을 가진 것처럼 보이지만,
작동 방식도 완전히 다르고, 쓰이는 상황도 전혀 다르다.
1. getOrDefault() — “단순 조회 + 기본 반환” 역할
V value = map.getOrDefault(key, defaultValue);
✔ 동작 방식
- key가 존재하면 해당 value를 그대로 반환한다.
- key가 존재하지 않으면 defaultValue를 반환만 한다.
- Map 자체에는 아무 것도 추가되지 않는다.
✔ 특징
- Map 수정 없음
- 읽기(Read) 연산
- defaultValue는 실제 Map에 넣지 않는다
- 멀티스레드 환경에서 안전성 보장 ❌ (HashMap이라면 특히)
✔ 예시
Map<String, Integer> countMap = new HashMap<>();
int count = countMap.getOrDefault("apple", 0);
System.out.println(count); // 0 출력
System.out.println(countMap); // {} 그대로
✔ 언제 사용?
- key가 없을 때 그냥 반환하기만 하면 되는 경우
- Map을 수정하고 싶지 않은 경우
- 단순 조회 + 기본 값 제공이 목적일 때
2. computeIfAbsent() — “없으면 생성하고 Map에 저장까지”
V value = map.computeIfAbsent(key, k -> new Value());
✔ 동작 방식
- key가 이미 존재하면 value를 그대로 반환한다.
- key가 존재하지 않으면 mappingFunction을 실행해 value를 생성하고 Map에 저장한 뒤 반환한다.
“조회 + 생성 + put”이 한 번에 이루어지는 원자적 연산이다.
✔ 특징
- Map을 수정
- 쓰기(Write) 연산
- 기본 값은 Map에 저장된다
- ConcurrentHashMap에서는 원자적으로 동작해서 멀티스레드 환경에서 안전
✔ 예시
ConcurrentHashMap<String, ReentrantLock> lockMap = new ConcurrentHashMap<>();
ReentrantLock lock = lockMap.computeIfAbsent("user1", k -> new ReentrantLock());
System.out.println(lockMap);
// {"user1"=ReentrantLock 객체} 저장됨
✔ 언제 사용?
- key가 없으면 Map에 기본 객체를 생성해서 저장해야 할 때
- 리소스 캐싱, 락 관리 등 객체가 여러 번 재사용되어야 할 때
- 멀티스레드 환경에서 안전하게 “있는지 확인 → 없으면 생성”이 필요할 때
(Double-checking 코드를 직접 만들 필요 X)
3. 두 메서드의 가장 큰 차이: Map을 수정하는지
| 메서드 | key가 없을 때 | Map에 값 저장 | 멀티스레드 안전성 |
| getOrDefault() | defaultValue 그냥 반환 | ❌ 저장 X | Map 종류에 따라 unsafe |
| computeIfAbsent() | 함수로 value 생성 + Map에 저장 | ✔ 저장 O | ✔ ConcurrentHashMap에서 thread-safe |
getOrDefault()와 computeIfAbsent()는 비슷해 보이지만 목적이 완전히 다르다.
- 조회 목적이면 getOrDefault
- 객체 생성 + Map 저장이 필요하면 computeIfAbsent
특히 멀티스레드 환경에서 per-key 자원 관리가 필요하다면
computeIfAbsent()는 거의 필수라고 할 수 있다.
반응형
'IT > JAVA' 카테고리의 다른 글
| Java 멀티스레드와 병렬 실행 (0) | 2025.12.07 |
|---|---|
| Java 함수형 인터페이스 Supplier, Runnable (0) | 2025.12.07 |
| ReentrantLock 락 제어 (0) | 2025.12.06 |
| Java 예외: RuntimeException (0) | 2025.12.06 |
| 동기화 vs 원자적 연산 (1) | 2025.07.24 |