컬렉션 프레임워크1

Jaca·2021년 10월 2일
0

컬렉션 프레임워크란, 데이터 군을 저장하는 클래스들을 표준화한 설계로써 JAVA API는 '데이터 군을 다루고 표현하기 위한 단일화된 구조' 라고 정의하고 있다.

컬렉션 프레임워크는 컬렉션, 다수의 데이터를 다루는 데 필요한 다양하고 풍부한 클래스들을 제공한다.
또한 인터페이스와 다형성을 이용한 객체지향적 설계를 통해 표준화되어 있기 때문에 사용법을 익히기도 편하고 재사용성이 높은 코드를 작성할 수 있다.

핵심 인터페이스

컬렉션 프레임워크는 컬렉션데이터 그룹을 3가지로 정의하고,
인터페이스 List와 Set의 공통된 부분을 다시 뽑아 Collection으로 추가 정의하였다.
Map 인터페이스는 이들과 전혀 다른 형태로 컬렉션을 다루기 때문에 같은 상속계층도에 속하지 못했다.

List 인터페이스
중복을 허용하면서 순서가 유지되는 컬렉션을 구현하는데 사용된다.
구현 클래스 : ArrayList, LinkedList, Stack, Vector 등

Set 인터페이스
중복을 허용하지 않고, 순서가 유지되지 않는 컬렉션을 구현하는데 사용된다.
구현 클래스 : HashSet, TreeSet 등

Map 인터페이스
키와 값의 쌍으로 이루어진 데이터의 집합, 중복 허용
구현 클래스 : HashMap, TreeMap, Properties 등

ArrayList

List 인터페이스를 구현하기 때문에 데이터의 저장순서가 유지되며 중복을 허용한다.
기존의 Vector를 개선한 것으로 Vector와 구현원리와 기능적 측면이 동일하다.
Vector는 기존 코드와의 호환성을 위해 남겨 두고 있을 뿐 가능하면 ArrayList를 사용할 것.

ArrayList는 0번째 위치부터 순차적으로 저장되며, 공간을 늘릴 수 없어 부족하다면 공간이 더 큰 배열을 생성해서 기존의 배열에 저장된 내용을 복사한 다음 저장한다.
딱 봐도 이 과정이 자원을 꽤 먹을것 같으니 미리 크기를 적당히 잡는게 낫것다.
중간 인덱스의 삽입과 삭제도 코드를 보니 기존의 배열에서 조작하고 복사하는 것을 확인할 수 있다.

LinkedList

배열의 가장 큰 단점인 '크기를 변경할 수 없다' 와 '비 순차적인 데이터의 추가, 삭제의 비용' 을 보완한 자료구조이다.

LinkedList는 불연속적으로 존재하는 데이터를 서로 연결한 형태로 구성되어 있다.

class LinkedListNode {
	Node next;
    Object object;
}

위와 같이 LinkedList의 각 요소는 자신과 연결된 다음 요소의 주소로 구성되어 있다.

LinkedList의 삭제는 그 다음 요소의 주소를 연결하는 것만으로 삭제가 이루어진다.
ArrayList와의 비순차적 삭제의 비용낭비가 없어 매우 빠르다.

LinkedList는 이동방향이 단방향이기 때문에 다음 요소로의 접근은 쉽지만 이전 요소에 접근은 어렵다.
이를 보완한 것이 DoubleLinkedList 이다.

class DoubleLinkedListNode {
	Node next;
    Noed previous;
    Object object;
}

DoubleLinkedList는 참조변수를 하나 더 추가하여 이전 요소에 대한 참조가 가능할 뿐, 그 외에는 LinkedList와 동일하다.
DoubleLinkedList는 LinkedList 보다 각 요소에 대한 접근과 이동이 쉽기 때문에 더 많이 사용된다.

DoubleLinkedList의 접근성을 보다 향상시킨 것이 Double Circular LinkedList이다.

단순히 DoubleLinkedList의 첫 번째와 마지막 요소를 서로 연결시킨 것이다.
이렇게 하면, 마지막 요소의 다음 요소가 첫 번째 요소가되고, 첫 번째 요소의 이전 요소가 마지막 요소가 된다.

순차적 추가/삭제는 ArrayList가, 중간 데이터의 추가/삭제는 LinkedList가 빠르다

Stack, Queue

스택은 LIFO 구조, 큐는 FIFO 구조 이다.

스택은 순차적으로 데이터를 추가하고 삭제하는 구조이기 때문에 ArrayList와 같은 배열 기반의 컬렉션을 기반으로 구현하며,
큔ㄴ 데이터를 꺼낼 때 항상 첫 번째 저장된 데이터를 삭제한다.
이를 ArrayList로 구현하면 빈 공간을 채우기 위해 데이터의 복사가 발생하므로 비효율적이다.
그래서 큐는 데이터의 추가/삭제가 쉬운 LinkedList로 구현한다.

PriorityQueue

Queue인터페이스의 구현체 중의 하나로, 저장한 순서에 관계없이 우선순위가 높은 것부터 꺼내고, null을 저장할 수 없다.
PriorityQueue는 저장공간을 배열을 사용하며, 각 요소를 heap의 형태로 저장한다.

