Collection Framework

YongJun·2023년 9월 15일

JAVA

목록 보기
20/24
post-thumbnail

Collection Framework란?

컬렉션 프레임워크는 자바 프로그래밍에서 빠질 수 없는 필수적인 요소이다. 컬렉션은 다수의 요소를 하나의 그룹으로 묶어 효율적으로 저장하고, 관리할 수 있는 기능을 제공하는 일종의 컨테이너이다. 배열은 크기가 고정되어 있는데에 반해, 컬렉션 프레임워크는 가변적인 크기를 갖는 (Resizable) 등의 특징을 갖는다. 또한 데이터 삽입, 탐색, 정렬 등 편리한 API 를 다수 제공한다. 이런 이점으로 개발자는 배열보다는 적절한 컬렉션 클래스를 선택해 사용하는 것이 권장된다.

장점

컬렉션 프레임워크는 아래와 같은 이점으로 프로그램의 유지보수를 쉽게 만들어준다.

  • List, Queue, Set, Map 등의 인터페이스를 제공하고, 이를 구현하는 클래스를 제공하여 일관된 API 를 사용할 수 있다.
  • 가변적인 저장 공간을 제공한다. 고정적인 저장 공간을 제공하는 배열에 대비되는 특징이다.
  • 자료구조, 알고리즘을 구현하기 위한 코드를 직접 작성할 필요 없이, 이미 구현된 컬렉션 클래스를 목적에 맞게 선택하여 사용하면 된다.
  • 제공되는 API 의 코드는 검증되었으며, 고도로 최적화 되어있다.

컬렉션 프레임워크에 저장할 수 있는 데이터는 오로지 객체(Object) 뿐이다.
즉, int형이나 double형 같은 자바의 primitive 타입은 적재를 못한다는 말이다. 따라서 primitive 타입을 wrapper 타입으로 변환하여 Integer 객체나 Double 객체로 박싱(Boxing)하여 저장하여야 한다. 또한 객체를 담는 다는 것은 곧 주소값을 담는다는 것이니, null도 저장이 가능하다.

구성요소

컬렉션 프레임워크는 아래의 3가지 요소로 구성된다.

  • 인터페이스 (Interfaces) : 각 컬렉션을 나타내는 추상 데이터에 대한 인터페이스 (List, Set, Map 등). 클래스는 이 인터페이스를 구현하는 방식으로 작성되었기 때문에 상세 동작은 달라도 일관된 조작법으로 사용할 수 있다.

  • 클래스 (Classes) : 컬렉션 별 인터페이스의 구현 (Implementation). 위에서 언급했듯, 같은 List 컬렉션이더라도 목적에 따라 ArrayList, LinkedList 등으로 상세 구현이 달라질 수 있다.

  • 알고리즘 (Algorithms) : 컬렉션이 제공하는 연산, 검색, 정렬, 셔플 (Shuffle) 등에 대한 메소드.

종류

Iterable interface

  • Iterator를 우리 말로 번역하면 '반복자'로, 객체 지향 프로그래밍에서 배열과 같은 여러 개의 데이터의 집합으로 이루어진 자료구조를 순회하는 객체를 의미한다.

  • 자바의 Iterator 인터페이스는 컬렉션 프레임워크에 저장된 요소들을 순회하여 읽어오는데 사용되는데, 어떤 컬렉션 프레임워크라도 읽어볼 수 있는 표준화된 방법을 제공한다

  • Iterator 관련 메서드
    Iterator 인터페이스가 제공하는 메서드는 3가지로 꽤 단순하다. 또한, '반복자'라는 이름답게 while, for 문과 함께 사용된다.
    ① hasNext()
    → 다음 요소가 존재하는지 혹은 그렇지 않은지 true/false로 리턴한다. true 이면 다음 요소다 있다는 것이고, false 이면 현재 요소가 마지막이라는 뜻이다.
    ② next()
    → 다음 요소를 가져온다.
    ③ remove()
    → next()로 호출된 요소를 제거한다.
    메서드의 종류를 순번을 붙여 나열한 이유는, Iterator에서 내부적으로 호출하는 메서드의 순서가 ① hasNext() → ② next() → ③ remove() 이기 때문이다.

