javaboiii의 JAVA/JAVA 요약정리(멘토씨리즈)

JAVA - 16) 컬렉션 프레임워크(Collection Framework)

javaboiii 2024. 7. 27. 23:47

JAVA

1. 컬렉션 프레임워크(Collection Framework)

자료 구조는 프로그램 실행 시 메모리에 자료를 유지하고 관리하기 위해 사용합니다. 배열은 정한 크기를 변경하거나

삭제할 수 없습니다. 또한 별도의 기능이 없기  때문에 직접 index를 이용해 데이터를 저장해야 합니다. 자바는 이러한

불편함을 해결하기 위해 필요한 자료구조를 미리 구현하여 java.util 패키지에서 제공하고 있습니다.

이를 '컬렉션 프레임워크'라고 합니다. 컬렉션은 기존에 있던 List(리스트), Queue(큐), Tree(트리) 등의 자료 구조를 뜻하고

프레임워크는 클래스와 인터페이스를 묶어 놓은 개념입니다.

즉, 컬렉션 프레임워크란 기존에 존재햇던 자료 구조에 인터페이스로 설계된 기능을 클래스를 통해 제공하여 데이터

관리에 용이한 자료 구조 객체를 구조화한 것을 말합니다.

컬렉션 프레임워크에서는 데이터를 저장하는 자료구조에 따라 다음과 같이 주요 인터페이스를 정의하고 있습니다.

 

List와 Set 인터페이스는 모두 컬렉션 인터페이스를 상속받지만, Map 인터페이스는 구조상의 차이로 별도로 정의됩니다.

인터페이스 설명 특징 대표 구현 클래스
List 순서가 있는 데이터 집합 데이터 중복 허용 O ArrayList, LinkedList
Set 순서를 유지하지 않는 데이터 집합 데이터 중복 허용 X HashSet, LinkedHashSet
Map 키(key)와 값(value)의 쌍으로
이루어진 데이터 집합
순서 유지 X, 키 중복 X, 값 중복 O HashMap, LinkedHashMap,
Properties

2. 제네릭(Generic)

Integer형 배열, String형 배열 등 배열에 포함되는 원소의 타입마다 추가, 삭제, 정렬과 같은 함수를 정의하고 사용하는

것은 분명 효율적인 일입니다. 자바의 제네릭(Generic)은 데이터의 타입을 일반화한다는 것을 의미합니다. 클래스나

메서드 정의 시 일반화하여 사용할 데이터 타입을 컴파일할 때 미리 지정하는 방법입니다.

JDK 1.5 이전에는 여러 타입을 사용하는 대부분의 클래스나 메서드에서 반환값으로 Object 타입을 사용했습니다.

이러한 경우 잘못된 캐스팅으로 인해 런타임 오류가 발생할 가능성이 있었지만 JDK 1.5부터 도입된 제네릭을 사용하면

컴파일할 때 타입이 미리 정해지므로 타입 검사나 변환과 같은 번거로운 작업을 생략할 수 있으며 클래스나 메서드 내부에

사용될 데이터 타입의 안정성을 높일 수 있습니다.

제네릭을 사용하는 이유

내부의 배열 타입이 Object인 클래스를 만들면 Object는 최상위 클래스이므로 어떠한 데이터 형태라도 저장이 가능하지만

데이터를 저장한 후 실제 꺼내어 사용하려면 어떤 데이터 타입을 지녔는지 일일히 확인해야 하고, 약속한 데이터가

입력되지 않아 에러가 발생할 수도 있습니다. 또한 사용할 때 데이터 타입 변환을 위한 검사를 해야 하는 번거로움이 있습니다. 이때, 제네릭을 사용하면 원하는 데이터 타입을 자유롭게 지정하여 저장할 수 있습니다.

Generic 선언 및 생성

제네릭 타입은 타입을 파라미터로 가지는 클래스와 인터페이스를 말하며, 다음과 같이 선언합니다. 클래스 또는

인터페이스 이름 뒤에 < > 기호를 추가하고 안에 타입 파라미터를 입력합니다.

public class 클래스명<T> {...}
public interface 인터페이스명<T> {...}

위에서 사용된 "T"를 타입 변수(type variable)라고 하며, 이를 이용해 타입을 제한합니다. 여러 개의 타입 변수는 쉼표(,)로

