컬렉션(Collection)의 개념
컬렉션은 여러 객체를 하나의 단위로 다룰 수 있도록 해주는 자료구조입니다. 자바 컬렉션 프레임워크는 데이터를 저장하고 관리하는 여러 가지 방법을 제공하며, 다양한 종류의 리스트(List), 셋(Set), 맵(Map) 등의 컬렉션을 포함하고 있습니다.
자바 컬렉션 프레임워크는 다음과 같은 두 가지 주요 인터페이스를 기반으로 구성됩니다:
- Collection: 객체의 집합을 나타내는 최상위 인터페이스.
- Map: 키와 값의 쌍을 저장하는 객체를 나타내는 인터페이스.
컬렉션을 위한 자바 인터페이스와 클래스
자바 컬렉션 프레임워크의 주요 인터페이스와 클래스는 다음과 같습니다:
1. List 인터페이스
- 순서가 있는 컬렉션으로, 중복을 허용합니다.
- 주요 구현 클래스: ArrayList, LinkedList, Vector
2. Set 인터페이스
- 순서가 없고 중복을 허용하지 않는 컬렉션입니다.
- 주요 구현 클래스: HashSet, TreeSet
3. Map 인터페이스
- 키와 값의 쌍으로 데이터를 저장하는 컬렉션입니다.
- 주요 구현 클래스: HashMap, TreeMap, LinkedHashMap
4. Queue 인터페이스
- FIFO(First-In, First-Out) 방식으로 데이터를 처리하는 컬렉션입니다.
- 주요 구현 클래스: LinkedList, PriorityQueue
5. Deque 인터페이스
- 양방향 큐(Double-ended Queue)로, 앞뒤에서 데이터 삽입 및 삭제가 가능합니다.
- 주요 구현 클래스: ArrayDeque
컬렉션과 제네릭
자바 컬렉션 프레임워크는 **제네릭(Generic)**을 사용하여 컬렉션에 저장되는 객체의 타입을 지정할 수 있습니다. 이를 통해 타입 안정성을 확보하고, 실행 시 발생할 수 있는 타입 불일치 오류를 컴파일 시점에서 처리할 수 있습니다.
예를 들어, ArrayList에서 Integer만 저장할 수 있도록 제네릭을 사용할 수 있습니다:
ArrayList<Integer> list = new ArrayList<>();
list.add(1); // OK
list.add("Hello"); // 컴파일 오류
제네릭을 사용하면 컬렉션에 저장되는 객체의 타입을 명확히 지정할 수 있어 코드의 안정성을 높이고, 타입 캐스팅을 줄일 수 있습니다.
주요 컬렉션 클래스 및 예시
1. Vector<E>
Vector는 ArrayList와 유사하지만, 동기화(synchronization)를 지원하여 멀티스레딩 환경에서 안전하게 사용됩니다. 하지만 성능 면에서는 동기화로 인해 다소 느릴 수 있습니다.
Vector<Integer> vector = new Vector<>();
vector.add(1);
vector.add(2);
2. ArrayList<E>
ArrayList는 동적 배열을 사용하여 데이터를 저장하는 클래스입니다. 순서가 있고, 중복된 요소를 허용합니다. 크기가 자동으로 조정되며, 빠른 임의 접근을 제공합니다.
ArrayList<String> list = new ArrayList<>();
list.add("Apple");
list.add("Banana");
3. Iterator
Iterator는 컬렉션의 요소를 순차적으로 접근하는 인터페이스입니다. hasNext()와 next() 메소드를 통해 컬렉션의 모든 요소를 순차적으로 탐색할 수 있습니다.
ArrayList<String> list = new ArrayList<>();
list.add("Apple");
list.add("Banana");
Iterator<String> iterator = list.iterator();
while (iterator.hasNext()) {
System.out.println(iterator.next());
}
4. HashMap<K, V>
HashMap은 키와 값을 쌍으로 저장하는 자료구조입니다. 키는 유일하고, 값은 중복될 수 있습니다. 빠른 검색을 제공하지만, 저장 순서는 보장하지 않습니다.
HashMap<String, Integer> map = new HashMap<>();
map.put("Alice", 25);
map.put("Bob", 30);
5. LinkedList<E>
LinkedList는 각 요소가 노드로 연결된 자료구조로, 삽입과 삭제에 유리합니다. List와 Queue 인터페이스를 구현하여 두 가지 방식으로 사용할 수 있습니다.
LinkedList<String> list = new LinkedList<>();
list.add("Apple");
list.add("Banana");
6. Stack<E>
Stack은 LIFO(Last-In-First-Out) 방식으로 데이터를 처리하는 클래스입니다. 주로 재귀적인 문제나 함수 호출 스택을 처리할 때 사용됩니다.
Stack<String> stack = new Stack<>();
stack.push("Apple");
stack.push("Banana");
System.out.println(stack.pop()); // Banana
7. Collections
Collections 클래스는 컬렉션을 다루는 유틸리티 클래스로, 정렬, 역순, 동기화 등을 지원하는 여러 정적 메소드를 제공합니다.
List<Integer> list = new ArrayList<>();
list.add(3);
list.add(1);
list.add(2);
Collections.sort(list); // 리스트를 오름차순으로 정렬
제네릭 컬렉션
자바 컬렉션에서 제네릭은 매우 중요한 역할을 합니다. 제네릭을 활용하면 타입 안전성을 높이고, 불필요한 타입 캐스팅을 방지할 수 있습니다. 제네릭을 사용하면 특정 타입만 저장할 수 있는 컬렉션을 만들 수 있기 때문에 컴파일 시점에서 타입 체크가 이루어집니다.
제네릭 컬렉션의 예시
// Integer만 저장할 수 있는 ArrayList
ArrayList<Integer> intList = new ArrayList<>();
intList.add(10); // OK
intList.add("Hello"); // 컴파일 오류
제네릭을 사용하면 타입을 명시할 수 있어 코드의 안정성을 높이고, 실행 시 타입 불일치를 방지할 수 있습니다.
결론
자바의 컬렉션 프레임워크는 데이터를 효율적으로 저장하고 처리할 수 있는 다양한 클래스와 인터페이스를 제공합니다. 제네릭을 활용하면 타입 안전성을 확보할 수 있으며, 컬렉션을 사용하여 데이터를 관리하는 데 있어 많은 편리함을 제공합니다. 각 컬렉션 클래스들은 특정 용도와 목적에 맞게 사용되므로, 데이터를 어떻게 처리할 것인지에 따라 적합한 클래스를 선택하는 것이 중요합니다.