Collection interface

  • Collection interface의 주요 메소드

    메소드설명
    boolean add(Object o)컬렉션에 객체 o 를 추가한다. 추가되어 컬렉션이 변화하였으면 true 를, 그렇지 않으면 false 를 반환한다.
    boolean addAll(Collection c)컬렉션에 컬렉션 c 이 갖고있는 요소를 모두 추가한다. 추가되어 컬렉션이 변화하였으면 true 를, 그렇지 않으면 false 를 반환한다.
    void clear()컬렉션을 비운다.
    boolean contains(Object o)컬렉션에 객체 o 가 포함되어 있는지 여부를 검사한다. 포함되어 있다면 true 를, 그렇지 않다면 false 를 반환한다.
    boolean containsAll(Collection c)컬렉션에 컬렉션 c 가 갖고있는 요소 모두가 포함되어 있는지 여부를 검사한다. 포함되어 있다면 true 를, 그렇지 않다면 false 를 반환한다.
    boolean isEmpty()컬렉션이 비어있는지 검사한다. 비어있다면 true 를, 그렇지 않다면 false 를 반환한다.
    boolean remove(Object o)컬렉션에서 객체 o 를 제거한다. 제거되어 컬렉션이 변화하였으면 true 를, 그렇지 않으면 false 를 반환한다.
    boolean removeAll(Collection c)컬렉션에서 컬렉션 c 이 갖고있는 요소를 모두 제거한다. 제거되어 컬렉션이 변화하였으면 true 를, 그렇지 않으면 false 를 반환한다.
    boolean removeIf(Predicate<? super E> filter)람다식을 통해 요소를 필터링할 수 있다.
    boolean retainAll(Collection c)컬렉션에서 컬렉션 c 이 갖고있는 요소를 제외한 나머지 요소를 모두 제거한다. 제거되어 컬렉션이 변화하였으면 true 를, 그렇지 않으면 false 를 반환한다.
    int size()컬렉션이 보유하고 있는 객체의 수를 반환한다.
    Object[] toArray()컬렉션을 배열로 변환한다.
    Object[] toArray(Object[] a)컬렉션을 배열로 변환한다. 파라미터로 넣어준 배열의 크기에 맞춰 배열이 생성되는데, 리스트의 사이즈가 배열의 크기보다 크다면, 리스트 사이즈에 맞춰 배열의 크기가 조절된다.
    Iterator iterator()컬렉션의 Iterator 를 반환한다.
    Stream stream()컬렉션의 Stream 을 반환한다.
    Stream parallelStream()병렬처리가 가능한 Stream 을 반환한다.

List interface

  • 저장 순서가 유지되는 컬렉션을 구현하는 데 사용

  • 같은 요소의 중복 저장을 허용

  • 배열과 마찬가지로 index로 요소에 접근

  • 리스트와 배열의 가장 큰 차이는 리스트는 자료형 크기가 고정이 아닌 데이터 양에 따라 동적으로 늘어났다 줄어들수 있다는 점이다. (가변)

  • 요소 사이에 빈공간을 허용하지 않아 삽입/삭제 할때마다 배열 이동이 일어난다

  • List interface의 주요 메소드

    메소드설명
    boolean add(Object o)리스트에 객체 o 를 추가한다. 추가되어 컬렉션이 변화하였으면 true 를, 그렇지 않으면 false 를 반환한다.
    void add(int index, Object o)리스트에 객체 o 를 index 위치에 추가한다.
    boolean addAll(Collection c)리스트에 컬렉션 c 이 갖고있는 요소를 모두 추가한다. 추가되어 리스트가 변화하였으면 true 를, 그렇지 않으면 false 를 반환한다.
    boolean addAll(int index, Collection c)리스트에 컬렉션 c 이 갖고있는 요소를 index 위치 부터 모두 추가한다. 추가되어 리스트가 변화하였으면 true 를, 그렇지 않으면 false 를 반환한다.
    void clear()리스트를 비운다.
    boolean contains(Object o)리스트에 객체 o 가 포함되어 있는지 여부를 검사한다. 포함되어 있다면 true 를, 그렇지 않다면 false 를 반환한다.
    boolean containsAll(Collection c)리스트에 컬렉션 c 가 갖고있는 요소 모두가 포함되어 있는지 여부를 검사한다. 포함되어 있다면 true 를, 그렇지 않다면 false 를 반환한다.
    Object get(int index)index 위치에 있는 요소를 반환한다.
    int indexOf(Object o)주어진 객체 o 중 가장 앞 요소의 위치(index) 를 반환한다. 존재하지 않는다면 -1을 반환한다.
    int lastIndexOf(Object o)주어진 객체 o 중 가장 뒤 요소의 위치(index) 를 반환한다. 존재하지 않는다면 -1을 반환한다.
    boolean isEmpty()리스트가 비어있는지 검사한다. 비어있다면 true 를, 그렇지 않다면 false 를 반환한다.
    boolean remove(Object o)리스트에서 객체 o 를 제거한다. 제거되어 컬렉션이 변화하였으면 true 를, 그렇지 않으면 false 를 반환한다.
    Object remove(int index)리스트에서 객체 o 를 제거한다. 제거되어 컬렉션이 변화하였으면 true 를, 그렇지 않으면 false 를 반환한다.
    boolean removeAll(Collection c)리스트에서 컬렉션 c 이 갖고있는 요소를 모두 제거한다. 제거되어 컬렉션이 변화하였으면 true 를, 그렇지 않으면 false 를 반환한다.
    void replaceAll(UnaryOperator operator)람다식을 이용해 각 요소를 변경할 수 있다.
    boolean retainAll(Collection c)컬렉션에서 컬렉션 c 이 갖고있는 요소를 제외한 나머지 요소를 모두 제거한다. 제거되어 컬렉션이 변화하였으면 true 를, 그렇지 않으면 false 를 반환한다.
    Object set(int index, Object o)index 위치에 있는 요소를 주어진 객체 o 로 교체한다.
    int size()컬렉션이 보유하고 있는 객체의 수를 반환한다.
    void sort(Comparator<? super E> c)요소를 오름차순으로 정렬한다. Collections.sort(c) 의 형태로 사용한다.
    Object[] toArray()컬렉션을 배열로 변환한다.
    Object[] toArray(Object[] a)컬렉션을 배열로 변환한다. 파라미터로 넣어준 배열의 크기에 맞춰 배열이 생성되는데, 리스트의 사이즈가 배열의 크기보다 크다면, 리스트 사이즈에 맞춰 배열의 크기가 조절된다.
    Iterator iterator()컬렉션의 Iterator 를 반환한다.
    ListIterator listIterator()ListIterator 를 반환한다.
    ListIterator listIterator(int index)index 이후로 순환하는 ListIterator 를 반환한다.
    Spliterator spliterator()Spliterator 를 반환한다.
    Stream stream()컬렉션의 Stream 을 반환한다.
    Stream parallelStream()병렬처리가 가능한 Stream 을 반환한다.

    List interface를 구현한 class의 메소드 설명에서는 위 메소드들은 제외한다.

