본문 바로가기
  • soobinhand의 기술 블로그
도서/자바 프로그래밍 언어 - James Gosling

[자바 프로그래밍 언어] 21장 컬렉션

by soobinhand 2022. 1. 9.
728x90

21.1     컬렉션

  • 컨테이너라고도 부르는 컬렉션은 객체를 효율적인 방법으로 접근할 수 있도록 저장하고 구성한다.
  • java.util 패키지에는 제네릭 컬렉션 프레임워크를 제공하는 인터페이스와 클래스들이 있다. 이 프레임워크는 일관되고 유연한 컬렉션 인터페이스 집합과 이 인터페이스들을 구현한 유용한 클래스들을 제공한다.
  • 컬렉션 인터페이스는 다음과 같다.
    • Collection<E> - 컬렉션의 최상위 인터페이스. add, remove, size, toArray와 같은 메소드를 제공한다.
    • Set<E> - 중복된 요소를 포함할 수 없는 컬렉션이며 요소들은 특정 순서로 저장되지 않는다.
    • SortedSet<E> - 요소들을 정렬하여 관리하는 집합. Set을 확장한 것.
    • List<E> - 리스트가 수정되지 않는 동안은 요소들을 특정 순서로 관리하는 컬렉션.
    • Queue<E> - 내부적인 순서로 요소들을 관리하는 컬렉션. 모든 큐는 peek과 poll과 같은 특정 연산의 대상이 되는 헤드 요소를 가져야 한다.
    • Map<K,V> - 키를 한 개의 값에 매핑한다. 맵과 컬렉션 모두 동일한 이름의 메소드로 개념을 표현하고 맵이 컬렉션으로 보여질 수 있지만 Map은 Collection을 확장하지 않는다.
    • SortedMap<K,V> - 키가 정렬된 맵. 맵을 확장.
    • Iterator<E> - 컬렉션에서 한 번에 한 개의 요소를 반환하는 객체들을 위한 인터페이스. 이것은 Iterable.iterator 메소드로 반환된 객체의 타입이다.
    • ListIterator<E> - List와 관련된 유용한 메소드를 추가한 List객체들을 위한 반복자.
    • Iterable<E> - Iterator를 제공하는 객체이며 향상된 for문에서 사용할 수 있다.
  • java.util 패키지는 대부분의 필요성을 만족시킬 수 있도록 위의 인터페이스를 구현한 유용한 클래스들을 제공한다.
    • HashSet<E> - 해시 테이블로 구현된 Set. 검색, 추가, 제거를 위한 범용적인 구현은 내용의 크기에 거의 영향을 받지 않는다.
    • TreeSet<E> - 균형 이진 트리로 구현된 SortedSet. 요소를 정렬해서 유지하며 HashSet보다 검색과 수정이 느림.
    • ArrayList<E> - 가변 길이 배열을 사용하여 구현된 List. 리스트가 클 경우 앞부분에 요소를 추가하고 삭제하는데 비용이 많이 들지만 생성하는 비용은 비교적 싸게 든다. 또한 빠르게 임의 접근할 수 있다.
    • LinkedList<E> - List와 Queue를 구현한 이중 연결 리스트. 어떤 크기에서든 수정 비용은 싸지만 임의 접근은 느리다.
    • HashMap<K,V> - Map의 해시 테이블 구현체. 검색과 삽입 시간이 비교적 싸게드는 매우 일반적이면서도 유용한 컬렉션이다.
    • TreeMap<K,V> - SortedMap을 구현한 요소들을 키로 정렬한 균형 이진 트리. 키를 사용하여 검색을 빠르게 해야 하는 정렬된 데이터 집합에서 유용하다.

21.2     반복

  • Collection<E>는 Iterable<E>를 확장하고 있으며 Iterable<E> 인터페이스는 Iterable<E> 인터페이스를 구현하는 객체를 반환하는 iterator 메소드를 정의하고 있다.
    • public boolean hasNext()
    • 반복할 수 있는 요소가 더 있다면 true.
    • public E next()
    • 반복하는 동안 다음 요소를 반환한다.
  • ListIterator<E> 인터페이스는 Iterator<E>를 확장하며 반복하는 동안 순서화된 List 객체를 조작할 수 있는 메소드를 가지고 있다. 그래서 hasNext와 next를 사용하여 앞쪽으로 반복할 수 있으며 hasPrevious와 previous를 사용하면 뒤쪽으로 반복할 수 있다.
  • remove의 협약은 remove가 호출되고 next나 previous의 마지막 호출 이후에 set이나 add를 호출하면 IllegalStateException이 발생하게 되어있다.
  • Iterator와 ListIterator의 협약은 스냅샷 보장을 포함하지 않는다. 즉, 컬렉션의 내용을 반복하는 동안 수정하면 이는 메소드가 반환한 값에 영향을 줄 수 있다.