Deque (Double-Ended Queue)

Queue의 변형으로, 양쪽 끝에 추가/삭제가 가능하다.

덱은 스택과 큐를 합친 것같은 모양새로, 스택만이나 큐만으로도 사용할 수 있다.

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

Iterator, ListIterator, Enumeration

Iterator, ListIterator, Enumeration은 컬렉션의 저장된 요소를 접근하는데 사용되는 인터페이스이다.
Enumeration은 Iterator의 구버젼이며, ListIterator은 Iterator의 기능을 향상시킨 것이다.

Iterator

컬렉션에 저장된 각 요소에 접근하는 기능을 가진 Iterator 인터페이스를 정의하고, Collection 인터페이스에는 'Iterator(Iterator 의 인스턴스)' 를 반환하는 iterator() 를 정의하고 있다.

ListIterator, Enumeration

Enumeration은 컬렉션 프레임워크가 만들어지기전에 사용하던 것으로 Iterator를 사용하면된다. 기존 코드의 호환을 위해 남겨두고 있는 것

ListIterator는 Iterator를 상속받아서 기능을 추가한 것으로, Iterator는 단방향 접근만 가능하지만, ListIterator는 양방향으로의 이동이 가능하다.

ListIterator는 Iterator에 이전방향으로의 접근 기능인 hasPrevious(), previous(), previousIndex() 가 추가되었다.

Iterator의 remove()는 단독으로 쓰일수 없고, next()와 같이 써야한다.
특정위치의 요소를 삭제하는 것이 아니라 읽어 온 것을 삭제한다.
next()의 호출 없이 remove()를 사용 시 IllegalStateExcetpion이 발생한다.

Arrays

Arrays 클래스에는 배열을 다루는데 유용한 메서드가 정의되어 있다.

  • copyOf(), copyOfRange()
    copyOf는 배열의 전체를, copyOfRange()는 배열의 일부를 복사해서 새로운 배열을 만들어 반환한다.
    복사할 값이 없다면 int의 경우 0, String의 경우 null로 채운다.

  • fill(), setAll()
    fill()은 배열의 모든 요소를 지정된 값으로 채운다,
    setAll()은 배열을 채우는데 사용할 함수형 인터페이스를 매개변수로 받는다.
    setAll()을 사용하려면 함수형 인터페이스를 구현한 객체를 넘겨주던가, 람다식을 지정해줘야 한다.

  • sort(), binarySearch()
    sort()는 배열을 정렬할 때, 저장된 요소를 검색할 때는 binarySearch()를 사용한다.
    binarySearch()를 사용할 때는 반드시 배열이 정렬된 상태여야 올바른 결과를 얻는다. 그리고 검색한 값과 같은 요소가 여러개 있다면, 어떤 인덱스가 반환될지는 알 수 없다.

  • equals(), deepEquals()
    equals()는 두 배열에 저장된 모든 요소를 비교해서 같으면 true, 다르면 false를 반환한다.
    다 차원 배열의 비교에는 deepEqulas()를 사용해야한다.

  • toString(), deepToString()
    toString()은 배열의 모든 요소를 문자열로 편하게 출력할 수 있다.
    다차원 배열에서는 deepToString()을 사용해야한다.
    배열의 모든 요소를 재귀적으로 접근해서 문자열을 구성하므로 3차원 이상의 배열에도 동작한다.

  • asList(Object... a)
    asList()는 배열을 List에 담아서 반환한다. 매개변수의 타입이 가변인수라서 배열 생성 없이 저장할 요소들만 나열하는 것도 가능하다.
    asList()는 반환한 List의 크기를 변경할 수 없다.
    즉 추가/삭제가 불가능하지만, 저장된 내용은 변경할 수 있다.
    만일 크기를 변경할 수 있는 List가 필요하다면, List의 인스턴스를 new연산자로 새로 만들어야한다.

  • parallelXXX(), spliterator(), stream()
    'parallel' 로 시작하는 메서드들이 있는데, 이 메서드들은 보다 빠른 결과를 얻기 위해 여러 쓰레드가 작업을 나누어 처리하도록 한다.
    spliterator()는 여러 쓰레드가 처리할 수 있게 하나의 작업을 여러 작업으로 나누는 Spliterator를 반환하며, stream()은 컬렉션을 스트림으로 변환한다.

Comparator와 Comparable

Comparator와 Comparable은 모두 컬렉션을 정렬하는데 필요한 메서드를 정의하고 있다.

public interface Comparator {
	int compare (Object o1, Object o2);
    boolean equals (Object obj);
}

public interface Comparable {
	public int compareTo (Object o);
}

compare()와 compareTo()는 선언형태와 이름이 약간 다를 뿐 두 객체를 비교한다는 것은 같다.
compareTo()는 두 객체가 같으면 0, 비교하는 값보다 작으면 음수, 크면 양수를 리턴한다.
이와 마찬가지로 compare()도 객체를 비교해서 음수, 0, 양수 중 하나를 반환하도록 구현해야한다.

Comparable는 기본 정렬 기준을 구현하는데 사용하고,
Comparator는 기본 정렬 기준 외에 다른 기준으로 정렬하고자할 때 사용한다.

profile
I am me

0개의 댓글