ArrayList Class

  • 배열을 이용하여 만든 리스트

  • 데이터의 저장순서가 유지되고 중복을 허용

  • 데이터량에 따라 공간(capacity)가 자동으로 늘어나거나 줄어들음

  • 단방향 포인터 구조로 자료에 대한 순차적인 접근에 강점이 있어 조회가 빠르다
    하지만, 삽입 / 삭제가 느리다는 단점이 있다. 단, 순차적으로 추가/삭제 하는 경우에는 가장 빠르다

  • ArrayList Class 메소드

    메소드설명
    Object clone()리스트의 얕은 복사본을 반환한다.
    void ensureCapacity(int minCapacity)리스트의 최소 용량을 확보한다.
    void forEach(Consumer<? super E> action)람다식을 사용하여 리스트 내부 요소를 순회할 수 있다.
    List subList(int fromIndex, int toIndex)기존 리스트에서 fromIndex 부터 toIndex - 1 의 범위의 요소를 갖는 새 리스트를 반환한다.
    void trimToSize()현재 리스트 크기에 맞춰 용량을 자른다.

예제1

package collection;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;

public class CollectionMain {

	@SuppressWarnings("all") //all : 모든 경고를 억제
	public static void main(String[] args) {
		/*
		Collection : 데이터를 저장하는 자료구조
		Collection 인터페이스를 사용하려면?
		1. implements
		 - 인터페이스를 구현한 클래스에서 인터페이스의 모든 추상메소드를 오버라이드 해줘야 한다, but collection인터페이스에는 추상메소드가 많다..
		2.대신 override해주는 클래스(우체국 택배 역할)(오버라이드된 메소드들이 내장되어있음)-interface를 대신 가져옴
		 - Collection coll = new ArrayList();
		3.메소드 이용
		 - Iterator it = coll.iterator();
		*/
		
		Collection coll = new ArrayList(); //2번 방법 사용(Collection - interface, ArrayList - class)
		//ArrayList 클래스에서 Serializable, Cloneable, Iterable<E>, Collection<E>, List<E>, RandomAccess 인터페이스들을 구현 하고있다 
		coll.add("호랑이"); //add() : 원소를 추가
		coll.add("사자");
		coll.add("호랑이"); //중복 허용
		coll.add(25);
		coll.add(43.8);
		coll.add("기린");
		coll.add("코끼리");
		
		Iterator it = coll.iterator(); 
		while(it.hasNext()) { 
			System.out.println(it.next()); 
		}
	}

}
/*
호랑이
사자
호랑이
25
43.8
기린
코끼리
*/

