[이것이 자바다] 15. 컬렉션 프레임워크 1️⃣ List, Set, Map

1. 컬렉션 프레임워크 소개
컬렉션 프레임워크(Collection Framework) 란?
: 다수의 데이터를 쉽고 효과적으로 처리할 수 있는 표준화된 방법을 제공하는 클래스의 집합, 라이브러리를 의미한다. 즉, 데이터를 저장하는 자료 구조와 데이터를 처리하는 알고리즘을 구조화하여 클래스로 구현해 놓은 것이다.
이러한 컬렉션 프레임워크는 자바의 인터페이스(interface)를 사용하여 구현된다.
컬렉션 프레임워크의 주요 인터페이스로는 List
, Set
, Map
이 있다.

이 중에서 List
와 Set
인터페이스는 모두 Collection
인터페이스를 상속받지만, 구조상의 차이로 인해 Map
인터페이스는 별도로 정의된다.
따라서 List
인터페이스와 Set
인터페이스의 공통된 부분을 Collection 인터페이스에서 정의하고 있습니다.

2. List 컬렉션
List
컬렉션은 List
컬렉션은 객체를 일렬로 늘어놓은 구조를 가지고 있다. List 컬렉션은 객체를 인덱스로 관리하기 때문에 객체를 저장하면 자동 인덱스가 부여되고 인덱스로 객체를 검색, 삭제할 수 있는 기능을 제공한다.
List
컬렉션은 객체 자체를 저장하는 것이 아니라 다음 그림과 같이 객체의 번지를 참조한다.

동일한 객체를 중복 저장할 수 있는데 이 경우 동일한 번지가 참조된다. null 또한 저장이 가능하며, 이 경우 해당 인덱스는 객체를 참조하지 않는다.
구현 클래스
- ArrayList
- Vector
- LinkedList

1. ArrayList
ArrayList 란?
: List 인터페이스의 구현 클래스로, ArrayList에 객체를 추가하면 객체가 인덱스로 관리된다.
그렇다면 배열과 다른 점은 무엇인가?
배열은 생성할 때 크기가 고정되고, 사용 중에 크기를 변경할 수 없지만, ArrayList
는 저장 용량을 초과한 객체들이 들어오면 자동적으로 저장 용량이 늘어난다.

ArrayList 선언
//<E> 위치에 원하는 객체타입 명시
List<E> list = new ArrayList<E>();
//타입설정 int타입만 사용가능
ArrayList<Integer> num = new ArrayList<Integer>();
//new에서 타입 파라미터 생략가능
ArrayList<Integer> num2 = new ArrayList<>();
//초기 용량(capacity)지정
ArrayList<Integer> num3 = new ArrayList<Integer>(10);
//생성시 값추가
ArrayList<Integer> list2 = new ArrayList<Integer>(Arrays.asList(1,2,3));
ArrayList
를 생성하고 런타임 시에 객체를 추가하는 것이 일반적이지만, 고정된 객체들로 구성된 List
를 생성할 때도 있다.
이런 경우에는 Arrays.asList(T … a)
메소드를 사용한다.
List<T> list = Arrays.asList(T ... a);
T타입 파라미터에 맞게 asList()
의 매개값을 순차적으로 입력하거나, T[]
배열을 매개값으로 주면 된다.
//생성시 값추가
ArrayList<Integer> list2 = new ArrayList<Integer>(Arrays.asList(1,2,3));
2. Vector
Vector 란?
:ArrayList
와 동일한 내부 구조를 가지나,Vector
는 스레드 환경에서 안전하게 객체를 추가, 삭제할 수 있다.
Vector
는 동기화된 메소드로 구성되어 있으므로 멀티 스레드가 동시에 이 메소드들을 실행할 수 없고, 하나의 스레드가 실행을 완료해야만 다른 스레드들이 실행할 수 있다. 그렇기 때문에 멀티 스레드 환경에서 안전하게 객체를 추가하고 삭제할 수 있다. 이것을 스레드가 안전(Thread Safe) 하다고 한다.

