Java Collection 이란 데이터의 집합, 그룹을 의미하며
JCF (Java Collections Framework)는 이러한 데이터 자료구조인 컬렉션과 이를 구현하는 클래스를 정의하는
인터페이스를 제공한다.
쉽게 이야기하면
여러개의 데이터를 담는 방법들을 제공한다고 생각하면 된다.
JAVA Collections Framework 상속구조는 아래와 같다.
* 간단요약
- 순서가 있는 목록인 List
- 순서 없이 데이터를 저장하는 Set
- 먼저들어온것이 먼저 나가는 Queue
- 나중에 들어온것이 먼저 나가는 Stack
- Key-Value 구조로 데이터를 저장하는 Map
위쪽부터 설명을 시작해보겠다.
Queue
- 자료의 입력과 출력을 한쪽 끝 (front, rear)으로 제한한 자료구조이다.
- 은행에 먼저온 사람이 가장 먼저 창구에서 일을 보는 것과 같은 FIFO(First In First Out) 구조로
- 먼저들어온 데이터가 먼저 나가는 구조이다.
활용예시
- 콜센터 고객 대기시간
- 프로세스 관리
- 프린터의 인쇄 대기열
Queue 사용법
1. Queue<String> que = new LinkedList<String>(); -- > 주로 사용함
2. Queue<String> que = new Array<String>();
3. Queue que = new LinkedList();
1번을 채택하여 사용한 경우
que.offer("a");
que.offer("b");
que.offer("c");
System.out.print(que); //[a,b,c] -> que 출력
System.out.print(que.element()); //a -> 맨 앞 값 가져오기
System.out.print(que.peek()); //a -> 맨 앞 값 가져오기(element()와 동일)
System.out.print(que.poll()); //a -> 맨 앞 값 가져오고 삭제
System.out.print(que); //[b,c] -> que 출력
PriorityQueue
- 데이터가 먼저 나오는 일반적인 Queue와는 다르게 우선순위가 가장 높은 데이터가 가장 먼저 나온다.
- 우선순위의 결정을 도와주는 Comparable<Student>를 Implements 한 후
compareTo 메소드를 이용해 우선순위 지정을 할 수 있다.
간단한 사용 예시
class Student implements Comparable<Student> {
String name;
int score;
public Genie (String name, int score) {
this.name = name;
this.score = score;
}
@Override
public int compareTo(Student target) {
return this.score <= target.score ? 1 : - 1;
}
@Override
public String toString() {
return "이름 : " + name + ", 점수 : " + score;
}
}
static PriorityQueue<Student> getPriorityQueueOfStudents() {
PriorityQueue<Student> priorityQueue = new PriorityQueue<>();
priorityQueue.offer(new Student("김길동", 20));
priorityQueue.offer(new Student("Gneie", 100));
priorityQueue.offer(new Student("홍길동", 66));
return priorityQueue;
}
public static void main(String[] args) {
PriorityQueue<Student> priorityQueue = getPriorityQueueOfStudents();
// 점수가 높은 순으로 학생들 목록을 출력
while (!priorityQueue.isEmpty())
System.out.println(priorityQueue.poll());
}
결과 --
이름 : Genie, 점수 : 100
이름 : 홍길동, 점수 : 66
이름 : 김길동, 점수 : 20
List
- List 는 배열이 가지고 있는 Index라는 장점을 버리는 대신 빈틈없는 데이터 적재라는 장점을 가졌다.
- 같은 값을 가진 데이터를 중복으로 저장할 수 있으며 기존의 배열은 크기를 지정하고 사용해야하는 반면 List는 add와 remove함수를 통해 융통성 있는 크기 조절이 가능하다.
* ArrayList와 List의 차이
- ArrayList 는 클래스이고 List는 인터페이스라는 점에서 차이가 있다.
- 클래스인 ArrayList 를 사용해서 생성 시점에 List 외에도 RandomAccess, Serializable인터페이스 등을 구현할 수 있다.
쉽게 말하면
List는 인터페이스이므로 도형에 비유할 수 있고
ArrayList는 클래스이므로 정사각형이라고 비유할 수 있다.
LinkedList
- 저장된 데이터간 연결(link)을 통해서 리스트로 구현된 객체이다.
- 다음 데이터의 위치 정보만을 가지고 있기 때문에 순차접근만 가능하다.
- 데이터 추가/삭제를 수행하는 경우 위치정보의 수정만으로 가능하기 때문에 성능이 좋다.
- index를 가진 배열을 보면 중간에 데이터가 추가되는 경우
기존에 있던 데이터들의 인덱싱이 다시 변경되어야하는 반면
LinkedList는 앞 데이터의 Link 값만 변경해주면 되기 때문에 빠르다고 생각하면 된다.
//선언
LinkedList<Integer> list = new LinkedList<Integer>();
//사용
list.addFirst(1);//가장 앞에 데이터 추가
list.addLast(2);//가장 뒤에 데이터 추가
list.add(3);//데이터 추가
list.add(1, 4);//index 1뒤에 데이터 4 추가
//값 출력
Iterator<Integer> iter = list.iterator();
while(iter.hasNext()){
System.out.println(iter.next());
}
Stack
- 제이터의 입력과 출력을 한 곳(방향)으로 제한한 자료구조.
- 가장 마지막에 들어온 데이터가 가장 먼저 나가는 구조이다. LIFO (Last In First Out)
활용예시
- 웹브라우저의 방문기록 뒤로가기 : 가장 나중에 열린 페이지부터 다시 보여준다.
- 역순 문자열 만들기
- 실행취소(undo) : 우리가 ctrl+z 를 누르면 가장 마지막에 실행된게 취소되는 모습과 같다.
- 수식의 괄호검사 : 연산자 우선 순위 표현을 위한 괄호 검사에 사용한다.
Vector
- Vector는 ArrayList와 동일한 내부구조를 가지고 있다. Vector 객체를 생성하기 위해선 저장할 타입을 지정해야한다.
- ArrayList와의 대표적인 차이점은 Vector 클래스는 동기회된 (syschronized) 메서드로 구성되어있다는 점으로
멀티 스레트 환경에서 안전하게 객체를 추가, 삭제할 수 있다. ( Thread Safe)
하지만 동기화 되어있기때문에 데이터를 추가, 삭제하는 과정은 ArrayList보다 느리다.
ArrayList
- 데이터가 순서대로 저장되며 add, remove 함수를 통해 유동적인 데이터의 추가, 삭제가 가능하다.
- 내부에서 처음 설정한 저장용량(capacity)의 크기를 넘어선 객체가 들어오면 배열의 크기를 1.5배 증가시킨다.
- index로 관리되어 있어 객체 검색과 맨 마지막에 객체를 추가하는 경우 좋은 성능을 발휘한다.
중간에 저장되어있는 데이터를 삭제하는 경우, 제거한 데이터부터 마지막 데이터까지 1칸씩 앞으로 이동하게되고
중간에 데이터를 추가하는 경우, 추가한 데이터부터 마지막 데이터까지 1칸씩 뒤로 이동해야한다.
그렇기 때문에 잦은 데이터의 추가, 삭제가 발생해야하는 경우라면 LinkedList를 사용하는것이 좋다.
선언방법
ArrayList<String> mylist = new ArrayList<String>();
Set
앞서 다루었던 List 클래스를 기반으로 한 ArrayList, LinkedList와 사용방법은 매우 유사하다.
하지만 List와는 다르게 데이터를 중복해서 저장할 수 없고 검색에 있어서는 우월한 속도를 자랑한다.
또 index로 관리 되지 않기 때문에 저장 순서가 보장되지 않는다.
수학에서 말하는 집합과 비슷한 내용이라고 생각하면 된다.
사용예시
A사이트에서는 출석체크 이벤트가 진행중이다.
사이트에 접속하면 자동으로 출석체크가 되는데,
한명의 사용자가 여러번 방문하는 경우 출석체크가 여러번 저장되게 된다.
> 이렇게 데이터를 중복해서 저장 할 필요가 없는 경우 Set 구조로 가져간다.
HashSet
- Set 컬렉션에서 가장 많이 사용되는 클래스 중 하나이다.
- 이유는 해시 알고리즘을 사용하여 검색속도가 매우 빠르기 때문이다.
사용예시
동명이인은 많지만 주민등록번호는 사람마다 가지고 있는 고유한 번호이다.
그렇다면 주민번호를 보면 같은 사람인지 판별이 가능하게 된다.
그런데 Set에 단순히 Person 클래스만 넘겨주면 중복여부를 판별하지 못한다.
그래서 사용하는 메소드가 바로 equals()과 hashcode()이다.
1. equals(Object o)
두 객체(현재 이 객체와 인자로 넘어온 객체 o)가 같다는 것을 알려주려면 true를 리턴한다.
2. hashCode()
equals에서 true를 반환했다면 hashCode는 두 객체에서 항상 같은 값을 반환해야합니다.
만일 equals에서 false를 반환했다면 hashCode 역시 다르게 반환하는 것이 좋습니다.
class Person{
String name; //이름
int residentNumber; //주민번호
public Person(String name,int residentNumber){
this.name=name;
this.residentNumber=residentNumber;
}
@Override
public int hashCode(){
/* Objects.hash 메소드로 residentNumber의 해쉬값 반환 */
return Objects.hash(residentNumber);
}
@Override
public boolean equals(Object o){
/* 주민 번호가 같은 Person은 true 반환 */
Person p=(Person)o;
return p.residentNumber==this.residentNumber;
}
}
// 이제 Set에 넣고 확인해보면
public static void main(String[] args){
Set hashSet=new HashSet();
hashSet.add(new Person("김길동", 1111));
hashSet.add(new Person("김기동", 1111));
hashSet.add(new Person("강감찬", 2222));
Iterator it=hashSet.iterator();
while(it.hasNext()){
Person p=it.next();
System.out.println(p.name+"/"+p.residentNumber);
}
}
//결과 ---
//김길동/1111
//강감찬/2222
ThreeSet
-이진탐색트리(BinarySearch Tree)의 형태로 데이터를 저장하는 컬렉션이다.
- 따라서 데이터의 추가, 삭제에는 시간이 걸리지만, 검색과 정렬 기능은 뛰어나다는 장점이 있다.
- 다른 Set 구조와 마찬가지로 중복된 데이터의 저장을 허용하지 않고 저장순서를 유지하지 않는다.
- 다른 점은 데이터가 정렬된 위치에 저장된다는 점이다.
사용예시를 보면 아래와 같다.
TreeSet<Integer> myset = new TreeSet<>();
myset.add(1);
myset.add(2);
myset.add(100);
myset.add(200);
myset.add(300);
System.out.println(myset); //TreeSet 객체 전부를 반환
System.out.println(myset.subSet(1,100)); // 1 이상 100미만 객체 반환
System.out.println(myset.headSet(100)); // 100보다 작은 객체 반환
System.out.println(myset.contains(777)); // 777 있는지 없는지에따라 true/false
System.out.println(myset.tailSet(200)); // 200 이상의 객체 반환
* 사용한 함수 설명
subSet(E fromElement, E toElement)
- fromElement 이상 toElement 미만의 객체를 반환
headSet(E toElement)
- toElement보다 작은 객체를 반환
contains(Object o)
- Object를 포함하는 객체를 반환
tailSet(E fromElement)
- fromElement 이상의 객체를 반환
HashSet과 TreeSet비교
HashSet, TreeSet 모두 중복을 허용하지 않고 순서가 없는 컬렉션이다.
1. 구현방식
- HashSet은 해싱을 이용해 구현
- TreeSet은 이진탐색트리를 이용해 구현
2. 속도
- HashSet > TreeSet
- 해싱이 이진탐색트리보다 빠름
3. 정렬 기능
- HashSet < TreeSet
- 이진탐색트리를 이용했기 때문에 데이터 정렬이 가능
SortedSet
- 인터페이스로 Set요소의 자연 순서 또는 생성시 Comparator제공된 순서에 따라 정렬 된 요소를
오름차순으로 유지하는 요소이다.
- SortedSet은 보관하는 객체의 순서가 의미가 있을 때,중복된 객체를 허용하지 않을 때 사용하면 좋다.
- 객체를 순서대로 Iteration하기 위해서는 다음 2가지중 하나는 반드시 필요하다.
1. SortedSet에 포함되는 객체가 Comparable인터페이스를 구현한 객체이거나
2. Comparator인터페이스를 구현한 객체이어야한다.
List<String> alpa= Arrays.asList("B", "A", "D", "F", "G", );
SortedSet<String> alpaSet = new TreeSet<>(alpa);
위와같이 5개의 알파벳문자로 TreeSet 객체를 생성하면 TreeSet은 원소들을 정렬된 상태인
A B D F G 순서로 보관하고 있는다.
* 특정범위에 접근하는 방법
// 첫번째 first, 마지막 last
System.out.println(alpaSet.first());
System.out.println(alpaSet.last());
// 가장 작은 원소부터 특정값까지 범위 접근은 headSet 메소드를 사용한다.
Set<String> headSet = alpaSet.headSet("D");
System.out.println("headSet: " + headSet);
// headSet: [A, B]
// 특정 데이터로부터 가장큰 데이터까지의 접근은 tailSet 메소드를 사용한다.
Set<String> headSet = alpaSet.tailSet("D");
System.out.println("headSet: " + headSet);
// headSet: [F, G]
// D보다 크거나 같고 G보다 작은 범위의 접근은 subSet을 사용한다.
Set<String> headSet = alpaSet.subSet("D","G");
System.out.println("headSet: " + headSet);
// headSet: [D, F]
Map
- Map 컬렉션은 Key와 value로 구성되어있다.
- 키와 값은 모두 객체이며 키는 중복될 수 없고 값은 중복으로 저장 가능하다.
- 만약 이미 존재하는 키값으로 새로운 데이터를 추가하면 기존의 데이터는 사라지고 새로운 값으로 대체된다.
* Map<key 자료형, value자료형>
- 키와 값의 타입은 기본 타입(byte, short, int, float, double, boolean, char)을 사용할 수 없고
클래스 및 인터페이스 타입만 가능하다.
HashTable
- Hashtable은 HashMap과 동일한 사용법을 갖는데 HashMap과 차이점으로는 동기화 부분이다.
- HashTable은 동기화된(Synchronized) 메서드로 구성되어 있기 때문에 멀티 스레드 환경에서는
동시에 메서드를 실행할 수 없다.
- 하나의 스레드가 작업이 완료되어 메서드에서 빠져나가야 다른 스레드가 해당 메서드를 실행할 수 있다.
- 멀티 스레드 환경에서 안전하게 객체를 추가, 삭제를 할 수 있기 때문에 스레드에 안전(thread safe)하다고 말한다.
선언방법
Map<String, String> map = new HashTable<>();
HashMap
- Map 인터페이스를 구현한 대표적으로 많이 사용되는 컬렉션이다.
- JDK 1.2부터 제공된 HashMap 클래스는 해시 알고리즘(hash algorithm)을 사용하여 검색 속도가 매우 빠르다.
선언방법
Map<String, String> map = new HashMap<>();
SortedMap
SortedMap은 key의 값이 Integer, Double 등과 같이 비교 가능한(Comparable) 타입이거나,
SortedMap을 생성하는 시기에 별도의 Comparator를 등록해서 정렬할 수 있다.
정리하자면, Map의 Key가 정렬되기 위해서는
- Key가 Comparable 인터페이스를 구현한다.
- Map 인스턴스 생성 단계에 Comparator 구현객체를 등록한다.
이때 유지되는 Key 순서는 Map이 지니는 entrySet(), entrySet(), values() 메소드를 통해
생성되는 Collection에도 반영된다.
Comparator comparator()
- SortedMap에 등록된 Comparator가 있으면 해당 인스턴스를 리턴하고, 별도로 등록된게 없으면 null을 리턴합니다.
K firstKey()
- 첫번째 Key를 리턴합니다. 오름차순의 경우 가장 작은 값(lowest)을 리턴합니다.
K lastKey()
- 마지막 Key를 리턴합니다. 오름차순의 경우 가장 큰 값(highest)을 리턴합니다.
SortedMap headMap(K toKey)
- 인자로 받은 toKey 보다 작은 Key들을 가지고서 부분적인 Map을 리턴합니다.
sortedMap tailMap(K fromKey)
- 인자로 받은 fromKey 보다 큰 Key들을 가지고서 부분적인 Map을 리턴합니다.
ThreeMap
- TreeMap 클래스는 키와 값을 한 쌍으로 하는 데이터를 이진 검색 트리(binary search tree)의 형태로 저장한다.
- 이진 검색 트리는 데이터를 추가하거나 제거하는 등의 기본 동작 시간이 매우 빠르다.
- JDK 1.2부터 제공된 TreeMap 클래스는 NavigableMap 인터페이스를 기존의 이진 검색 트리의 성능을 향상시킨
레드-블랙 트리(Red-Black tree)로 구현한다.
선언방법
TreeMap<Integer, String> tm = new TreeMap<Integer, String>();
'Java' 카테고리의 다른 글
JAVA ) 직접 경험한 경력직 기술 면접 질문 모음 (0) | 2020.07.20 |
---|---|
JAVA 언어의 장단점 (0) | 2020.07.13 |
JVM 그것이 알고싶다. (0) | 2020.07.12 |
String Pool 이란 무엇일까? String에 대한 고찰 (0) | 2020.07.12 |
JAVA 설치 및 환경설정! (0) | 2020.07.09 |