Java Collection - 놓치기 쉬운 개념들

이강현·2025년 4월 15일

놓치기 쉬운 개념들

목록 보기
11/19

fail-fast

멀티 쓰레드 상황이 아닌데도 ConcurrentModificationException 을 마주하는 경우가 있습니다.
대부분의 경우 Iterator 를 사용하여 순회를 하는 도중에 변경을 시도했기 때문입니다.

  • 컬렉션의 Iterator생성된 이후 컬렉션의 구조가 변경되면 Iterator 는 ConcurrentModificationException 를 발생시킵니다.
    이를 fail-fast 메커니즘이라 합니다.
  • 컬렉션에서 직접 변경 메서드를 호출하는 것이 아닌, Iterator제공하는 변경 메서드(remove())를 사용하면 안전합니다.
List<String> list = new ArrayList<>(Arrays.asList("apple", "banana", "cherry"));
Iterator<String> iterator = list.iterator();
while (iterator.hasNext()) {
    String item = iterator.next();
    if (item.equals("banana")) {
        iterator.remove(); // safe
    }
}
System.out.println(list);
  • Collection 에서 제공하는 removeIf(), removeAll(), retainAll() 도 대안이 될 수 있습니다.



Collections decoration

Collections 유틸리티 클래스에서 Collection 들을 위한 decorate 메서드들을 제공합니다.

  • synchronizedXXX() - 멀티 스레드 상황을 위한 decorate 메서드
    • synchronizedCollection(Collection c), synchronizedList(List list), synchronizedSet(Set s), synchronizedMap(Map m)

  • unmodifiableXXX() - 읽기 전용 컬렉션을 만들기 위한 decorate 메서드
    • unmodifiableCollection(Collection c), unmodifiableList(List list), unmodifiableSet(Set s), unmodifiableMap(Map m)

  • singletonXXX() - 단 하나의 객체만을 저장하는 컬렉션을 만들기 위한 decorate 메서드
    • singletonList(Object o), singleton(Object o), singletonMap(Object key, Object value)



Collections & Implements

상황에 맞는 인터페이스와 구현체를 사용합니다.

자료구조 인터페이스싱글 스레드 환경에 적합한 구현체 및 간단한 설명멀티 스레드 환경에 적합한 구현체 및 간단한 설명
ListArrayList: 배열 기반, 빠른 인덱스 접근.CopyOnWriteArrayList: 읽기 잦고 쓰기 적을 때 유용, 쓰기 시 복사.
LinkedList: 빠른 중간 삽입/삭제.Collections.synchronizedList(new LinkedList<>()): 동기화 래퍼, 전체 락.
Vector (Legacy): 동기화 지원 (성능 낮음).
SetHashSet: 순서 없음, 빠른 검색.ConcurrentSkipListSet: 정렬된 Set, 락-프리, 높은 동시성.
LinkedHashSet: 삽입 순서 유지.Collections.synchronizedSet(new LinkedHashSet<>()): 동기화 래퍼.
TreeSet: 자동 정렬.Collections.synchronizedSortedSet(new TreeSet<>()): 동기화 래퍼.
QueueLinkedList: FIFO.ConcurrentLinkedQueue: 락-프리 FIFO, 높은 동시성.
PriorityQueue: 우선순위 기반.PriorityBlockingQueue: 우선순위 기반 블로킹 큐.
ArrayDeque: 양방향 큐.LinkedBlockingQueue: 블로킹 FIFO, 용량 제한 가능.
DequeLinkedList: 양방향 삽입/삭제.ConcurrentLinkedDeque: 락-프리 양방향 큐, 높은 동시성.
ArrayDeque: 효율적인 양방향 삽입/삭제.LinkedBlockingDeque: 블로킹 양방향 큐, 용량 제한 가능.
MapHashMap: 빠른 키 검색.ConcurrentHashMap: 높은 동시성, 빠른 읽기.
LinkedHashMap: 삽입 순서 유지.Collections.synchronizedMap(new LinkedHashMap<>()): 동기화 래퍼.
TreeMap: 키 기준 자동 정렬.ConcurrentSkipListMap: 정렬된 Map, 락-프리, 높은 동시성.
Hashtable (Legacy): 동기화 지원 (성능 낮음), null 불가.



compareTo

Java 의 소스코드에서 compareTo() 의 구현 방식들을 확인할 수 있습니다.
이러한 코드들에서 자바 코드를 최적화 하는 방법들을 배울 수 있습니다.

// compareTo in Integer class
public int compareTo(Integer anotherInteger) {
    return compare(this.value, anotherInteger.value);
}
public static int compare(int x, int y) {
    return (x < y) ? -1 : ((x == y) ? 0 : 1);
}

뺄셈이 아니라 삼항 연산자를 두번 사용함으로써 모든 자리수의 계산을 할 필요가 없어지고, 대소비교를 동등비교보다 먼저 함으로써 비교를 두번 해야하는 경우를 줄였습니다.



Properties

  • Map 인터페이스의 구현체인 Hashtable 을 상속받은 Properties 는 key 와 value 모두 String 인 딕셔너리 구조입니다.
  • 주로 애플리케이션의 환경설정과 관련된 속성을 저장하는데 사용되며 데이터를 파일로부터 읽고 쓰는 편리한 기능들을 제공합니다.
메서드짧은 설명
getProperty(String key)키로 값(String) 조회, 없으면 null.
getProperty(String key, String defaultValue)키로 값(String) 조회, 없으면 defaultValue.
setProperty(String key, String value)키-값(String) 설정.
load(InputStream inStream)바이트 스트림에서 속성 로드.
load(Reader reader)문자 스트림에서 속성 로드.
store(OutputStream out, String comments)속성 저장 (바이트 스트림, 주석).
store(Writer writer, String comments)속성 저장 (문자 스트림, 주석).
stringPropertyNames()모든 키(String) Set 반환.
propertyNames()모든 키(String) Enumeration 반환 (Legacy).
list(PrintStream out)속성 목록 출력 (PrintStream).
list(PrintWriter out)속성 목록 출력 (PrintWriter).
defaults()기본 속성 객체 반환.
getProperty(String key, Properties defaults)키로 속성 검색, 없으면 기본 속성에서 검색.
save(OutputStream out, String comments)속성 저장 (Legacy, 예외 처리 다름).
profile
백엔드 개발자 지망생입니다.

0개의 댓글