구분하여 명시할 수 있습니다. 타입 파라미터는 정해진 규칙은 없지만 일반적으로 알파벳 대문자 한 글자로 표현합니다.

다음은 제네릭에서 자주 사용하는 타입의 인자와 의미 입니다. 제네릭을 표현할 때 사용합니다.

타입 변수 의미
<T> Type
<E> Element
<K> Key
<N> Number
<V> Value

 

클래스에 제네릭을 부여하면 해당 클래스를 선언할 때 데이터 타입을 부여하게 됩니다. 그러면 객체를 생성할 때 타입이

지정된 부분이 대체 되어 해당 클래스는 지정된 객체만을 저장할 수 있게 되고, 따로 타입을 변환할 필요 없이 데이터를

출력할 수 있습니다. 또한, 클래스를 사용해 다른 데이터를 저장하고 싶다면, DataList 클래스를 다시 선언하여 원하는 

데이터 타입을 부여한 후 사용하면 됩니다. 이렇듯 제네릭을 이용하면 하나의 객체로 다양한 데이터를 사용할 수 있습니다.

3. List 컬렉션

List는 배열과 유사한 자료 구조로 중복이 허용되면서 저장 순서가 유지되는 구조를 제공합니다. 즉 벼열처럼 index를

사용해 데이터를 저장하고 찾게 됩니다. 다만, 배열과는 다르게 크기의 제한이 없으며 삽입, 삭제, 변경의 기능이 자유롭습니다. 데이터의 크기를 특정할 수 없는 다량의 데이터를 저장할 때 용이하게 사용할 수 있는 자료 구조입니다.

 

List 컬렉션은 List 인터페이스를 생성하여 기능을 정의하고 하위 클래스에 상속해 그 기능을 구현하도록 합니다. 대표적으로 List 인터페이스를 사속하여 구현한 ArrayList, LinkedList, Vector 등을 List 계열 자료 구조로 사용합니다.

다음은 List가 제공하는 주요 메서드 입니다.

메서드 동작 기능 설명
void add(E e) 삽입 데이터를 순차적으로 삽입
void add(int index, E e) 중간 삽입 원하는 index 위치에 삽입
void set(int index, E e) 치환 원하는 index 위치의 값 변경
E get(int index) 반환 선택된 index 위치의 값 반환
void remove(int index) 삭제 선택된 index 위치 값의 삭제
void clear() 전체 삭제 모든 데이터 삭제
int size() 크기 저장된 데이터의 개수 반환
boolean contains(Object o) 검색 데이터 존재 여부 확인

 

메서드의 매개변수 또는 메서드 반혼 타입에 E라는 타입은 List 컬렉션을 생성할 때 지정한 저장 데이터 타입을 반영합니다

ArrayList

ArrayList는 가장 많이 사용하는 List 인터페이스의 대표적인 구현 클래스로 JDK 1.2부터 제공된 ArrayList는 내부적으로는

배열을 이용해 구현되어 배열과의 호환성이 좋은 자료 구조입니다. ArrayList를 선언하는 방법은 다음과 같습니다.

List<데이터 타입> list = new ArrayList<데이터 타입>();

자료 구조 선언 시 저장할 데이터의 타입을 명시해야 하는데 지정되는 데이터는 항상 객체형으로 지정해야 합니다.

int형, long형, double형과 같이 기본 자료형은 대응하는 Wrapper 클래스를 이용하여 지정합니다.

ArrayList 데이터 저장

ArrayList에 데이터를 추가하려면 add(E e) 또는 add(int index, E e) 메서드를 사용합니다.

일반 적인 add(E e) 메서드를 이용해 데이터를 삽입하면 기존에 존재하는 마지막 데이터의 뒤에 차레대로 삽입됩니다.

삽입 시에는 index가 부여되며 배열과 마찬가지로 순차적으로 부여됩니다.

add(int index, E e) 메서드는 원하는 index 위치에 데이터를 삽입할 수 있습니다. 그러나 연속성이 없이 순서를 부여해

삽입하는 것은 불가능합니다.

데이터 삽입을 원하는 위치에 기존 데이터가 존재한다면, 기존 데이터는 뒤로 이동하게 되고 새로운 데이터가 그 자리에

