[java2] #17 - Collection Framework(Set/List/Map), Iterator
컬렉션 프레임 워크
컬렉션 프레임 워크란 데이터를 저장하는 클래스들을 표준화 한 설계이며
아래 그림과 같이 데이터를 저장하는 구조에 따라 3가지 인터페이스로 구성된다.
Set, List, Map은 데이터들의 집합체라고 볼 수 있다. 그 중 Set과 List는 데이터의 그룹(Collection)이다.
Set | 순서를 유지하지 않는 데이터의 집합이다. 데이터의 중복이 허용되지 않고 HashSet, TreeSet등이 있다. |
List | 순서를 유지하는 데이터의 집합이다. 데이터의 중복이 허용되며 Vector, LinkedList, ArrayList 등이 있다. |
Map | 키(Key)와 값(Value)으로 이루어진 데이터의 집합이다. 순서는 유지되지 않으며 키는 중복을 허용하지 않는다. Map의 클래스로는 TreeMap, Hashtable, HashMap 등이 있다. |
Collection
모든 컬렉션의 상위 인터페이스이다.
1. List
순서가 있고 중복을 허용한다.
index를 사용해 특정위치에 원소를 삽입하거나 접근할 수 있다.
크기가 가변적이다.
종류와 특징
ArrayList | 이전 블로그 참고 https://yoonddo.tistory.com/24 - 단방향 포인터 구조로 데이터 순차적 접근에 강점을 가진다. - 배열을 기반으로 데이터를 저장한다. - 데이터 삽입, 삭제가 느리지만 데이터 검색이 빠르다. |
Vector | - ArrayList에 동기화가 보장되도록 최적화한 클래스이다. - 모든 메소드가 동기화 되어있어서 잘 사용하지 않는다. |
LinkedList | - 노드, 링크로 구성된다. - 양방향 포인터 구조로 데이터의 삽입, 삭제가 빈번할 경우 빠른 성능을 보장한다. 삽입, 삭제 : O(1) / 검색 : O(n) - ArrayList보다 검색이 느리다. - 이름처럼 데이터를 담고있는 노드들이 연결되어 있는데, 노드의 포인터가 다음이나 이전노드와의 연결을 담당한다. - 스택, 큐, 양방향큐(덱) 등을 만들기 위한 용도로 사용한다. |
2. Set
데이터의 집합이며 순서가 상관없고 요소의 중복을 허용하지 않는다.
중복되지 않은 데이터를 구할 때 유용하며 빠른 검색속도를 가진다.
인덱스가 따로 존재하지 않기 때문에 iterator를 사용한다.
HashSet | 이전 블로그 참고 https://yoonddo.tistory.com/26 - 인스턴스의 해시값을 기준으로 저장하기 때문에 순서를 보장하지 않는다. - NULL 값을 허용한다. - TreeSet보다 삽입, 삭제가 빠르다. |
LinkedHashSet | - HashSet 클래스를 상속받은 LinkedList이다. - 데이터가 삽입된 순서대로 데이터를 관리한다. |
TreeSet | - 정렬O - 정렬된 순서대로 보관하며 정렬방법을 지정할 수 있다. - 이진탐색트리(Red-Black-Tree) 형태로 데이터를 저장한다. - 데이터를 추가, 삭제하는 시간이 더 걸리지만 검색과 정렬이 더 뛰어나다. - 기본적으로는 오름차순으로 데이터를 저장한다. |
3. Map
key와 Value의 한쌍으로 이루어지는 데이터의 집합이다.
Key에 대한 중복이 없으며 순서를 보장하지 않는다.
뛰어난 검색 속도를 가지며 인덱스가 따로 존재하지 않아 iterator를 사용한다.
HashMap | 이전 블로그 참고 https://yoonddo.tistory.com/25 - Ket에 대한 중복이 없으며 순서를 보장하지 않는다. - Key와 Value값으로 Null을 허용한다. - 동기화가 보장되지 않는다. - 검색에 가장 뛰어난 성능을 가진다. |
HashTable | - 동기화가 보장되어 병렬 프로그래밍이 가능하고 HashMap보다 처리속도가 느리다. - Key와 Value값으로 NULL을 허용하지 않는다. |
LinkedHashMap | - 입력된 순서를 보장한다. |
TreeMap | - 이진 탐색 트리(Red-Black Tree)를 기반으로 키와 값을 저장한다. - Key값을 기준으로 오름차순 정렬되고 빠른 검색이 가능하다. - 저장 시 정렬을 하기 때문에 시간이 다소 오래 걸린다. |
List와 Set의 검색 속도 차이
- List는 인덱스를 관리하지만 Set은 값만 관리하기 때문에 List보다 검색 시간이 더 빠르다
package day06;
import java.time.Duration;
import java.time.Instant;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.stream.IntStream;
public class SpeedTest {
public static void main(String[] args) {
final int SIZE = 10_000_000;
final List<Integer> arrayList = new ArrayList<Integer>();
final Set<Integer> hashSet = new HashSet<>();
final int data = 9_000_000;
//순차 병렬 집계연산
IntStream.range(0, SIZE).forEach(value -> {
arrayList.add(value);
hashSet.add(value);
});
Instant start = Instant.now();
arrayList.contains(data);
Instant end = Instant.now();
long elapsedTime = Duration.between(start, end).toMillis();
System.out.println("array list search time : " + elapsedTime + "밀리초");
start = Instant.now();
hashSet.contains(data);
end = Instant.now();
elapsedTime = Duration.between(start, end).toMillis();
System.out.println("hash set search time : " + elapsedTime + "밀리초");
}
}
Iterator (반복자)
Iterator는 자바의 컬렉션 프레임워크에서 컬렉션에 저장되어있는 요소들을 읽어오는 방법을
표준화 한 것이다. 데이터 집합체를 다룰 때는 개별적인 클래스에 대해 데이터를 읽는 방법을
알아야 하기 때문에 각 컬렉션에 접근이 힘들어진다. Iterator를 쓰게 되면 어떤 컬렉션
이라도 동일한 방식으로 접근이 가능해 그 안에 있는 항목들에 접근할 수 있는 방법을 제공한다.(다형성)
특징 |
- Vector<E>, ArrayList<E>, LinkedList<E>가 상속받는 인터페이스 - Iterator()를 호출하면 Iterator 객체 반환 - 자바의 컬렉션에 저장되어있는 요소들을 읽어오는 방법의 인터페이스, 즉 쉽게 컬렉션으로부터 정보를 얻어내는 인터페이스이다. |
Iterator Method
- hasNext() - 다음 요소에 읽어 올 요소가 있는지 확인하는 메소드 있으면 true, 없으면 false를 반환한다.
- next() - 실제로 Iterator가 가리키는 데이터 저장소에서 현재 위치를 순차적으로 하나씩 증가해
다음 요소를 가져온다.
- remove() - next()로 읽어온 요소를 삭제한다.
*메소드 호출 순서는 hasNext() -> next() -> remove() 이다.
1. 사용 방법
- Iterator 개체는 컬랙션 개체의 iterator() 메서드를 호출하여 얻어올 수 있다.
- hasNext() 메서드로 이동이 가능한지 확인 후 next() 메서드로 해당 위치의 보관한 개체를 참조하여
원하는 작업을 수행한다.
2. 장점과 단점
- Iterator 개체를 사용하면 size() 메서드를 얻어와서 반복 처리하는 것보다 속도에서 불리하다.
이는 Iterator 개체를 사용하는 부분이 있기 때문에 불가피한 사항이다. 하지만 컬렉션 종류에
관계없이 일관성있게 프로그래밍 할 수 있다는 장점을 갖고있다.
- 소스코드에 어떠한 컬렉션을 사용할지 정해지지 않았지만 컬렉션 내에 보관한 모든 내용을 출력하는
등의 작업을 먼저 하길 원한다면 Iterator를 사용하는 것은 좋은 선택이다.
// 사용가능한 객체 예시
ArrayList arr = new ArrayList();
Vector<> vec = new Vector<>();
LinkedList<Member> link = new LinkedList<Member>();
Set<String> st = new Set<>(String);
// Iterator 객체 얻기
Iterator it0 = arr.iterator(); //vector의 요소를 순차 검색할 객체
Iterator<> it1 = vec.iterator<>();
Iterator<Member> it2 = link.iterator<Member>();
Iterator<String> it3 = st.iterator<String>();
// while문으로 하나씩 객체 얻기
while (it0.hasNext()){
String st = (String)it0.next();
}
- hasNext() : 해당 iterator 객체에 값 존재 여부 (boolean)
- next() : iterator 객체의 값 얻기
// for문을 통한 객체 얻기
for(Member mem : link){
mem.get();
mem.set();
...
}
for(String stOne : st){
System.out.println(stOne);
...
}
- for문을 통해 객체를 얻을 때는 Iterator 객체가 아닌 Collection 객체를 사용한다.
- for문이 만나면 자동으로 Collection 객체의 요소를 순차적으로 얻어온다.
참고 출처 : https://joy-baek.tistory.com/20