예제2

package collection;

import java.util.ArrayList;
import java.util.List;

public class CollectionMain2 {

	public static void main(String[] args) {
		//ArrayList 클래스
		//ArrayList<String> list = new ArrayList<String>();
		List<String> list = new ArrayList<String>();
		list.add("호랑이"); 
		list.add("사자");
		list.add("호랑이"); //중복 허용
//		list.add(25)
//		list.add(43.8);
		list.add("기린");
		list.add("코끼리");
		
		for(int i=0; i<list.size(); i++) {
			System.out.println(list.get(i));
		}
		System.out.println();
		
		for(String s :list) {
			System.out.println(s);
		}
	}

}
/*
호랑이
사자
호랑이
기린
코끼리

호랑이
사자
호랑이
기린
코끼리
*/

LinkedList Class

  • 노드(객체)를 연결하여 리스트 처럼 만든 컬렉션 (배열이 아님)(각 노드는 이전 노드와 다음 노드값을 가지고 있다)

  • 데이터의 중간 삽입, 삭제가 빈번할 경우 빠른 성능을 보장한다.

  • 하지만 임의의 요소에 대한 접근 성능은 좋지 않다.

  • 자바의 LinkedList는 Doubly LinkedList(양방향 포인터 구조)로 이루어져 있다.

  • LinkedList는 리스트 용도 이외에도, 스택, 큐, 트리 등의 자료구조의 근간이 된다.

  • LinkedList Class 메소드

    메소드설명
    void addFirst(Object o)리스트 맨 앞에 객체 o 를 추가한다.
    void addLast(Object o)리스트 마지막에 객체 o 를 추가한다.
    Iterator descendingIterator()반대 순서의 Iterator 를 반환한다.
    Object getFirst()리스트의 첫번째 객체를 반환한다. 리스트가 비어있으면 NoSuchElementException 예외가 발생한다.
    Object getLast()리스트의 마지막 객체를 반환한다. 리스트가 비어있으면 NoSuchElementException 예외가 발생한다.
    Object element()리스트의 첫번째 객체 o 를 반환한다. getFirst() 와 동일한 기능을 수행한다.
    boolean offer(Object o)리스트의 마지막에 객체 o 를 추가한다. 용량이 초과되어 추가하지 못할 경우 false 를 반환한다.
    boolean offerFirst(Object o)리스트의 맨 앞에 객체 o 를 추가한다. 용량이 초과되어 추가하지 못할 경우 false 를 반환한다.
    boolean offerLast(Object o)리스트의 마지막에 객체 o 를 추가한다. 용량이 초과되어 추가하지 못할 경우 false 를 반환한다.
    Object peek()리스트의 첫번째 객체를 반환한다. 단, 리스트가 비어있을 경우 null 을 반환한다.
    Object peekFirst()리스트의 첫번째 객체를 반환한다. 단, 리스트가 비어있을 경우 null 을 반환한다.
    Object peekLast()리스트의 마지막 객체를 반환한다. 단, 리스트가 비어있을 경우 null 을 반환한다.
    Object poll()리스트의 첫번째 객체를 반환하고 삭제한다. 단, 리스트가 비어있을 경우 null 을 반환한다.
    Object pollFirst()리스트의 첫번째 객체를 반환하고 삭제한다. 단, 리스트가 비어있을 경우 null 을 반환한다.
    Object pollLast()리스트의 마지막 객체를 반환하고 삭제한다. 단, 리스트가 비어있을 경우 null 을 반환한다.
    Object pop()리스트의 첫번째 객체를 반환하고 삭제한다. 리스트가 비어있으면 NoSuchElementException 예외가 발생한다.
    void push(Object o)리스트 맨 앞에 객체 o 를 추가한다.
    Object remove()리스트의 첫번째 객체를 반환하고 삭제한다. 리스트가 비어있으면 NoSuchElementException 예외가 발생한다.
    Object removeFirst()리스트의 첫번째 객체를 반환하고 삭제한다. 리스트가 비어있으면 NoSuchElementException 예외가 발생한다.
    boolean removeFirstOccurrence(Object o)리스트를 주어진 객체 o 와 일치하는 객체 중 가장 앞에 있는 객체를 리스트에서 삭제하고, 삭제에 성공했다면 true 를 반환한다.
    Object removeLast()리스트의 마지막 객체를 반환하고 삭제한다. 리스트가 비어있으면 NoSuchElementException 예외가 발생한다.
    boolean removeLastOccurrence(Object o)리스트를 주어진 객체 o와 일치하는 객체 중 가장 뒤에 있는 객체를 리스트에서 삭제하고, 삭제에 성공했다면 true 를 반환한다.