추가됩니다. 하지만 추가를 원하는 위차가 연속성이 없는 위치라면 문법적으로 오류가 발생하지 않지만 실행 시 오류가 발생합니다.

ArrayList 데이터 치환

List에 저장된 데이터를 변경할 수 있습니다. 변경을 원하는 index 위치와 치환할 값 또는 객체를 지정하면 해당 위치의

값이 변경됩니다. 이때, 사용하는 메서드는 다음과 같습니다.

void set(int index, E value);

set() 메서드를 사요해 원하는 위치의 값을 변경할 수 있습니다.

ArrayList 데이터 삭제

List의 데이터 삭제는 단지 데이터만 삭제되는 것이 아니라 해당 위치의 공간까지 삭제됩니다. 배열의 경우 공간이 생성되면 삭제할 수 없지만 List는 원하는 위치의 공간을 삭제할 수 있으며 빈 공백을 메우기 위해 뒤의 데이터들이 앞으로 이동합니다. 데이터를 삭제할 때는 remove() 메서드를 이용합니다. 해당 메서드는 remove(int index)와 remove(Object o)

두 가지가 있는데 remove(int index)는 index를 이용해 특정 위치의 데이터를 삭제하고 remove(Object o)는 저장한

데이터를 삭제 합니다.

ArrayList 데이터 얻기

List에 담긴 값을 가져올 때는 E get(int index) 메서드를 이용해 원하는

index 위치에 저장되어 있는 값을 출력할 수 있습니다.

LinkedList

LinkedList는 데이터와 다음 데이터의 주소를 가지는 노드(node) 객체가 연결되어 데이터를 저장하는 자료 구조입니다.

ArrayList와 마찬가지로 List 컬렉션의 구현 클래스이므로 사용할 수 있는 메서드가 대부분 동일합니다. ArrayList는 배열을

이용해 데이터를 저장하는 반면 LinkedList는 node라는 객체를 생성하여 인접 데이터를 링크해서 체인처럼 관리합니다.

 

LinkedList는 node라는 구조를 가진 클래스들이 체인 형식으로 이어져 있습니다. 노드는 데이터 값과 주소를 가지는데, 주소는 다음에 오는 노드의 값을 가지고 있어서 연결 구조를 이룹니다. 따라서 index가 실제 존재하지는 않지만, 서로 연결되어 있기 때문에 순서를 알 수 있습니다.

LinkedList 선언

LinkedList는 다음과 같이 선언합니다.

List<Integer> list = new LinkedList<Integer>();
List<Integer> list = new LinkedList<>();
또는
LinkedList<Integer> list = new LinkedList<Integer>();
LinkedList<Integer> list = new LinkedList<>();

LinkedList의 경우에는 부모 타입으로 선언하거나 기본 선언 방식인 자신의 객체 타입 그대로 선언하는 방식을 택하게 됩니다. LinkedList는 List 인터페이스 외 다른 기능들도 상속하고 있으므로 LinkedList 본연의 기능을 모두 사용할 경우에는

기본적인 객체 선언 방식을 선택합니다.

LinkedList 데이터 저장

LinkedList의 데이터 추가 기능은 ArrayList와 동일합니다. add(E e) 또는 add(int index, E e) 메서드를 이용해 데이터를

추가합니다. 하지만 내부적으로 동작하는 방식은 상당히 다릅니다.

LinkedList에서 데이터를 추가할 때는 기존에 연결되어 있던 링크를 끊고, 추가된는 데이터에 새롭게 주소를 연결합니다.

또한 추가되는 노드는 뒤에 올 데이터와 링크하여 삽입합니다. ArrayList는 삽입되는 위치부터 맨 뒤의 데이터까지 이동시키고 데이터를 삽입하기 때문에 삽입 속도가 느리지만 LinkedList는 노드가 가지고 있는 다음에 오는 개체의 주소만 변경하면 되므로 빠르게 처리할 수 있습니다.

LinkedList 삭제