Vector
는 항상 동기화가 된다는 장점이자 단점을 가지고 있다. 스레드가 1개일때도 동기화를 하기 때문에 ArrayList
보다 성능이 떨어진다. Arraylist
는 기본적인 기능은 벡터와 동일하나 자동 동기화 기능이 빠져있고, 동기화 옵션이 존재한다. 또한, Vector
에 비해 속도가 더 빠르기 때문에 Vector
에 비해 많이 쓰인다.
Vector 선언
//저장할 객체 타입을 타입 파라미터로 표기하고 기본 생성자를 호출
List<E> list = new Vector<E>();
//타입설정 int타입만 사용가능
Vector<Integer> num1 = new Vector<Integer>();
//new에서 타입 파라미터 생략가능
Vector<Integer> num2 = new Vector<>();
//초기 용량(capacity)지정
Vector<String> v1 = new Vector<String>(10);
//초기값 지정
Vector<Integer> v2 = new Vector<Integer>(Arrays.asList(1,2,3));
3. LinkedList
LinkedList 란?
: 저장된 객체를 인접 참조를 링크해서 체인처럼 관리한다.

중간에 데이터를 추가나 삭제하더라도 전체의 인덱스가 한 칸씩 뒤로 밀리거나 당겨지는 일이 없기에 ArrayList
에 비해서 데이터의 추가나 삭제가 비교적 쉽다.
하지만 인덱스가 없기에 특정 요소에 접근하기 위해서는 순차 탐색이 필요로 하여 탐색 속도가 떨어진다는 단점이 있다.
그러므로 탐색 또는 정렬을 자주 하는 경우엔 ArrayList
를 사용하고 데이터의 추가, 삭제가 많은 경우 LinkedList
를 사용하는 것이 좋다.
LinkedList 선언
//저장할 객체 타입을 타입 파라미터로 표기하고 기본 생성자를 호출
LinkedList list = new LinkedList();
//타입설정 int타입만 사용가능
LinkedList<Integer> num = new LinkedList<Integer>();
//new에서 타입 파라미터 생략가능
LinkedList<Integer> num2 = new LinkedList<>();
//생성시 값추가
LinkedList<Integer> list2 = new LinkedList<Integer>(Arrays.asList(1,2));
3. Set 컬렉션
Set
컬렉션은 저장 순서가 유지되지 않는다. 또한, 객체를 중복해서 저장할 수 없다.
즉, Set
컬렉션은 인덱스를 관리하지 않으므로, 인덱스를 매개값으로 갖는 메소드가 없다.
Set
의 경우에 값을 추가하거나 삭제할 때 내가 추가 또는 삭제하고자 하는 값이 Set 내부에 존재하는지 한 번 탐색을 한 후에 추가, 삭제를 진행해야하므로 List
구조에 비해 속도가 느리다.

구현 클래스
- HashSet
- TreeSet

Set
컬렉션에는 인덱스로 객체를 검색하여 가져오는 메소드가 없다. 대신 Iterator객체를 반환하는 메소드가 있고, Iterator 객체에서는 hasNext()
, next()
, remove()
를 제공한다.
1. HashSet
HashSet 이란?
Set
인터페이스의 구현 클래스이기 때문에Set
의 성질을 그대로 상속 받는다. 객체들을 순서 없이 저장하고, 동일한 객체는 중복 저장하지 않는다.
HashSet
의 경우 정렬을 해주지 않고 TreeSet
의 경우 자동정렬을 해준다는 차이점이 있다.
그렇다면 중복은 어떻게 걸러내는 것인가?
HashSet은 객체를 저장하기 전에 먼저 객체의 hashCode()메소드를 호출해서 해시 코드를 얻어낸 다음 저장되어 있는 객체들의 해시 코드와 비교한 뒤 같은 해시 코드가 있다면 다시 equals() 메소드로 두 객체를 비교해서 true가 나오면 동일한 객체로 판단하고 중복 저장을 하지 않는다.
HashSet 선언
//저장할 객체 타입을 타입 파라미터로 표기하고 기본 생성자를 호출
Set<E> set1 = new HashSet<>();
//set1의 모든 값을 가진 HashSet생성
HashSet<Integer> set2 = new HashSet<Integer>(set1);
//초기 용량(capacity)지정
HashSet<Integer> set3 = new HashSet<Integer>(10);
//초기 capacity,load factor지정
HashSet<Integer> set4 = new HashSet<Integer>(10, 0.7f);
//초기값 지정
HashSet<Integer> set5 = new HashSet<Integer>(Arrays.asList(1,2,3));
HashSet
도 저장공간보다 값이 추가로 들어오면 List
처럼 저장공간을 동적으로 늘릴 수 있다.
하지만, Set
의 경우에 추가 저장공간은 한 칸씩이 아니라 약 두배로 늘린다. 여기서 과부하가 많이 발생하므로 초기에 저장할 데이터 갯수를 알고 있다면 Set
의 초기용량을 지정해주는 것이 좋다.
2. TreeSet
TreeSet 이란?
Set
인터페이스를 구현한 클래스로써 객체를 중복해서 저장할 수 없고 저장 순서가 유지되지 않는다.HashSet
과는 달리TreeSet
은 이진 탐색 트리(BinarySearchTree) 구조로 이루어져 있다.
이진 탐색 트리는 추가와 삭제에는 시간이 조금 더 걸리지만 정렬, 검색에 높은 성능을 보이는 자료구조이다.
그렇기 때문에 HashSet
보다 데이터의 추가와 삭제는 시간이 더 걸리지만, 검색과 정렬 속도는 빠르다.

