배열 대신 컬렉션을 사용하라는 2주차 피드백이 있었는데요
자바의 Collection
이란 무엇일까요?
엄청 많네요.. 내용이... 열심히 정리해보겠씁미다!!!!! 😂
여러 원소를 담은 자료구조로, 배열과의 차이점은 정적 메모리 할당이 아닌 동적 메모리 할당을 합니다.
즉, 배열은 크기를 지정해주고 공간을 만든다면 컬렉션은 유동적으로 추가/삭제해줄 수 있습니다.
자바 컬렉션의 구조는 다음과 같습니다.
Collection
인터페이스를 상속 받은 하위 클래스들을 Collection
인터페이스의 함수를 구현해야합니다.
Collection
인터페이스에 구현된 함수들은 다음과 같습니다.
return type | method | details |
---|---|---|
boolean | add(element) | 요소를 추가 |
boolean | addAll(Collection) | 컬렉션 요소(매개변수)를 모두 추가 |
void | clear | 컬렉션의 모든 요소를 제거 |
boolean | contains(Object) | 매개변수 객체가 해당 컬렉션에 있는지 확인 |
boolean | containsAll(Collection) | 매개변수 모든 객체들이 해당 컬렉션에 있는지 확인 |
boolean | equals(Object) | 매개변수 객체와 같은 객체인지 비교 |
int | hashCode() | 해시 코드 값을 리턴 |
boolean | isEmpty() | 컬렉션이 비어있는 지 확인 |
Interator | iterator() | 요소를 하나씩 처리하기 위해 iterator 객체 리턴 |
boolean | remove(Object) | 매개변수와 동일한 객체 삭제 |
boolean | removeAll(Collection) | 매개변수 객체들을 해당 컬렉션에서 삭제 |
boolean | retainAll(Collection) | 매개변수로 넘어온 객체들만 컬렉션이 남겨둔다. |
int | size() | 요소의 개수 리턴 |
Object[] | toArray() | 컬렉션에 있는 데이터를 배열로 복사 |
T[] | toArray(T[ ]) | 컬렉션에 있는 데이터들을 지정한 타입의 배열로 복사 |
List
인터페이스는 배열처럼 순서가 있습니다.
List
의 하위 클래스인 ArrayList
, LinkedList
, Vector
, Stack
이 순서가 있는 컬렉션으로 많이 사용된다고 합니다.
여기서, ArrayList
와 Vector
는 거의 동일하지만 ArrayList
는 Thread safe하지 않고, Vector
는 Thread safe합니다.
(Thread safe : 한 객체에 동시에 여러 일을 수행하는 경우 문제가 발생할 수 있다. 그런 문제로부터 safe한 경우를 의미한다.)
Stack
은 Vector
를 확장하여 사용하고, LIFO를 지원하기 위해 만들어졌습니다.
한 클래스의 한 가지 종류의 객체만 저장하기 때문에
컬렉션 관련 클래스의 객체를 선언할 때 제네릭을 사용하여 선언하는 것을 권장합니다.(<>
).
데이터 추가
return type | method | details |
---|---|---|
boolean | add(E e) | 매개변수 데이터를 가장 끝에 추가 |
void | add(int index, E e) | 매개변수 데이터를 지정된 index 위치에 추가 |
boolean | addAll(Collection<? extends E> c) | 매개변수 컬렉션 데이터를 가장 끝에 추가 |
boolean | addAll(int index, Collection<? extends E> c) | 매개변수 컬렉션 데이터를 index에 지정된 위치에 추가 |
데이터 확인
return type | method | details |
---|---|---|
int | size() | ArrayList 객체의 데이터 개수 리턴 |
E | get(int index) | 매개변수 지정 위치의 데이터 리턴 |
int | indexOf(Object o) | 매개변수 객체와 동일한 데이터의 위치 리턴 |
int | lastIndexOf(Obejct o) | 매개변수 객체와 동일한 마지막 데이터 위치 리턴 |
Object[] | toArray() | ArrayList 객체들의 값들을 Obejct[]] 타입의 배열로 변환하여 리턴 |
T[] | toArray(T[] a) | ArrayList 객체들의 값을 매개변수로 넘어온 T 타입의 배열로 변환하여 리턴 |
데이터 삭제 및 변경
return type | method | details |
---|---|---|
void | clear() | 모든 데이터 삭제 |
E | remove(int index) | 매개 변수에 지정한 위치의 데이터 삭제, 해당 데이터를 리턴 |
boolean | remove(Object o) | 매개변수에 넘어온 객체와 동일한 첫번째 데이터 삭제 |
boolean | removeAll(Collection<?> c) | 매개변수로 넘어온 컬렉션 객체와 동일한 모든 데이터 삭제 |
E | set(int index, E element) | 지정 위치의 데이터를 두번째 매개변수(element) 값으로 변경, 해당 위치 데이터는 리턴 |
LinkedList
는 각 노드가 데이터와 포인터를 가지고 한줄로 연결되어 있는 방식의 자료구조입니다.
한 요소의 앞 뒤에 무엇이 연결되어 있는지 알고 있기 때문에 중간에 요소를 삽입하거나 삭제할 때 ArrayList
보다 효율적입니다.
return type | method | details |
---|---|---|
boolean | add(Object o) | 매개변수 객체를 리스트 끝에 추가 |
void | add(E o) | 매개변수 데이터를 끝에 추가 |
void | add(int index, Object element) | 지정된 위치(index)에 객체를 추가 |
boolean | addAll(Collection c) | 매개변수 컬렉션을 끝에 추가 |
void | addFirst(E o) | 매개변수 데이터를 앞에 추가 |
void | clear() | 모든 요소 삭제 |
boolean | contains(Object o) | 지정된 객체가 해당 리스트에 있는지 확인 |
boolean | containsAll(Colllection c) | 매개변수 컬렉션의 모든 요소가 포함되어 있는 지 확인 |
E | element() | 첫번째 요소 반환 |
E | removeFirst() | 첫번째 요소 반환&삭제 |
Object | get(int index) | 지정된 위치의 객체 반환 |
int | indexOf(Object o) | 지정된 객체와 동일한 요소의 위치 반환 |
boolean | isEmpty() | 리스트가 비어있는 지 확인 |
Iterator | iterator() | iterator 반환 |
ListIterator | listIterator(int index) | 지정위치부터 시작하는 ListIterator 반환 |
boolean | offer(E o) | 전달된 요소를 끝에 추가 |
E | peek() | 가장 첫번째 요소 반환 |
E | poll() | 가장 첫번째 요소 반환 후 삭제 |
boolean | remove(Object o) | 매개변수 객체와 동일한 첫번째 요소를 삭제 |
boolean | removeAll(Collection c) | 매개변수 컬렉션과 일치하는 모든 요소 제거 |
boolean | retainAll(Collection c) | 매개변수 컬렉션의 모든 요소가 포함되어있는지 확인 |
Object | set(int index, Object element) | 지정된 위치의 객체를 매개변수 객체로 변환 |
int | size() | 리스트 크기 반환 |
List | subList(int fromIndex, int toIndex) | LinkedList의 일부를 List로 반환 |
Object[] | toArray() | Linkedlist에 저장된 객체를 배열로 반환 |
Object[] | toArray(Object[] a) | LinkedList에 저장된 객체를 배열로 변환하여 매개변수 배열에 저장 |
마지막으로 들어온 데이터를 가장 처음에 꺼내는 LIFO(Last In First Out) 기능을 구현하려고 할 때 필요한 클래스입니다.
return type | method | details |
---|---|---|
boolean | empty() | 객체가 비어있는지 확인 |
E | peek() | 객체 가장 위 데이터를 리턴 |
E | pop() | 객체 가장 위 데이터를 지우고 리턴 |
E | push(E item) | 매개변수 데이터를 가장 위에 저장 |
int | search(Object o) | 매개변수 데이터의 위치 리턴 |
Queue
의 사전적의미는 "줄을 서서 기다리는 것"이라고 하는데요,
이처럼 줄 지어 순서대로 처리되는 것을 Queue
라고 하고 FIFO(First In First Out)의 형태를 가집니다.
front
는 삭제 연산을 수행rear
는 삽입 연산만 수행Queue
)를 만들어 대기return type | method | details |
---|---|---|
boolean | add(Object o) | 맨 뒤 요소 삽입, 큐에 공간이 없는 경우 IllegalStateException 발생 |
Object | element() | 맨 앞의 요소를 반환 |
boolean | offer(Object o) | 맨 뒤에 요소 삽입 |
E | peek() | 맨 앞 요소 반환, 큐가 비었으면 null 반환 |
E | poll() | 맨 앞 요소 반환, 해당 큐 제거 & 큐가 비어있으면 null 반환 |
Object | remove() | 객체를 꺼내 반환 |
Deque는 인터페이스로 구현되었습니다.
맨 앞과 맨 끝 모두 삽입과 삭제가 발생할 수 있습니다. (어떻게 사용하느냐에 따라 Queue
가 될수도 Stack
이 될 수도 있습니다.)
이를 구현한 ArrayDeque
, LinkedBlockingDeque
, ConcurrentLinkedDeque
, LinkedList
등의 클래스가 있습니다.
method | details |
---|---|
addFirst(E e) | 맨 앞 요소 삽입, 용량 제한시 예외 발생 |
offerFirst(E e) | 맨 뒤 요소 삽입, 용량 제한시 false |
addLast(E e) | 맨 끝 요소 삽입, 용량 제한시 예외 발생 |
add(E e) | addLast()와 동일 |
offerLast(E e) | 맨 끝 요소 삽입, 용량 제한시 false |
removeFirst() | 맨 앞 요소를 리턴&제거, 덱이 비었으면 예외 발생 |
pollFirst() | 맨 앞 요소를 리턴&제거, 덱이 비었으면 null 리턴 |
removeLast() | 맨 뒤 요소를 리턴&제거, 덱이 비어있으면 예외 발생 |
pollLast() | 맨 뒤 요소를 리턴&제거, 덱이 비어있으면 null 리턴 |
remove() | removeFirst()와 동일 |
poll() | pollFirst()와 동일 |
getFirst() | 맨 앞 요소를 리턴, 덱이 비었으면 예외 발생 |
peekFirst() | 맨 앞 요소를 리턴, 덱이 비었으면 null 발생 |
getLast() | 맨 뒤 요소 리턴, 덱이 비어있으면 예외 발생 |
peek() | peekFirst()와 동일 |
removeFirstOccurrence(Object o) | 매개변수 객체와 동일한 첫번째 요소를 제거 |
removeLastOccurrnece(Object o) | 매개변수 객체와 동일한 마지막 요소를 제거 |
element() | removeFirst()와 동일 |
addAll(Collection <? extends E c> | 매개변수 컬렉션을 맨 뒤에 삽입 |
push() | addFirst()와 동일, 덱을 스택으로 사용할 때 쓰임 |
pop() | removeFirst()와 동일, 덱을 스택으로 사용할 때 쓰임 |
remove(Object o) | removeFirstOccurrence(Object o)와 동일 |
contain(Object o) | 매개변수 객체와 동일한 객체가 포함되어있는 지 확인 |
size() | 덱의 크기 반환 |
iterator() | 맨 앞부터 순차적으로 실행되는 iterator 반환 |
descendingIterator() | 맨 뒤부터 순차적으로 실행되는 iterator 반환 |
우선순위 큐는 데이터의 우선순위를 먼저 결정하고 그 우선순위가 높은 요소가 먼저 나가는 자료구조입니다.
큐의 값을 꺼내면(맨 앞 요소) 우선 순위가 가장 높은 값이 반환됩니다.
메소드는 위에서 설명한 내용과 동일하여 생략하겠습니다. 👌
Set
은 List
와 다르게 객체의 중복 저장이 불가능하고 인덱스를 관리하지 않기 때문에 저장 순서가 보장되지 않습니다. (null값 저장가능)
따라서 데이터를 탐색하려면 iterator
를 생성하여 데이터를 가져와야합니다.
Set
인터페이스를 구현한 클래스는 HashSet
, TreeSet
, LinkedHashSet
등이 있습니다.
HashSet
: 데이터를 중복 저장할 수 없고 순서를 보장하지 않습니다.TreeSet
: 기본적으로 오름차순 데이터를 정렬하여 저장합니다.LinkedHashSet
: 입력된 순서대로 데이터를 관리합니다.Set
의 데이터를 iterator
를 이용하여 탐색해보는 예제를 보겠습니다.
Set<String> set = new HashSet<String>();
set.add("김철수");
... // 데이터 추가
Iterator<String> it = set.iterator();
while (it.hasNext()) {
System.out.println(it.next());
}
Map
은 키와 값으로 이루어져있습니다.
키에 따라 값을 찾을 수 있기 때문에 삽입 순서는 정해지지 않습니다.
Map
에서 고유Map
에서 중복되어도 상관 Xreturn type | method | details |
---|---|---|
V | put(K key, V value) | 첫번째 매개변수(키)와 두번째 매개변수(값)을 갖는 데이터 저장 |
void | putAll(Map<? extends K, ? extends V> m) | 매개변수인 Map의 모든 데이터 저장 |
V | get(Object key) | 매개변수(키)에 해당하는 값을 리턴 |
V | remove(Object key) | 매개변수(키)에 해당 값을 리턴하며 해당 키와 값은 삭제 |
Set | keySet() | 키의 목록을 Set 타입으로 리턴 |
Collection | values() | 값의 목록을 Collection 타입으로 리턴 |
Set<Map.Entry<K,V>> | entrySet() | Map 안 Entry 타입의 Set을 리턴 |
int | size() | Map의 크기를 리턴 |
void | clear() | Map의 내용을 삭제 |
기능 | HashMap | Hashtable |
---|---|---|
키나 값에 null 저장 | O | X |
여러 스레드 동시 접근 | X | O |
대부분 HashMap
객체를 생성할 때 매개변수가 없는 생성자를 사용한다. 하지만 HashMap
에 담을 데이터 개수가 많은 경우 초기 크기를 지정해주는 것을 권장한다.
HashMap
의 예시를 한번 볼까요? 😉
HashMap<String, String> map = new HashMap<String, String>();
map.put(1, "김철수");
map.put(2, "김영희");
for (Entry<Integer, String> entry : map.entrySet()) {
System.out.println(entry.getKey() + entry.getValue());
}
for (Integer i : map.keySet()) {
System.out.println(i+map.get(i));
}
map.remove(1); // "김영희" 제거
map.clear(); // 모두 제거
TreeMap
클래스는 키와 값을 저장하는 동시에 키를 정렬합니다.
(정렬 순서 : 숫자 > 알파벳 대문자 > 알파벳 소문자 > 한글)
정렬이 필요하다면 HashMap
보다는 TreeMap
을 사용을 권장합니다.
return type | method | details |
---|---|---|
K | firstKey() | 가장 앞에 키를 리턴 |
K | lastKey() | 가장 뒤의 키를 리턴 |
K | higherKey() | 특정 키 뒤에 있는 키를 리턴 |
K | lowerKey() | 특정 키 앞에 있는 키를 리턴 |
TreeMap
의 예제도 보도록 하겠습니다.
TreeMap<Integer, String> map = new TreepMap<>();
map.put(30, "김삼십");
map.put(10, "윤십");
map.put(20, "최이십");
for (Intger key : map.keySet()) {
System.out.println(key+map.get(key));
}
/*
10 윤십
20 최이십
30 김삼십
*/
Collection
인터페이스로 구현된 클래스들에 대해서 알아보았습니다.
관련 메소드도 많이 적어놨는데, 이걸 다 외우기 보다는 이런 것들이 있구나 정도로만 보시면 될 듯 합니다.
그리고 나중에 적절하다고 판단되는 API를 선택하여 관련 메소드를 다시 보고 사용할 수 있도록 해야겠습니다. 😊