[JAVA]Collection 프레임워크에 대하여 알아보기

Inung_92·2023년 4월 18일
1

JAVA

목록 보기
14/15
post-thumbnail

Collection 프레임워크란?

📖데이터를 저장하는 자료구조와 데이터를 처리하는 알고리즘을 구조화하여 클래스로 구현해놓은 것

다시 말해 collection 프레임워크란 다수의 데이터를 쉽고 효율적으로 처리할 수 있는 표준화된 방법을 제공하는 클래스의 집합이다.

⚡️ collection 프레임워크의 주요 인터페이스

  • List : 순서가 있는 객체의 저장 공간, 데이터의 중복을 허용
  • Set : 순서가 없는 객체의 저장 공간, 데이터의 중복을 불허
  • Map : key-value로 데이터를 핸들링하며, key는 중복을 불허하고 value는 중복을 허용

⚡️ collection 프레임워크의 구성

여기서 Map은 구조상의 차이로 인해 collection과 별개의 인터페이스로 구성되어있다.

⚡️ 사용이유

  • 일관된 API 제공 : 하위의 모든 클래스(ArrayList, LinkedList 등)가 상속을 통해 통일된 메서드 구현
  • 프로그래밍 노력 감소 : 객체 지향 프로그래밍의 추상화의 기본개념이 성공적으로 구현
  • 프로그램 속도 및 품질 향상 : 알고리즘 및 데이터 구조 선응을 향상시킬 수 있는 수단으로 사용 가능

일관된 API를 제공한다는 것은 collection의 하위 객체들의 모든 하위 클래스들은 공통된 인터페이스를 구현한다. 예를 들어 List 인터페이스를 구현하는 ArrayList와 LinkedList는 List 인터페이스의 메소드를 구현할 수 있기 때문에 List형으로 동작이 가능한 것이다. 이런 부분들이 프로그래밍 노력을 감소시키는 한가지의 이유가 될 수 있다.

또한, 기본적으로 collection 프레임워크는 데이터의 자료구조와 처리를 위한 알고리즘을 구조화한 것이기 때문에 프로그램의 속도 및 품질 향상을 기대할 수 있다. 내부적으로 메소드를 통해 알고리즘을 구현하며, 객체 자체가 자료구조의 한가지 형태를 가지고 있기 때문이다.


Collection 프레임워크의 인터페이스

⚡️ List

📖 객체를 순서대로 저장하며 데이터의 중복을 허용

List는 우리가 가장 많이 접해보고 다뤄본 객체라고 할 수도 있다.

🖥️ List의 특징

  • 객체를 일렬로 늘어놓은 구조
  • 동일한 객체를 중복 저장하는 것이 가능하며, 이런 경우 데이터의 번지를 참조
  • Null 저장도 가능하며 해당 인덱스의 객체는 참조하지 않음

🖥️ List의 구조

🖥️ List의 하위 클래스

📖 ArrayList

데이터의 크기가 가변적이며, 초기 용량은 객체 10개를 저장할 수 있음

List를 구현하는 ArrayList는 우리가 흔히 알고 배열과 유사한 모습을 가지고 있다. 하지만 동일하다고 볼 수는 없는데 그 차이를 알아보자.

차이점

  • 크기 : 배열은 고정된 크기를 가지는 반면 ArrayList는 가변적인 크기를 가진다. 즉 ArrayList는 동적으로 크기가 변경될 수 있다.
  • 데이터의 추가/삭제 : 배열은 데이터를 추가/삭제 할 경우 복사작업을 수행하며 비용이 많이 든다. 반면에 ArrayList는 데이터 추가/삭제 시 자동으로 데이터의 크기를 조정한다.
  • 데이터 타입의 보장 : ArrayList는 제너릭 클래스를 통해 타입의 안정성을 보장해준다.

기본문법

//String 형의 제너릭을 가지는 ArrayList
ArrayList<String> arrayList = new ArrayList<>();

//메소드
arrayList.add("test"); // 추가
arrayList.remove(0); // 삭제
arrayList.indexOf("test"); //파라미터의 인덱스 검색
arrayList.get(0); //해당 인덱스의 객체 가져오기
...생략