Vector Class

  • 멀티 쓰레드 환경에서 동기화를 지원하여 오류로부터 안전하다. 대신 그렇기 때문에 ArrayList 보다 동작이 느리다.
  • Vector는 컬렉션 프레임워크가 자바에 추가되기전부터 존재한 레거시 클래스이다. 하위 호환을 위하여 Deprecated 되지 않았을 뿐, 사용하는 것이 권장되지 않는 클래스이다.
  • 또한, 멀티 스레드 프로그래밍을 하더라도 ArrayList 를 사용하면 되므로 결국 어떤 상황에서도 사용하지 않는 것이 좋다.

만일 현업에서 컬렉션에 동기화가 필요하면 Collections.synchronizedList() 메서드를 이용해 ArrayList를 동기화 처리하여 사용한다.

예제3

package collection;

import java.util.Iterator;
import java.util.Vector;

public class VectorMain {

	public static void main(String[] args) {
		Vector<String> v = new Vector<String>();
		System.out.println("백터 크기 = "+v.size()); //0
		System.out.println("백터 용량 = "+v.capacity()); //기본용량 10, 10개씩 증가
		System.out.println();
		
		System.out.println("항목 추가");
		for(int i=0; i<10; i++) {
			v.add(i+1+""); //add() : 벡터에 요소를 추가
			System.out.print(v.get(i)+" "); //get() : 백터에서 값을 추출
		}//for
		System.out.println();
		System.out.println("백터 크기 = "+v.size()); //10
		System.out.println("백터 용량 = "+v.capacity()); //10
		System.out.println();
		
		System.out.println("항목 1개 추가");
		v.addElement(5+"");//중복 허용
		System.out.println("백터 크기 = "+v.size()); //11
		System.out.println("백터 용량 = "+v.capacity()); //20
		System.out.println();
		
		for(int i=0; i<v.size(); i++) {
			System.out.print(v.get(i)+" ");
		}
		System.out.println();
		
		System.out.println("마지막 항목 삭제");
		//v.remove(5+""); //앞 부분의 "5" 항목이 삭제
		v.remove(10); //10번 위치의 항목을 삭제
		
		//iterator : '반복자', 배열과 같은 여러 개의 데이터의 집합으로 이루어진 자료구조를 순회하는 객체, Iterator 인터페이스는 컬렉션 프레임워크에 저장된 요소들을 순회하여 읽어오는데 사용
		Iterator<String> it = v.iterator(); //Iterator는 interface라서 new로 생성 X, 메소드로 interface 생성
		while(it.hasNext()) { //hasNext() : 다음 요소가 존재하는지 혹은 그렇지 않은지 true/false로 리턴한다. true 이면 다음 요소다 있다는 것이고, false 이면 현재 요소가 마지막이라는 뜻이다.
			System.out.print(it.next()+" "); //next() : 다음 요소를 가져온다.
		}
		System.out.println();
	}
}
/*
백터 크기 = 0
백터 용량 = 10

항목 추가
1 2 3 4 5 6 7 8 9 10 
백터 크기 = 10
백터 용량 = 10

항목 1개 추가
백터 크기 = 11
백터 용량 = 20

1 2 3 4 5 6 7 8 9 10 5 
마지막 항목 삭제
1 2 3 4 5 6 7 8 9 10
*/

Stack Class

  • 후입선출 LIFO(Last-In-First-Out) 자료구조
  • 마지막에 들어온 원소가 처음으로 나간다
  • 들어올때는 push, 나갈때는 pop이라는 용어를 사용
  • Stack은 Vector를 상속하기 때문에 문제점이 많아 잘 안쓰인다. (대신 ArrayDeque 사용)

예제4

package collection;

import java.util.Stack;
import static java.lang.System.out;

public class StackMain {