21.3     Comparable과 Comparator로 순서화하기

  • 객체를 정렬할 필요가 있는 클래스들은 java.lang.Comparable<T> 인터페이스를 구현해야 한다. 이 인터페이스는 한 개의 메소드를 가지고 있다.
    • public int compareTo(T other)
    • 객체가 other 객체보다 작거나 같거나 크다면 0보다 작거나 같거나 큰 값을 반환한다. 이 메소드는 동일한 객체에 equals 메소드를 사용했을 때 true를 반환할 경우에만 0을 반환한다.
  • 주어진 클래스가 Comparable를 구현하지 않았거나 자연적인 순서화가 어떤 목적으로든 올바르지 않다면 Comparator 객체를 제공해야 한다. Comparator<T> 인터페이스는 다음과 같은 메소드를 가지고 있다.
    • public int compare(T o1, T o2)
    • 제공된 두 개의 객체에 대해 compareTo와 같은 방법으로 순서화를 제공한다.

21.4     Collection 인터페이스

  • 이미 살펴본 것처럼 대부분의 컬렉션 타입들은 Collection 인터페이스의 서브 타입이다. Map의 서브 타입들은 이에 해당하지 않는다.
  • 컬렉션 시스템의 기반은 Collection 인터페이스이다.
  • 매개변수를 가지지 않은 toArray메소드는 Object 객체를 반환한다. toArray(T[])메소드를 사용해 다른 타입의 배열을 생성할 수 있다.

21.5     Set과 SortedSet

  • Set<E> 인터페이스는 Collection<E>를 확장하며 메소드를 위한 더 구체적인 협약을 제공한다. 하지만 Set<E>만을 위한 새로운 메소드를 추가하고 있지는 않다. Set 컬렉션은 중복된 요소를 포함할 수 없다. 만약 동일한 요소를 set에 두 번 추가한다면 첫 번째 호출은 true를 반환하지만 두 번째 호출은 false를 반환한다.
  • SortedSet 인터페이스 상에서의 Iterator는 항상 지정된 순서로 요소들을 반환할 것이다. 기본적으로 요소들의 순서는 자연적인 순서가 될 것이다.
    • public Comparator<? super E> comparator()
    • SortedSet에서 사용할 Comparator를 반환한다. 만약 자연적 순서가 요소들에 사용되었다면 null 값을 반환한다.
    • public E first()
    • Set에서 첫 번째 객체를 반환한다.
    • public E last()
    • Set에서 마지막 객체를 반환한다.
    • public SortedSet<E> subSet ( E min, E max )
    • Set에서 min보다 같거나 크고 max보다 작은 요소들을 포함하는 Set의 뷰를 반환한다.
    • public SortedSet<E> headSet(E max)
    • max보다 작은 값들을 가지는 Set의 모든 요소를 포함하는 Set의 뷰를 반환한다.
    • public SortedSet<E> tailSet(E min)
    • min보다 큰 값들을 가지는 Set의 모든 요소를 포함하는 Set의 뷰를 반환한다.
  • HashSet은 해시 테이블로 구현된 Set<E>이다. HashSet의 내용을 수정하거나 검사하는 것은 O(1) 걸린다. 즉 Set의 크기가 증가하더라도 더 많은 시간을 필요로 하지 않는다.
  • LinkedHashSet<E>는 HashSet<E>를 확장하며 Set내에서의 요소들의 순서를 정의하여 HashSet의 협약을 변경하고 있다. LinkedHashSet의 내용을 반복할 때 요소들은 추가된 순서인 삽입 순서로 반환될 것이다.
  • TreeSet은 요소들을 균형 잡힌 트리 구조로 저장한다.

21.6     List

  • List<E> 인터페이스는 Collection<E>를 확장하며 요소들을 정의된 순서로 보유하는 컬렉션을 정의한다.
  • public E get(int index)
  • index번재의 항목을 반환한다.
  • public E set(int index, E elem)
  • index 번째의 항목을 elem으로 설정한다. 또한 이전 요소를 반환한다.
  • public void add(int index, E elem)
  • elem을 리스트의 index 번째에 추가한다.
  • public E remove(int index)
  • 리스트에서 index번째 항목을 제거하고 반환한다.
  • public int indexOf(Object elem)
  • 리스트에서 elem과 같은 첫 번째 객체의 인덱스를 반환한다.
  • public int lastIndexOf(Object elem)
  • 리스트에서 elem과 일치하는 마지막 객체의 인덱스를 반환한다.
  • public List<E> subList(int min, int max)
  • 현재 리스트의 min부터 max를 포함하지 않는 범위 내의 부분 List를 반환한다. 
  • 그래서 list.subList(min, max).clear()를 사용하여 리스트의 일부분을 제거할 수 있다.
  • ArrayList는 배열 기반으로 요소들을 저장하는 기본적인 리스트 구현체이다. ArrayList 끝에서 요소들을 추가하고 제거하는 것이 매우 단순하다. 그래서 O(1)이다. 
  • 추가된 요소는 배열에 저장되며 저장할 공간이 없는 경우엔 새로운 배열을 할당해야 한다.
  • LinkedList는 이중 링크드 리스트이며 성능 특징은 사실상 ArrayList와 반대이다. 요소를 끝에 추가하는 것은 O(1)이지만 이 외에는 더 많은 비용이 든다. 요소를 중간에 추가하거나 제거하는 것은 어떤 복사도 필요하지 않기 때문에 O(1)이다.
  • LinkedList는 큐를 작성하기 위한 좋은 기반이며 실제로 다음에 살펴볼 Queue 인터페이스를 구현하고 있기도 하다.
  • 자주 검색해야 하는 리스트를 위해서는 ArrayList를 사용하는 것이 바람직함.
  • 가능하면 변수를 추상 타입으로 선언해야 하며 구현 클래스인 ArrayList보다는 추상 List를 선호해야 한다.
  • 마커 인터페이스 RandomAccess는 고속 임의 접근을 지원하는 리스트 구현체들을 표시한다. 임의 접근은 리스트의 어떤 요소라도 바로 접근할 수 있다는 것을 의미한다.
  • ArrayList는 인덱스로 요소를 쉽게 접근할 수 있기에 RandomAccess를 구현하고 있다. 이와 대조적으로 LinkedList는 요소를 한 쪽 끝에서부터 접근하므로 RandomAccess를 구현하고 있지 않다.
  • RandomAccess의 목적은 주어진 리스트의 종류에 따라 알고리즘을 다르게 적용하는 것이다.

