본문 바로가기

Springあるある

Map :: values() 사용 시 주의점(Feat. ConcurrentModificationException)

 

package hello.itemservice.domain.item;

import org.springframework.stereotype.Repository;

import java.util.*;

@Repository
public class ItemRepository {

    private static final Map<Long, Item> store = new HashMap<>(); //static
    private static long sequence = 0L; //static

  

    public List<Item> findAll() {
        
        return new ArrayList<>(store.values());

    }



},

 

 

 

위 코드에서 store.values()를 new ArrayList<>(store.values())로 감싸는 이유는 불변성을 보장하고, 데이터 조작을 방지하기 위해서입니다.

store.values()가 반환하는 것은 Map의 values() 메서드 결과로, 이 값은 Collection 타입입니다. 이를 바로 반환할 경우 몇 가지 문제가 발생할 수 있습니다:


1. store의 데이터가 외부에서 변경되는 것을 방지

  • store.values()는 store의 내부 데이터를 직접 참조하는 를 반환합니다.
  • 즉, 반환된 Collection에서 데이터를 추가, 삭제하면 원래 store에 있는 데이터도 변경될 수 있습니다.
  • 예를 들어, 다음 코드처럼 데이터가 변경될 수 있습니다:
    java
    코드 복사
    List<Item> items = itemRepository.findAll(); items.clear(); // store 데이터가 모두 삭제됨
  • 이를 방지하기 위해, 데이터를 복사한 새로운 ArrayList를 반환합니다.

2. 호환성 및 기능성

  • store.values()의 반환 타입은 Collection이며, Collection은 제한된 메서드만 제공합니다.
  • 반면, ArrayList는 더 많은 기능(예: 인덱스 기반 접근, 정렬, 수정 등)을 제공합니다.
  • 반환 타입이 List로 고정되면 호출자가 더 다양한 메서드를 활용할 수 있습니다.

3. 안정성 및 예외 방지

  • store.values()로 반환된 컬렉션은 Map의 상태에 따라 동적으로 동작합니다.
  • 예를 들어, store에서 데이터를 변경하면 values()로 반환된 컬렉션도 영향을 받을 수 있습니다. 이로 인해 예상치 못한 동작이나 ConcurrentModificationException 같은 문제가 발생할 수 있습니다.
  • 복사본을 반환하면 이런 문제를 방지할 수 있습니다.

결론

new ArrayList<>(store.values())는 다음을 위해 사용됩니다:

  1. 내부 데이터(store)의 불변성을 유지.
  2. 호출자가 더 안전하고 확장된 작업을 수행할 수 있도록 보장.
  3. 예상치 못한 동작이나 예외를 방지.

이러한 이유로 데이터를 복사한 ArrayList로 감싸 반환하는 것이 일반적인 패턴입니다.

 
4o