LinkedList의 삭제는 ArrayList와 동일하게 remove(int index) 또는 remove(Object o) 메서드를 이용합니다. List를 상속한 자료 구조들은 List 인터페이스를 상속하여 구현했으므로 사용 메서드는 동일합니다. 하지만 구현 방식은 ArrayList와는 다르게 동작합니다. ArrayList의 경우 삭제된 데이터의 공백을 메우기 위해 이후 데이터들을 모두 앞으로 이동시키는 반면

LinkedList는 삭제할 데이터와의 연결을 끊고 그 뒤의 데이터와 연결하여 쉽게 데이터를 삭제합니다.

 

ArrayList와 LinkedList의 성능을 비교하면 그 성격이 뚜렷하게 나타납니다.

ArrayList의 경우 연속성 있게 데이터를 추가할 수 있으면 출력 속도가 빠릅니다. 그러나 데이터를 특정 위치에 삽입하거나

삭제하는 것은 LinkedList가 우위에 있습니다. 따라서 데이터를 나열하여 저장하고 사용할 때는 ArrayList를, 삽입과 삭제가

빈번한 경우에는 LinkedList를 사용하는 것이 좋습니다.

4. Set 컬렉션

Set 컬렉션은 List 컬렉션과 다른게 객체의 저장 순서를 저장하지 않습니다. Set 컬렉션은 수학의 집합과 유사한 개념을

지니고 있습니다. List 컬렉션은 데이터 저장 시 중복을 허용하지만 Set 컬렉션은 데이터의 중복을 허용하지 않습니다.

또한 데이터를 저장할 때 순서, 즉 index를 부여하지 않기 때문에 데이터가 입력된 순서로 출력된다는 보장은 없습니다.

 

Set 컬렉션은 Set 인터페이스를 상속해 구현되었습니다. 대표적으로 HashSet, TreeSet, LinkedHashSet을 Set계열

자료 구조로 사용합니다.

다음은 Set 인터페이스에서 제공하는 주요 메서드입니다.

메서드 기능 설명
void add(E e) 데이터를 순차적으로 삽입
void remove(Object o) 선택된 값 삭제
void clear() 모든 데이터 삭제
int size() 저장된 데이터의 개수 반환
boolean constain(Object o) 데이터 존재 여부 확인

HashSet 클래스

HashSet 클래스는 Set 컬렉션 클래스에서 가장 많이 사용되는 클래스로 인터페이스를 상속받아 구현합니다.

HashSet클래스를 선언하는 방법은 다음과 같습니다.

Set<E> set = new HashSet<E>();
Set<E> set = new HashSet<>();

E는 Set컬렉션에 저장할 데이터 타입을 의미합니다. Set 컬렉션을 선언할 때 어떤 데이터 형식을 저장할지 제네릭을 통해 지정하게 됩니다.

HashSet 데이터 저장

HasSet은 데이터를 저장할 때 순서(index)를 부여하지 않고, 데이터의 중복을 허용하지 않습니다. 즉 동일한 값 또는 객체를 허용하지 않는다는 의미입니다. 여기서 동일한 객체한, 꼭 같은 타입의 인스턴스를 의미하는 것은 아닙니다.

HashSet은 데이터를 객체의 hashCode() 값을 호출하여 비교하고 같으면 equals() 메서드를 호출하여 다시 비교해 두 객체가 같음을 증명합니다.

 

만약 HashSet에 객체를 저장해야 한다면 해당 객체는 hashCode와 equals 메서드를 사용해 비교하는 로직을 구현해야 합니다.

HashSet의 데이터 삭제

HashSet의 데이터 삭제는 List 컬렉션과 동일하게 remove(Object o) 메서드를 사용합니다. Set 컬렉션은 index가 존재하지 않으므로 순서에 의한 삭제는 지원하지 않습니다.

5. 반복차 Iterator

Iterator<E>는 List 컬렉션에서 제공하는 인터페이스로 사전적인 의미로는 '반복하다'라는 뜻을 지니고 있습니다.

List 컬렉션의 요소를 순회하여 하나씩 추출하는 데 사용합니다. E에는 순회할 데이터의 타입을 지정하는데 보통 순회할

컬렉션이 포함하는 데이터 타입과 동일하게 지정합니다. 반복자라고도 불리는 Iterator 객체는 선언된 컬렛견 객체에서 가져와 사용합니다. 다음은 Iterator를 사용해 모든 요소를 순회할 때 사용하는 메서드입니다.