4. Map 컬렉션
Map
컬렉션은 키(key
)와 값(value
)으로 구성된 객체를 저장하는 구조를 가지고 있는 자료구조이다.
키는 중복으로 저장할 수 없고 값은 중복으로 저장할 수 있으며 중복된 key
값이 들어온다면 기존의 값은 없어지고 새로운 값으로 대치된다.

자바의 Map
은 대응관계를 쉽게 표현할 수 있게 해 주는 자료형이다.
Map
은 리스트나 배열처럼 순차적으로 해당 요소 값을 구하지 않고, key를 통해 value를 얻는다.
따라서 Map
컬렉션은 키(key
)로 데이터를 관리한다. 그렇기 때문에 키를 매개값으로 갖는 메소드가 많다.

구현 클래스
- HashMap
- HashTable
- LinkedHashMap
- Properties
- TreeMap
1. HashMap
HashMap이란?Map
인터페이스를 구현한 대표적인Map
컬렉션이다.
HashMap
은 이름 그대로 해싱(Hashing)을 사용하기 때문에 많은 양의 데이터를 검색하는 데 있어서 뛰어난 성능을 보인다.

키 객체는 hashCode()
와 equals()
를 재정의해 동등 객체가 될 조건을 정해야 한다. 동등 객체, 즉 동일한 키가 될 조건은 hashCode()
의 리턴값이 같아야 하고, equals()
메소드가 true
를 리턴해야 한다.
HashMap 선언
//K -> 키 타입, V -> 값 타입
Map<K, V> map = new HashMap<K, V>();
//String 과 Integer 를 키와 value 로
Map<String, Integer> map = new HashMap<>();
2. HashTable
HashTable이란?HashMap
과 동일한 내부 구조이며Hashtable
도 키 객체는hashCode()
와equals()
를 재정의해 동등 객체가 될 조건을 정해야 한다.
HashMap과 차이점은Hashtable
은 동기화된 메소드로 구성되어 있기 때문에 멀티 스레드가 동시에 이 메소드들을 실행할 수 없다.
즉, 멀티 스레드 환경에서 안전하게 객체를 추가, 삭제 할 수 있다.
HashTableMap 선언
//K -> 키 타입, V -> 값 타입
Map<K, V> map = new HashTable<K, V>();
//String 과 Integer 를 키와 value 로
Map<String, Integer> map = new HashTable<>();
3. Properties
properties 란?Hashtable
의 하위 클래스이다. 따라서Hashtable
의 모든 특징을 가진다.
차이점은 Properties
는 키와 값을 String으로 제한한 컬렉션이란 점이다.
보통 프로퍼티 파일을 읽을 때 사용한다. 프로퍼티 파일을 읽기 위해서는 Properties 객체를 생성하고, load()
메소드를 호출하면 된다.