자바의 정석 책을 공부하고 정리한 글입니다!
혹시라도 틀린 부분이 있다면 친절하게 알려주세요.
감사합니다!
CH11. 컬렉션 프레임워크(1)
컬렉션 프레임워크란 컬렉션을 저장하는 클래스들을 표준화한 설계를 의미합니다.
- 컬렉션(collection): 여러 객체를 모아 놓은 것
- 프레임워크(framework): 표준화된 프로그램 방식
컬렉션 프레임워크의 핵심 인터페이스는 다음과 같습니다:
- List
순서가 있는 데이터의 집합으로 데이터의 중복을 허용한다. 구현 클래스로는 ArrayList, LinkedList, Stack, Vector 등이 있다. - Set
순서를 유지하지 않는 데이터의 집합으로 데이터의 중복을 허용하지 않는다. 구현 클래스로는 HashSet, TreeSet 등이 있다. - Map
키(key):값(value)의 쌍으로 이루어진 데이터의 집합이다. Map의 경우 순서는 유지되지 않으며, 키는 중복을 허용하지 않지만, 값은 중복을 허용한다. 쿠현 클래스로는 HashMap, TreeMap, HashTable, Properties 등이 있다.
이 중, List와 Set 인터페이스의 공통 부분을 뽑아낸 것을 Collection 인터페이스라 하며, 다음과 같은 메서드가 있습니다.
스택과 큐
1. 스택(Stack)
스택이란 데이터를 하니씩 쌓아 올린 형태의 자료 구조로, 가장 나중에 들어온 데이터가 가장 먼저 나가는 후입선출(LIFO) 구조입니다. 예를 들어, 스택에 1, 2, 3의 순서로 데이터를 넣었다면 꺼낼 때는 3, 2, 1 순서로 나오게 됩니다.
스택에서 가장 최근에 들어온 데이터는 top이라 부르며, 기본적으로 push로 저장, pop으로 값을 제거합니다.
주요 메서드는 다음과 같습니다.
2. 큐(Queue)
큐는 스택과 반대로 가장 먼저 들어온 데이터가 가장 먼저 나가는 선입선출(FIFO) 구조입니다. 예를 들어, 큐에 1, 2, 3을 순차적으로 넣었다면 꺼낼 때도 1, 2, 3으로 나오게 됩니다.
큐에서 가장 먼저 들어온 요소를 head라 부르며, offer/add를 통해 저장, poll/remove를 통해 제거합니다.
주요 메서드는 다음과 같습니다.
메서드 | 설명 |
boolean add(Object o) | 큐의 마지막에 요소 추가 (공간이 부족하면 IllegalStateException 예외 발생) |
boolean offer(Object o) | 큐의 마지막에 요소 추가 (공간이 부족하면 false 반환) |
Object remove() | 큐의 head 값 제거한 후 반환 (큐가 비어있으면 NoSuchElementException 예외 발생) |
Object poll() | 큐의 head 값 제거한 후 반환 (큐가 비어있으면 null 반환) |
Object element() | 큐의 head 값을 제거하지 않고 반환 (큐가 비어있으면 NoSuchElementException 예외 발생) |
Object peek() | 큐의 head 값을 제거하지 않고 반환 (큐가 비어있으면 null 반환) |
큐는 인터페이스이며, 보통 LinkedList나 ArrayDeque와 같은 클래스가 이를 구현합니다.
3. 우선순위 큐(PriorityQueue)
우선순위 큐는 Queue인터페이스의 구현체 중 하나로 요소가 들어간 순서가 아닌, 우선순위가 높은 것부터 꺼내는 큐입니다. 또한, null은 저장하면 우선순위를 판단할 수 없기 때문에 저장할 수 없으며, 저장하게 되면 NullPointException이 발생합니다.
기본적으로 오름차순으로 정렬되며, 사용자가 지정한 Comparator에 의해 우선순위가 정해집니다.
우선순위 큐는 저장공간으로 배열을 사용하며, 각 요소를 heap이라는 자료구조의 형태로 저장합니다.
4. 덱(Deque)
덱은 Double Ended Queue의 약자로, 양쪽 끝에서 모두 요소를 삽입하고 제거할 수 있는 양방향 큐입니다. 따라서 덱은 스택과 큐의 특징을 모두 가질 수 있습니다.
Iterator, ListIterator, Enumeration
Iterator, ListIterator, Enumeration은 모두 컬렉션에 저장된 요소를 접근하는데 사용되는 인터페이스입니다.
1. Iterator
Iterator인터페이스는 컬렉션에 저장된 각 요소에 접근하는 기능을 가진 인터페이스로, Collection인터페이스에는 Iterator를 반환하는 iterator()를 정의하고 있습니다.
Iterator인터페이스의 주요 메서드는 다음과 같습니다.
메서드를 사용할 때는 다음과 같은 주의사항이 있습니다:
- next()를 호출하기 전에는 반드시 hasNext()를 호출하여, 다음 요소가 있는지 없는지 확인해야 한다. 그렇지 않으면 NoSuchElementException 예외가 발생할 수도 있다.
- remove()는 직전에 next()로 반환된 요소만 삭제가 가능하며, next() 호출 없이 remove()를 사용하면 IllegalStateException 예외가 발생한다.
- remove()는 선택적 기능이므로 구현 클래스에서 반드시 지원할 필요가 없다. 이런 경우, remove()를 호출하면 UnsupportedOperationException 예외가 발생한다
Iterator는 컬렉션의 요소를 읽어오는 방법을 표준화한 것이기 때문에 코드의 재사용성을 높이는 것이 가능합니다.
Collection c = new ArrayList(); // 다른 컬렉션으로 변경하고 싶다면 ArrayList만 변경하면 된다.
Iterator it = c.iterator();
while(it.hasNext()) {
System.out.println(it.next());
}
이처럼 공통 인터페이스로 표준을 정의하고 구현체에서 표준을 따르도록 하면, 코드의 일관성을 유지하여 재사용성을 극대화할 수 있습니다. 이는 객체지향 프로그래밍의 중요한 목적 중 하나입니다.
Map인터페이스를 구현한 컬렉션 클래스는 key와 value을 쌍으로 저장하고 있기 때문에 iterator()를 직접 호출할 수 없습니다. 따라서 keySet()이나 entrySet()과 같은 메서드를 통해 key, value를 각각 Set 형태로 변형한 후에 iterator()를 호출할 수 있습니다.
2. ListIterator와 Enumeration
- Enumeration
컬렉션 프레임워크가 만들어지기 전에 사용하던 것으로 Iterator의 구버전이다. 웬만하면 Enumeration 대신에 Iterator를 사용하는 것이 좋다. - ListIterator
Iterator를 상속받아 기능을 추가한 것으로, 양방향으로의 이동이 가능하다. 다만 List를 구현한 컬렉션만 사용할 수 있다.
Arrays
Arrays클래스에는 배열을 다루는데 유용한 메서드가 정의되어 있으며 Arrays에 정의된 메서드는 모두 static메서드입니다.
1. 배열의 복사 - copyOf(), copyOfRange()
- copyOf(): 배열 전체를 복사해 새로운 배열을 만들어 반환
- copyOfRange(): 배열의 일부를 복사해 새로운 배열을 만들어 반환
int[] arr = {0, 1, 2, 3, 4};
int[] arr2 = Arrays.copyOf(arr, arr.length); // [0, 1, 2, 3, 4]
int[] arr3 = Arrays.copyOf(arr, 3); // [0, 1, 2]
int[] arr4 = Arrays.copyOfRange(arr, 2, 4); // [2, 3] -> 4는 포함하지 않는다.
2. 배열 채우기 - fill(), setAll()
- fill(): 배열의 모든 요소를 지정된 값으로 채운다.
- setAll(): 배열을 채우는데 사용할 함수형 인터페이스를 매개변수로 받는다. 따라서 이 메서드를 호출할 때는 함수형 인터페이스를 구현한 객체를 매개변수로 지정하거나 람다식을 지정해야 한다.
함수형 인터페이스란 딱 하나의 추상 메서드만 가지는 인터페이스를 말합니다.
3. 배열의 정렬과 검색 - sort(), binarySearch()
- sort(): 배열을 정렬할 때 사용하며 오름차순으로 정렬된다.
- binarySearch(): 배열에 저장된 요소를 검색할 때 사용하며, 반드시 정렬된 상태여야 올바른 결과를 얻을 수 있다. binarySearch(arr, 2)와 같은 형태로 사용하며, 2가 저장된 인덱스 값을 반환한다.
4. 배열의 비교와 출력 - equals(), toString()
- equals(): 두 배열에 저장된 모든 요소를 비교한다.
- toString(): 배열의 모든 요소를 문자열로 편하게 출력할 수 있다.
equals(), toString()는 모두 1차원 배열에서만 사용할 수 있습니다.
5. 배열을 List로 변환 - asList(Object... a)
다음과 같은 형태로 사용할 수 있습니다.
List list1 = Arrays.asList(new Integer[]{1, 2, 3,});
List list2 = Arrays.asList(1, 2, 3);
이렇게 asList()로 변환한 리스트는 크기를 변경할 수 없어 삭제 또는 추가가 불가능합니다.
만약 크기를 변경할 수 있는 List가 필요하다면 다음과 같이 사용해야 합니다.
List list = new ArrayList(Arrays.asList(1, 2, 3, 4, 5));
Comparator와 Comparable
Comparator와 Comparable은 모두 인터페이스로 컬렉션을 정렬하는데 필요한 메서드를 정의하고 있습니다.
Comparable을 구현하고 있는 클래스들은 같은 타입의 인스턴스끼리 서로 비교할 수 있는 클래스(wrapper클래스와 String, Date 등)이며, 기본적으로 오름차순으로 정렬되도록 구현되어 있습니다.
다음은 Comparator와 Comparable의 소스 코드의 일부입니다.
public interface Comparator {
int compare(Object o1, Object o2);
}
public interface Comparable {
public int compareTo(Object o);
}
compare()와 compareTo()는 둘 다 두 객체를 비교하는 목적으로 고안된 것입니다. 둘 다 반환값은 int지만 실제로는 비교하는 두 객체가 같으면 0, 비교하는 값보다 작으면 음수, 크면 양수를 반환하도록 구현해야 합니다.
'도서 정리 > 자바의 정석' 카테고리의 다른 글
[자바의 정석] CH12 지네릭스, 열거형, 애너테이션 (1) | 2025.04.30 |
---|---|
[자바의 정석] CH11 컬렉션 프레임워크(2) (1) | 2025.04.25 |
[자바의 정석] CH10 날씨와 시간 & 형식화 (1) | 2025.04.21 |
[자바의 정석] CH09 java.lang패키지와 유용한 클래스 (1) (0) | 2025.04.16 |
[자바의 정석] CH08 예외처리 (1) | 2025.04.14 |