메섣드 기능 설명
boolean hashNext() 다음 순회할 데이터 유무 확인
가져올 객체가 있으면 true, 없으면 false를 반환
E next() 다음 위치의 데이터로 이동하여 반환

List 계열의 컬렉션의 경우 index를 이용한 for문보다는 Iterator를 이용하거나, 향상된 for문을 사용하는 것이 성능 향상에 도움이 됩니다.

6. Map 컬렉션

Map은 List, Set과 달리 Map 인터페이스가 별도로 존재하며, 데이터를 List 계열의 컬렉션과 다르게 처리합니다. Map 인터페이스는 데이터를 key(키)와 value(값)로 구분하여 저장하는 방식(key-value 방식)을 사용합니다.

 

Map은 인터페이스를 상속하여 구현한 HashMap, TreeMap, LinkedHashMap이 있습니다. 이 중에서 HashMap은 Map 인터페이스를 구현하여 가장 많이 사용하는 대표적인 클래스입니다.

Map에서 key는 중복될 수 없지만 value는 중복이 가능합니다. 만약 key가 중복되어 입력될 경우 key에 해당하는 value값이 업데이트되어 저장되기 때문에 key의 중복에 유의해야 합니다. Map의 key와 value는 Entry라는 인터페이스를 상속한 객체에 저장되는 Entry는 Map 인터페이스 안에서 정의되는 내부 인터페이스를 말합니다.

 

Map 컬렉션은 Map.Entry 구조를 저장하고 해당 객체는 key와 value를 저장합니다. 검색을 요구하는 데이터를 저장하는데

효과적이지만 데이터를 저장하고 삭제할 대는 다소 느린 편입니다.

 

다음은 Map 컬렉션의 주요 메서드입니다.

메서드 기능 설명
void put(K key, V value) key에 대응하는 value 저장
E get(K key) key에 대응하는 value 반환
boolean containsKey(K key) key 존재 여부 검색
boolean conntainsValue(V value) value 존재 여부 검색
Set<E> keySet() 모든 key를 Set 컬렉션에 저장하여 반환
Set<Map.Entry> entrySet() 모든 Map.Entry 객체를 Set에 담아서 반환

HashMap<k, v>

HashMap은 앞에서 다뤘던 HashSet과 마찬가지로 해싱(hashing)을 통해 key의 중복 여부를 판단합니다. 즉 key로 지정된 객체의 hashCode와 equals 메서드를 이용해 동일 여부를 판단하게 됩니다. HashMap은 Map 인터페이스를 상속하여 기능을 구현했기 떄문에 key의 중복을 허용하지 않습니다. 만약 중복된 key가 들어오면 기존 key가 지닌 데이터를 업데이트하게 됩니다.

HashMap 선언 및 사용법

HashMap의 선언은 이전의 컬렉션 선언과 크게 다르지 않지만, key에 대한 제네릭이 추가되었습니다.

HashMap을 선어하는 방법은 다음과 같습니다.

Map <KEY, V> map = new HashMap<KEY, V>();
Map <KEY, V> map = new HashMap<>();

응용문제

1. 다음 중 컬렉션의 설명으로 틀린 것은 무엇입니까 ?

① List 컬렉션은 index로 객체를 관리하며 중복 저장을 허용합니다.

② Set 컬렉션은 순서를 유지하지 않으며 중복저장을 허용하지 않습니다.

③ Map 컬렉션은 key와 value로 구성된 Map.Entry를 저장합니다.

④ LinkedList는 List 컬렉션과 동일하게 index로 객체를 관리합니다.

 

정답 : ④

2. 다음 빈칸에 알맞은 코드를 작성해 보세요.

package section16;

public class PRACTICE_16_02{
	public static void main(String[] args){
    	List<ㅁㅁㅁㅁ> list = new ArrayList<>();
        
        List.add(1);
        List.add(2);
        List.add(3);
        List.add(4);
        List.add(5);
        
        for(int i=0; i<list.size(); i++){
        	System.out.println(list.get(i));
        }
    }
}

정답 : 

package section16;