ArrayList의 인덱스 구조

  • 추가 : 0부터 1씩 증가하며 차례대로 저장
  • 삭제 : 해당 인덱스로부터 마지막 인덱스까지 1씩 밀려남
  • 특정위치 인덱스 추가 : 해당 인덱스부터 마지막 인덱스까지 1씩 밀려남
    빈번한 객체 삽입 및 삭제가 이루어지는 작업에는 부적합하며 인덱스 검색 또는 마지막 객체를 추가하는 경우 좋은 성능을 발휘한다.

📖 Vector

ArrayList와 동일한 내부 구조를 가지고 있으나 동기화(synchronized) 메소드로 구성되어 있어 멀티스레드가 동시에 해당 메소드들을 실행 불가

vector의 동기화 개념도

기본문법

//Vector 선언
List<String> vector = new Vector<>();

Vector는 ArrayList와 비교하였을 때 동기화가 필요한 상황 및 환경에서 사용하면 된다.

📖 LinkedList

다른 List 구현 객체들과 내부 구조가 다르며 각 노드가 데이터와 포인터를 가지고 한 줄로 연결되어 있는 방식

LinkedList는 노드의 포인터가 이전 노드와 다음 노드와의 연결을 담당한다. 이러한 특성으로 인해 순차적으로 추가 및 삭제하는 경우에는 ArrayList가 빠르지만 특정 인덱스 위치에 추가 및 삭제하는 경우는 LinkedList가 빠른 성능을 보여준다.

LinkedList의 내부구조

기본문법

//객체 선언
List<String> linkedList = new LinkedList<>();

ArrayList와의 시간비교

public class CompareTime {
	public static void main(String[] args) {
		ArrayList<String> list_arr = new ArrayList<String>();
		LinkedList<String> list_link = new LinkedList<String>();
		
		//시간판단 변수 선언
		long startTime;
		long endTime;
		
		//ArrayList 동작시간 측정 및 출력
		startTime = System.nanoTime();
		for(int i = 0; i < 10000; i++) {
			list_arr.add(0, String.valueOf(i));
		}
		endTime = System.nanoTime();
		System.out.println("Array 동작시간 : " + (endTime-startTime) + "ns");
		list_arr.clear();

		//LinkedList 동작시간 측정 및 출력
		startTime = System.nanoTime();
		for(int i = 0; i < 10000; i++) {
			list_link.add(0, String.valueOf(i));
		}
		endTime = System.nanoTime();
		System.out.println("Linked 동작시간 : " + (endTime-startTime) + "ns");
		list_link.clear();
	}
}

//실행결과
Array 동작시간 : 23342958ns
Linked 동작시간 : 3926791ns

이렇게 List의 하위 객체들은 각자의 특징을 가지고 있기 때문에 상황과 해당 기능, 또는 프로그램의 특성에 맞게 사용하면된다.

⚡️ Set

📖 순서가 없는 데이터의 집합이며, 중복된 데이터를 불허하는 특성을 보유

Set은 집합이라고 생각하면 이해하기 편할 것이다.

🖥️ Set의 특징

  • 객체의 저장 순서를 유지하지 않음.
  • 데이터가 저장된 순서와 나오는 순서가 다름.
  • 단 하나의 Null만 저장 가능

🖥️ Set의 구조

🖥️ Set의 하위 클래스

📖 HashSet

객체를 저장하기 전 기존 객체들 중 동일한 hashCode여부를 분석하여 객체를 저장하고, 중복을 불허하는 클래스

HashSet은 이미 저장되어 있는 객체들의 해시코드를 비교하여 동일한 해시코드 식별 시 equals()를 통해 객체를 최종적으로 비교 후 중복일 경우 저장하지 않고, 중복이 아닐경우에만 저장하는 구조를 가진다.

기본문법

//선언
Set<String> hashSet = new HashSet<>();

중복검사 절차도

순서는 다음과 같다.
1. 객체 저장 시도
2. hashCode()를 통한 동일 해시코드 확인
3. 해시코드가 기존 객체와 동일하다면 equals()를 통해 동등 객체여부 확인
4. 동등 객체가 존재한다면 저장 불허
5. 그렇지 않다면 저장

