Lesson: Implementations

Dev.Hammy·2024년 1월 19일

Java API

목록 보기
15/15

implementation은 인터페이스 섹션에 설명된 인터페이스를 구현하는 컬렉션을 저장하는 데 사용되는 data object입니다. 이 강의에서는 다음과 같은 종류의 구현을 설명합니다.

  • General-purpose implementations : 범용 구현은 일상적인 사용을 위해 설계된 가장 일반적으로 사용되는 구현입니다. 이는 범용 구현이라는 제목의 표에 요약되어 있습니다.
  • Special-purpose implementations : 특수 목적 구현은 특수한 상황에서 사용하도록 설계되었으며 비표준 성능 특성, 사용 제한 또는 동작을 표시합니다.
  • Concurrent implementations : 동시 구현은 일반적으로 단일 스레드 성능을 희생하면서(expense of) 높은 동시성을 지원하도록 설계되었습니다. 이러한 구현은 java.util.concurrent 패키지의 일부입니다.
  • Wrapper implementations : 래퍼 구현은 추가되거나 제한된 기능을 제공하기 위해 다른 유형의 구현(종종 범용 구현)과 함께 사용됩니다.
  • Convenience implementations : 편의 구현은 특수 컬렉션(예: 싱글톤 세트)에 대한 범용 구현에 대한 편리하고 효율적인 대안을 제공하는 일반적으로 정적 팩토리 메서드를 통해 제공되는 미니 구현입니다.
  • Abstract implementations : 추상 구현은 사용자 정의 구현의 구성을 용이하게 하는 뼈대 구현입니다. 나중에 사용자 정의 컬렉션 구현 섹션에서 설명합니다. 고급 주제이므로 특별히 어렵지는 않지만 이 작업을 수행해야 하는 사람은 상대적으로 적습니다.

범용 구현은 다음 표에 요약되어 있습니다.

General-purpose Implementations
Interfaces Hash table Implementations Resizable array Implementations Tree Implementations Linked list Implementations Hash table + Linked list Implementations
Set HashSet   TreeSet   LinkedHashSet
List   ArrayList   LinkedList  
Queue          
Deque   ArrayDeque   LinkedList  
Map HashMap   TreeMap   LinkedHashMap

표에서 볼 수 있듯이 Java 컬렉션 프레임워크는 Set, ListMap 인터페이스의 여러 범용 구현을 제공합니다. 각각의 경우에 하나의 구현(HashSet, ArrayListHashMap)은 확실히 대부분의 애플리케이션에 사용되는 구현이며 다른 모든 항목은 동일합니다. SortedSetSortedMap 인터페이스에는 테이블에 행이 없습니다. 각 인터페이스에는 하나의 구현(TreeSetTreeMap)이 있으며 SetMap 행에 나열됩니다. 두 가지 범용 대기열 구현이 있습니다. LinkedListList 구현이기도 하고, PriorityQueue는 표에서 생략되었습니다. 이 두 구현은 매우 다른 의미를 제공합니다. LinkedList는 FIFO 의미를 제공하는 반면 PriorityQueue는 해당 값에 따라 요소의 순서를 지정합니다.

각 범용 구현은 해당 인터페이스에 포함된 모든 선택적 작업을 제공합니다. 모두 null 요소, 키 및 값을 허용합니다. 동기화(synchronized)된 항목은 없습니다(thread-safe). 모두에는 iteration 중에 불법적인 동시 수정을 감지하고 미래의 불확실한 시간(undetermined time)에 임의적이고(arbitrary) 비결정적인(non-deterministic) 동작을 위험에 빠뜨리는 대신 빠르고 깔끔하게 실패하는 fail-fast iterators가 있습니다. 모두 직렬화 가능(Serializable)하며 모두 public clone 메서드을 지원합니다.

이러한 구현이 동기화되지 않았다는 사실은 과거와의 단절을 나타냅니다. 레거시 컬렉션 VectorHashtable은 동기화됩니다. 동기화가 아무런 이점이 없을 때 컬렉션이 자주 사용되기 때문에 현재 접근 방식을 취했습니다. 이러한 용도에는 단일 스레드(single-threaded) 사용, 읽기 전용(read-only) 사용 및 자체 동기화(own synchronization)를 수행하는 더 큰 데이터 개체의 일부로 사용이 포함됩니다. 일반적으로 사용자가 사용하지 않는 기능에 대해 비용을 지불하도록 하지 않는 것이 좋은 API 설계 방식입니다. 또한 불필요한 동기화로 인해 특정 상황에서 교착 상태(deadlock)가 발생할 수 있습니다.

스레드로부터 안전한(thread-safe) 컬렉션이 필요한 경우 래퍼 구현 섹션에 설명된 동기화 래퍼를 사용하면 모든 컬렉션을 동기화된 컬렉션으로 변환할 수 있습니다. 따라서 동기화는 범용 구현에서는 선택 사항이지만 레거시 구현에서는 필수입니다. 또한 java.util.concurrent 패키지는 Queue를 확장하는 BlockingQueue 인터페이스와 Map을 확장하는 ConcurrentMap 인터페이스의 동시 구현(concurrent implementation)을 제공합니다. 이러한 구현은 단순한 동기화 구현보다 훨씬 높은 동시성을 제공합니다.

원칙적으로(As a rule) 구현이 아닌 인터페이스에 대해 생각해야 합니다. 이것이 바로 이 섹션에 프로그래밍 예제가 없는 이유입니다. 대부분의 경우 구현 선택은 성능에만 영향을 미칩니다. 인터페이스 섹션에서 언급한 대로 선호되는 스타일은 Collection이 생성될 때 구현을 선택하고 새 컬렉션을 해당 인터페이스 유형의 변수에 즉시 할당하는 것입니다(또는 인터페이스 타입의 인수를 기대하는 메서드에 컬렉션을 전달하는 것입니다). 이러한 방식으로 프로그램은 주어진 구현에 추가된 메서드에 종속되지 않으므로 프로그래머는 성능 문제나 동작 세부 사항에 의해 보장되는 경우 언제든지 구현을 자유롭게 변경할 수 있습니다.

다음 섹션에서는 구현에 대해 간략하게 설명합니다. 구현의 성능은 작업 수행의 시간 복잡도에 대한 점근적(asymptotic) 상한을 참조하기 위해 상수 시간(constant-time), 로그(log), 선형(linear), n log(n) 및 quadratic와 같은 단어를 사용하여 설명됩니다. 이 모든 것은 꽤 많은 내용이며, 그것이 무엇을 의미하는지 모른다면 별로 중요하지 않습니다. 더 알고 싶다면 좋은 알고리즘 교과서를 참조하세요. 한 가지 명심해야 할 점은 이러한 종류의 성능 지표에는 한계가 있다는 것입니다. 때로는 명목상 느린 구현이 더 빠를 수도 있습니다. 의심스러울 때는 성능을 측정해 보세요!

0개의 댓글