public class PRACTICE_16_02{
	public static void main(String[] args){
    	List<Integer> list = new ArrayList<>();
        
        List.add(1);
        List.add(2);
        List.add(3);
        List.add(4);
        List.add(5);
        
        for(int i=0; i<list.size(); i++){
        	System.out.println(list.get(i));
        }
    }
}

3. 다음 중 Set 컬렉션에 대한 설명으로 틀린 것은 무엇입니까 ?

① 대표적인 구현 클래스로는 HashSet, LinkedHashSet, TreeSet이 있습니다.

② Set 컬렛견에서 객체를 하나씩 꺼내오고 싶다면 Iterator를 이용합니다.

③ HashSet은 hashCode()와 equals()를 이용해 중복된 객체를 판별합니다.

④ Set 컬렉션에는 null을 저장할 수 없습니다.

 

정답 : ④

4. 랜덤 함수를 사용해 리스트 컬렉션에 10개의 숫자를 입력한 후 입력된 숫자 중에서 짝수의 합을 구하여 출력해보세요.

package section16;

public class ArrayListSumExample{
	public static void main(String[] args){
    	List<Integer> list = new ArrayList<>();
        
        for(int i=0; i<10; i++){
        	
        }
        int sum = 0;
        for(int i=0; i<list.size(); i++){
        	
        }
        
        System.out.println("짝수의 합: " +sum);
    }
}

정답 :

package section16;

public class ArrayListSumExample{
	public static void main(String[] args){
    	List<Integer> list = new ArrayList<>();
        
        for(int i=0; i<10; i++){
        	list.add(i);
        }
        int sum = 0;
        for(int i=0; i<list.size(); i++){
        	if(list.get(i)%2 == 0){
            	sum += list.get(i);
            }
        }
        
        System.out.println("짝수의 합: " +sum);
    }
}

5.주머니에는 파란색, 빨간색, 검은색 공이 모두 10개 들어있습니다. 각각의 색깔을 지닌 공이 몇 개씩 들어있는지 Map 컬렉션을 사용해 출력해 보세요.

package section16;

public class PRACTICE_16_05{
	public static void main(String[] args){
    	String[] balls = {"빨간색", "파란색", "검은색", "검은색", "빨간색", "파란색",
        					"빨간색", "빨간색", "파란색", "검은색"};
    	Map<String, Integer> map = new HashMap<>();
        for(String ball : balls){
        .
        .
        . 이어서 작성
        .
        
        
        
실행 결과 : 
빨간색 4개
파란색 3개
검은색 3개

정답 : 

package section16;

public class PRACTICE_16_05{
	public static void main(String[] args){
    	String[] balls = {"빨간색", "파란색", "검은색", "검은색", "빨간색", "파란색",
        					"빨간색", "빨간색", "파란색", "검은색"};
    	Map<String, Integer> map = new HashMap<>();
        for(String ball : balls){
        	if (map.containsKey(ball)) {
				map.put(ball, map.get(ball) + 1);
			} else {
				map.put(ball, 1);
			}
		}

		// 결과 출력
		for (Map.Entry<String, Integer> entry : map.entrySet()) {
			System.out.println(entry.getKey() + ": " + entry.getValue() + "개");
		}
    }
}

 

 

6. 다음 빈칸에 알맞은 단어를 작성해 보세요.

데이터를 다룰 때 사용되는 주요 자료 구조를 ㅁㅁㅁㅁㅁㅁㅁㅁ라고 합니다.

 

저장 순서가 유지되지 않으며 객체를 중복해서 저장할 수 없고 하나의 null만 저장할 수 있는 ㅁㅁㅁ 컬렉션이 있습니다.

 

Map 컬렉션은 ㅁㅁㅁ와 ㅁㅁㅁㅁㅁ으로 구성된 Map.Entry 객체를 저장하는 구조를 가지고 있습니다.

 

정답 : 컬렉션, Set, key, value

'javaboiii의 JAVA > JAVA 요약정리(멘토씨리즈)' 카테고리의 다른 글

JAVA -18) 스레드(Thread)  (0) 2024.07.29
JAVA - 17) 람다식  (0) 2024.07.28
JAVA -15) 기본 API 클래스  (0) 2024.07.26
JAVA -14) 예외처리  (0) 2024.07.25
JAVA -13) 내부 클래스  (2) 2024.07.24