여기서 중요한 점은 해시코드가 동일하더라도 equals()로 판단한 동등객체 여부가 불일치 한다면 다른 객체로 간주하여 저장을 허가하는 것이다.

📖 TreeSet

Set 인터페이스와 기본 특성은 동일하지만 이진탐색트리 구조로 이루어진 클래스

이진탐색트리(BinarySearch Tree)는 추가와 삭제에는 시간이 더 걸리지만 정렬 및 검색에는 높은 성능을 보여주는 자료구조 이다. TreeSet은 HashSet보다 데이터의 추가와 삭제에는 시간이 더 소요되지만 검색과 정렬에는 유리하다는 것이 장점이다. 기본적으로 nature ordering(대소 비교를 통해 크고 작은 객체를 정렬하는 기법)을 지원하나 생성자의 매개변수를 통해 정렬방법 지정이 가능하다.

또한, TreeSet은 기존의 이진탐색트리가 시간이 많이 소요되는 단점을 보완하기 위하여 레드-블랙 트리를 적용하였다. 레드-블랙 트리에 대해 설명하자면 부모노드보다 작은 값을 가지는 노드는 왼쪽, 큰 값은 오른쪽으로 배치하여 데이터의 추가나 삭제 시 트리가 한쪽으로 치우쳐지지 않도록 균형을 맞춘 것이다.

레드-블랙 트리 개념도

기본문법 및 예시

//선언
Set<String> treeSet = new TreeSet<>();

//데이터 추가 및 삭제
//값 추가
set1.add(7);  //빈 공간에 7 추가
set1.add(23);  //7 < 23이므로 23은 7의 우측 자식으로 추가
set1.add(1);  //7 > 1이므로 1은 7의 좌측 자식으로 추가
set1.add(72); //7 < 72이고, 23 < 72이므로 72는 23의 우측 자식으로 추가
set1.add(21); //7 < 21이고, 23 > 21이므로 21은 23의 좌측 자식으로 추가
set1.add(9); //7 < 9이고, 23 > 9이며, 21 > 9이므로 9는 21의 좌측 자식으로 추가

//값 삭제
set1.remove(72); //지정 값 제거
set1.clear(); //모든값 제거

메소드 활용

//최소값 출력
set1.first();

//최대값 출력
set1.last();

//입력값과 비교하여 큰 데이터 중 최소값 출력, 없으면 null 반환
set1.higher(3);  //3보다 큰 데이터 중 최소값 출력

//입력값과 비교하여 작은 데이터 중 최대값 출력, 없으면 null 반환
set1.lower(3); //3보다 작은 데이터 중 최대값 출력

위와 같이 TreeSet을 활용하면 객체들의 집합에서 가장 높거나 낮은 값을 구할 수 있으며, 지정된 파라미터와 집합 내 객체들의 값을 비교할 수도 있다. 이러한 측면에서 사용한다면 TreeSet은 활용도가 높다고 할 수 있다.


마무리

Map에 대해서 작성하면 게시글 자체가 너무 비대해져 가독성이 떨어질 것이라 판단되어 Map은 구조상의 차이도 있기 때문에 다음 게시글에서 작성하려한다.

사실 개발을 처음 시작하고 대부분 배열을 사용하거나 객체 자체를 반복문을 통해서 사용했었다. 하지만 DB와 연동하기 시작하고, 기초적인 코딩테스트 문제들을 풀다보니 Collection 프레임워크의 장점들을 확인할 수 있었고, 잘 활용한다면 코드의 재사용이나 유지보수성을 크게 개선할 수 있다는 것을 느끼게 되었다.

이번 게시글을 통해 완전히 기초적인 부분들을 다루어 보았지만 차츰차츰 활용하는 수준이 높아지다보면 더욱 복합적인 문제들도 보다 간편하게 해결할 수 있을 것이라 생각한다.

다음 게시글에서 Map에 대하여 이어서 정리하겠다.

그럼 이만.👊🏽

profile
서핑하는 개발자🏄🏽

0개의 댓글