21.7     Queue

  • Queue<E> 인터페이스는 Collection<E>를 확장하며 컬렉션의 내부 구성에 약간의 구성을 추가하고 있다. 큐는 제거될 다음 요소인 헤드 위치를 정의한다. 
    • public E element()
    • 큐의 헤드를 반환하며 이를 제거하지는 않는다. 큐가 비어있다면 예외 발생
    • public E peek()
    • 큐의 헤드를 반환하며 이를 제거하지는 않는다. 큐가 비어있다면 null을 발생.
    • public E remove()
    • 큐의 헤드를 반환하며 이를 제거한다. 큐가 비어있다면 예외 발생
    • public E poll()
    • 큐의 헤드를 반환하며 이를 제거한다. 큐가 비어있다면 null을 발생
    • public void offer(E elem)
    • 주어진 요소를 큐에 삽입
  • Queue 구현체 중에는 PriorityQueue가 있다. 이 큐는 제한되지 않은 큐로, 우선순위 힙에 기반한 큐이다. 큐의 헤드는 큐에서 가장 작은 요소며 헤드는 요소들의 자연적 순서나 제공된 Comparator에 의해 결정된다.

21.8     Map과 SortedMap

  • 인터페이스 Map<K,V>는 Collection을 상속하지 않는다. 왜냐하면 Map<K,V>는 Collection과는 다른 협약을 가지고 있기 때문이다. 주요 다른 점은 Map에 요소만을 추가하지 못한다는 것이다. 추가하려면 키와 값을 한 쌍으로 추가해야 한다. Map은 키로 저장된 값을 찾을 수 있게 해준다. 주어진 키는 하나의 값이나 값이 아닌 것들과 연결된다. 한 개의 값은 원하는 만큼의 많은 키들에 의해 매핑될 수 있다.
    • public boolean containsKey(Object key)
    • 주어진 키에 대한 매핑을 가지고 있다면 true를 반환한다.
    • public boolean containsValue(Object value)
    • 주어진 값에 대한 적어도 한 개의 매핑을 가지고 있다면 true 반환.
    • public V get(Object key)
    • 키가 매핑하고 있는 객체를 반환한다.
    • public V put(K key, V value)
    • Map에서 key를 주어진 value로 연관시킨다. Map에 이미 key가 존재한다면 이 key값을 변경하고 변경되기 전의 원래 값을 반환한다.
    • public V remove(Object key)
    • key의 매핑을 제거한다. 반환 값을 put의 반환 값과 동일.
  • HashMap에서 containsKey는 O(1)인 반면, containsValue는 O(n)이다. 왜냐하면 키는 hash 기법에 의해 찾을 수 있지만 값은 일치되는 것이 발견될 때까지 각각의 요소들을 탐색해야 하기 때문이다.
  • HashMap은 Map을 해시 테이블로 구현한다.
  • LinkedHashMap은 해시맵을 확장하며 해시맵의 협약을 개선하여 맵의 엔트리들의 순서를 정의한다.
  • 반복 시에 용량에 관계 없이 오직 크기에 비례한 시간만이 필요하다.

21.9     enum 컬렉션

  • 추상 클래스 EnumSet<E extends Enum<E>>은 특정 enum타입에 대한 모든 enum상수인 요소들의 집합을 나타낸다.
  • EnumMap<K extends Enum<K>, V>은 enum값을 키로 사용하는 특별한 맵이다. 맵의 모든 값은 동일한 enum 타입이어야 한다.

21.10     래퍼 컬렉션과 Collections 클래스

21.11     동기화된 래퍼와 병렬 컬렉션

21.12     Arrays 유틸리티 클래스

21.13     Iterator 구현하기

21.14     컬렉션 구현하기

21.15     레거시 컬렉션 타입

21.16     Properties

728x90

댓글