	public static void main(String[] args) {
		String[] groupA = {"우즈베키스탄", "쿠웨이트", "사우디", "대한민국"};
		
		Stack<String> stack = new Stack<String>();
		
		for(int i=0; i<groupA.length; i++) {
			stack.push(groupA[i]); //push() : 주어진 객체를 스택에 넣는다.
		}
		
		while(!stack.isEmpty()) { //isEmpty() : 컬렉션 인터페이스의 메소드, 공백 상태이면 true 반환
			out.println(stack.pop()); //pop() : 스택의 맨 위 객체를 가져온다, 객체를 스택에서 제거한다.
		}

	}

}
/*
대한민국
사우디
쿠웨이트
우즈베키스탄
*/

Queue interface

  • 선입선출 FIFO(First-In-First-Out) 구조(처음 들어온 원소가 가장 먼저 나간다)

  • 자바에서는 Queue 는 인터페이스이고 필요에 따라 큐 컬렉션을 골라 사용할 수 있다.

  • Queue interface 메소드

    메소드설명
    boolean add(Object o)지정된 객체를 Queue에 추가, 저장공간 부족 시 IllegalStateException 발생
    Object remove()Queue에서 객체를 꺼내 반환, 비어있을 경우 NoSuchElementException 발생
    Object element()삭제없이 요소를 읽어온다, 비어있을 경우 NosuchElementException 발생
    boolean offer(Object o)Queue에 객체를 저장
    Object poll()Queue에서 객체를 꺼내서 반환, 비어있을 경우 null을 반환
    Object peek()삭제없이 요소를 읽어온다, 비어있을 경우 null을 반환

예제5

package collection;

import java.util.LinkedList;
import java.util.PriorityQueue;
import java.util.Queue;

import static java.lang.System.out;

public class QueueMain {

	public static void main(String[] args) {
		String [] item = {"포르쉐", "페라리", "벤틀리"};
		
		//LinkedList<String> q = new LinkedList<String>();
		Queue<String> q = new PriorityQueue<String>();
		
		for(String n : item) {
			q.offer(n); //offer() : 요소 추가
		}
		
		out.println("q의 크기 : "+q.size()+"\n");
		String data = "";
		
		while((data=q.poll())!=null) { //poll() : 맨 앞에 있는 값 반환 후 삭제, 비어있을 경우 null 반환
			out.println(data+"삭제!");
			out.println("q의 크기 : "+q.size()+"\n");
		}//while

	}

}
/*
q의 크기 : 3

벤틀리삭제!
q의 크기 : 2

페라리삭제!
q의 크기 : 1

포르쉐삭제!
q의 크기 : 0
*/

PriorityQueue Class

  • 우선 순위를 가지는 큐 (우선 순위 큐)
  • 일반적인 큐와는 조금 다르게, 원소에 우선 순위(priority)를 부여하여 우선 순위가 높은 순으로 정렬되고 꺼낸다
  • 수행할 작업이 여러 개 있고 시간이 제한되어 있을 때 우선순위가 높은 것부터 수행할때 쓰인다 (네트워크 제어, 작업 스케쥴링)
  • 우선순위 큐에 저장할 객체는 필수적으로 Comparable 인터페이스를 구현해야한다. - compareTo() 메서드 로직에 따라 자료 객체의 우선순위를 결정하는 식으로 동작되기 때문이다.
  • 저장공간으로 배열을 사용하며, 각 요소를 힙(heap) 형태로 저장한다.
  • null 저장 불가능

힙(heap)은 이진 트리의 한 종류로 우선순위가 가장 높은 자료를 루트 노드로 갱신한다는 점으로, 가장 큰 값이나 가장 작은 값을 빠르게 찾을 수 있다는 특징이 있다.

예제6

// 우선순위 큐에 저장할 객체는 필수적으로 Comparable를 구현
class Student implements Comparable<Student> {
    String name; // 학생 이름
    int priority; // 우선순위 값

    public Student(String name, int priority) {
        this.name = name;
        this.priority = priority;
    }

    @Override
    public int compareTo(Student user) {
        // Student의 priority 필드값을 비교하여 우선순위를 결정하여 정렬
        if (this.priority < user.priority) {
            return -1;
        } else if (this.priority == user.priority) {
            return 0;
        } else {
            return 1;
        }
    }

    @Override
    public String toString() {
        return "Student{" +
                "name='" + name + '\'' +
                ", priority=" + priority +
                '}';
    }
}
public static void main(String[] args) {

    // 오름차순 우선순위 큐
    Queue<Student> priorityQueue = new PriorityQueue<>();

    priorityQueue.add(new Student("주몽", 5));
    priorityQueue.add(new Student("세종", 9));
    priorityQueue.add(new Student("홍길동", 1));
    priorityQueue.add(new Student("임꺽정", 2));

    // 우선순위 대로 정렬되어 있음
    System.out.println(priorityQueue);
    // [Student{name='홍길동', priority=1}, Student{name='임꺽정', priority=2}, Student{name='주몽', priority=5}, Student{name='세종', priority=9}]

    // 우선순위가 가장 높은 값을 참조
    System.out.println(priorityQueue.peek()); // Student{name='홍길동', priority=1}

    // 차례대로 꺼내기
    System.out.println(priorityQueue.poll()); // Student{name='홍길동', priority=1}
    System.out.println(priorityQueue.poll()); // Student{name='임꺽정', priority=2}
    System.out.println(priorityQueue.poll()); // Student{name='주몽', priority=5}
    Syste

Deque interface

  • Deque(Double-Ended Queue)는 양쪽으로 넣고 빼는 것이 가능한 큐를 말한다.
  • 스택과 큐를 하나로 합쳐놓은 것과 같으며 스택으로 사용할 수도 있고, 큐로 사용할 수도 있다.
  • Deque의 조상은 Queue이며, 구현체로 ArrayDeque와 LinkedList 등이 있다.

ArrayDeque Class

  • 스택으로 사용할 때 Stack 클래스보다 빠르며, 대기열로 사용할 때는 LinkedList보다 빠르다.

  • 사이즈에 제한이 없다.

  • null 요소는 저장되지 않는다.

  • 메소드 비교(Deque vs Queue vs Stack)

    DequeQueueStack
    offerLast()offer()push()
    pollLast()-pop()
    pollFirst()poll()-
    peekFirst()peek()-
    peekLast()-peek()

예제7

Deque<Integer> deque = new ArrayDeque<>();

deque.offerLast(100); // [100]
deque.offerFirst(10); // [10, 100]
deque.offerFirst(20); // [20, 10, 100]
deque.offerLast(30); // [20, 10, 100, 30]

deque.pollFirst(); // 20 <- [10, 100, 30]
deque.pollLast(); // [10, 100] -> 30
deque.pollFirst(); // 10 <- [100]
deque.pollLast(); // [] -> 100

Set interface

  • 데이터의 중복을 허용하지 않고 순서를 유지하지 않는 데이터의 집합 리스트

  • 순서 자체가 없으므로 인덱스로 객체를 검색해서 가져오는 get(index) 메서드도 존재하지 않는다

  • 중복 저장이 불가능하기 때문에 심지어 null값도 하나만 저장할 수 있다

  • Set interface 메소드

    메소드설명
    boolean add(E e)주어진 객체를 저장 후 성공적이면 true를 중복 객체면 false를 리턴합니다.
    boolean contains(Object o)주어진 객체가 저장되어있는지 여부를 리턴합니다.
    Iterator iterator()저장된 객체를 한번씩 가져오는 반복자를 리턴합니다.
    isEmpty()컬렉션이 비어있는지 조사합니다.
    int Size()저장되어 있는 전체 객체수를 리턴합니다.
    void clear()저장된 모든 객체를 삭제합니다.
    boolean remove(Object o)주어진 객체를 삭제합니다.

HashSet Class

  • 배열과 연결 노드를 결합한 자료구조 형태
  • 가장 빠른 임의 검색 접근 속도를 가진다
  • 추가, 삭제, 검색, 접근성이 모두 뛰어나다
  • 대신 순서를 전혀 예측할 수 없다

LinkedHashSet Class

  • 순서를 가지는 Set 자료
  • 추가된 순서 또는 가장 최근에 접근한 순서대로 접근 가능
  • 만일 중복을 제거하는 동시에 저장한 순서를 유지하고 싶다면, HashSet 대신 LinkedHashSet을 사용하면 된다

예제8

package collection;

import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;

public class SetMain {

	public static void main(String[] args) {
		Set<String> set = new HashSet<String>(); 
		
		set.add("호랑이");
		set.add("사자");
		set.add("호랑이"); //중복 허용 x, 순서 x
		set.add("기린");
		set.add("코끼리");
		
		Iterator it = set.iterator(); 
		while(it.hasNext()) { 
			System.out.println(it.next());  
		}//while
	}
}
/*
호랑이
코끼리
기린
사자
*/

TreeSet Class

  • 이진 검색 트리(binary search tree) 자료구조의 형태로 데이터를 저장
  • 중복을 허용하지 않고, 순서를 가지지 않는다
  • 대신 데이터를 정렬하여 저장하고 있다는 특징이다
  • 정렬, 검색, 범위 검색에 높은 성능을 뽐낸다.

예제9

Map interface

  • 키(Key)와 값(value)의 쌍으로 연관지어 이루어진 데이터의 집합

  • 값(value)은 중복되서 저장될수 있지만, 키(key)는 해당 Map에서 고유해야만 한다.

  • 만일 기존에 저장된 데이터와 중복된 키와 값을 저장하면 기존의 값은 없어지고 마지막에 저장된 값이 남게 된다.

  • 저장 순서가 유지 되지 않는다.

  • Map interface 메소드

    추상 메소드설명
    void clear()Map의 모든 객체를 삭제
    boolean containsKey(Object key)지정된 key객체와 일치하는 객체가 있는지 확인
    boolean containsValue(Object value)지정된 value객체와 일치하는 객체가 있는지 확인
    Set entrySet()Map에 저장된 key-value쌍을 Map.Entry타입의 객체로 저장한 Set을 반환
    boolean equals(Object o)동일한 Map인지 비교
    Object get(Object key)지정한 key객체에 대응하는 value객체를 반환
    int hashCode()해시코드를 반환
    boolean isEmpty()Map이 비어있는지 확인
    Set keySet()Map에 저장된 모든 key객체를 반환
    Object put(Object key, Object value)Map에 key객체와 value객체를 연결(mapping)하여 저장
    void putAll(Map t)지정된 Map의 모든 key-value쌍을 추가
    Object remove(Object key)지정한 key객체와 일치하는 key-value객체를 삭제
    int size()Map에 저장된 key-value쌍의 개수를 반환
    Collection values()Map에 저장된 모든 value객체를 반환

Map 인터페이스의 메소드를 보면, Key값을 반환할때 Set 인터페이스 타입으로 반환하고, Value값을 반환할때 Collection 타입으로 반환하는걸 볼 수 있다.
Map 인터페이스에서 값(value)은 중복을 허용하기 때문에 Collection 타입으로 반환하고, 키(key)는 중복을 허용하지 않기 때문에 Set 타입으로 반환하는 것이다.

HashTable Class

  • 자바 초기 버전에 나온 레거시 클래스
  • Key를 특정 해시 함수를 통해 해싱한 후 나온 결과를 배열의 인덱스로 사용하여 Value를 찾는 방식으로 동작된다
  • HashMap 보다는 느리지만 동기화가 기본 지원된다
  • 키와 값으로 null이 허용 X

HashMap Class

  • Hashtable을 보완한 컬렉션
  • 배열과 연결이 결합된 Hashing형태로, 키(key)와 값(value)을 묶어 하나의 데이터로 저장한다
  • 중복을 허용하지 않고 순서를 보장하지 않는다
  • 키와 값으로 null이 허용된다
  • 추가, 삭제, 검색, 접근성이 모두 뛰어나다
  • HashMap은 비동기로 작동하기 때문에 멀티 쓰레드 환경에서는 어울리지않는다 (대신 ConcurrentHashMap 사용)

예제10

package collection;

import java.util.HashMap;
import java.util.Map;

public class MapMain {

	public static void main(String[] args) {
		Map<String, String> map = new HashMap<String, String>();
		//키-값
		map.put("book101", "백설공주"); 
		map.put("book201", "인어공주");
		map.put("book102", "백설공주"); 
		map.put("book301", "피오나");
		map.put("book101", "엄지공주"); 
		
		System.out.println(map.get("book101"));
		System.out.println(map.get("book102"));
		System.out.println(map.get("book501")); //Key의 Value값이 없으면 null
		
	}
}
/*
엄지공주
백설공주
null
*/

LinkedHashMap Class

  • HashMap을 상속하기 때문에 흡사하지만, Entry들이 연결 리스트를 구성하여 데이터의 순서를 보장한다.
  • 일반적으로 Map 자료구조는 순서를 가지지 않지만, LinkedHashMap은 들어온 순서대로 순서를 가진다.

TreeMap Class

  • 이진 검색 트리의 형태로 키와 값의 쌍으로 이루어진 데이터를 저장 (TreeSet 과 같은 원리)
  • TreeMap은 SortedMap 인터페이스를 구현하고 있어 Key 값을 기준으로 정렬되는 특징을 가지고 있다.
  • 정렬된 순서로 키/값 쌍을 저장하므로 빠른 검색(특히 범위 검색)이 가능하다
  • 단, 키와 값을 저장하는 동시에 정렬을 행하기 때문에 저장시간이 다소 오래 걸리다
  • 정렬되는 순서는 숫자 → 알파벳 대문자 → 알파벳 소문자 → 한글 순이다.
profile
개(발자어)린이

0개의 댓글