15. [Java] 컬렉션(Collection) 2 / 20230502

2023. 5. 3. 02:15

🧑🏻‍💻 TIL(Today I Learned)


🧑🏻‍💻 컬렉션 프레임워크

 

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

➡️ 여러 데이터를 그룹으로 묶어놓은 것이 컬렉션, 이러한 컬렉션을 다루는 데 있어 편리한 미리 정의해 놓은 것

➡️ 특정 자료 구조에 데이터를 추가하고, 삭제하고, 수정하고, 검색하는 등 동작을 수행하는 편리한 메서드 제공

 

🔎 주요 인터페이스 세 가지 

  • List
    • 데이터의 순서가 유지되며 중복 저장이 가능한 컬렉션을 구현하는 데 사용 
    • ArrayList, Vector, Stack, LinkedList 등이 List 컬렉션 구현
  • Set 
    • 데이터의 순서가 유지되지 않으며 중복 저장 불가능한 컬렉션을 구현하는 데 사용
    • HashSet, TreeSet 등이 Set 인터페이스 구현
  • Map
    • 키(Key)와 값(value)의 쌍으로 데이터를 저장하는 컬렉션을 구현하는 데 사용
    • 데이터의 순서가 유지되지 않으며 키는 값을 식별하기 위해 사용되므로 중복 저장이 불가능하지만 값은 중복 저장 가능
👉🏻 List와 Set은 공통점이 많아  Collection이라는 인터페이스로 묶임 
👉🏻 즉, 이 둘의 공통점이 추출되어 추상화된 것이 바로 Collection 인터페이스 

 

🔎 Collection 인터페이스

Collection 인터페이스에서 사용할 수 있는 메서드

 

 

2. List<E> 

➡️ 배열과 같이 객체를 일렬로 늘어놓은 구조 

➡️ 객체를 인덱스로 관리하기 때문에 객체를 저장하면 자동으로 인덱스가 부여되고, 인덱스로 객체를 검색 추가 삭제할 수 있는 등의 여러 기능 제공 

➡️ 컬렉션 인터페이스의 메서드 또한 상속받아 사용가능

 

🔎  ArrayList

➡️ List 인터페이스를 구현한 클래스, 컬렉션 프레임워크에서 가장 많이 사용됨 

➡️ List 인터페이스를 구현하므로 저장 순서가 유지되고 중복 허용(데이터의 저장공간으로 배열 사용)

➡️ 객체를 추가하면 객체가 인덱스로 관리됨
    → 배열은 생성될 때 크기가 고정되며 크기를 변경할 수 없지만 ArrayList 는 저장 용량을 초과하여 객체들이 추가되면 자동으로 저장 용량이 늘어나게 됨 

➡️ List 계열의 자료구조의 특성을 이어받아 데이터가 연속적으로 존재함 : 데이터의 순서 유지

ArrayList<타입 매개변수> 객체명 = new ArrayList<타입 매개변수>(초기 저장 용량);

ArrayList<String> container1 = new ArrayList<String>();
// String 타입의 객체를 저장하는 ArrayList 생성
// 초기 용량이 인자로 전달되지 않으면 기본적으로 10으로 지정됩니다. 

ArrayList<String> container2 = new ArrayList<String>(30);
// String 타입의 객체를 저장하는 ArrayList 생성
// 초기 용량을 30으로 지정하였습니다.
  • 객체를 추가하면 인덱스 0부터 차례대로 저장됨
    → 특정 인덱스의 객체를 제거하면 바로 뒤 인덱스부터 마지막 인덱스까지 모두 앞으로 1 씩 당겨짐
  • 빈번한 객체 삭제와 삽입이 일어나는 곳에서는 LikedList 사용하는 것이 좋음 

 

🔎  LinkedList

➡️ 데이터를 효율적으로 추가, 삭제, 변경하기 위해 사용

➡️ 배열에는 모든 데이터가 연속적으로 존재하지만 LinkedList에는 불연속적으로 존재하며 이 데이터는 서로 연결(Link) 되어 있음 

➡️ 배열은 구조가 간단하고 데이터를 읽는 데 걸리는 시간이 짧지만 크기를 변경할 수 없고 비순차적인 데이터의 추가 삭제에 시간이 많이 걸린다는 단점이 있음 
     ✍🏻 그걸 보완하는 것이 "LinkedList"

➡️ 불연속적으로 연결되어 있는 것 → 노드를 하나하나 연결하고 있음 

class Node {
	Node next; // 다음 노드를 찾아갈 수 있는 참조변수 가지고 있음
	Object obj; // 데이터
}

// 데이터의 삭제 : 단 한 번의 참조변경만으로 가능
// 데이터의 추가 : 한번의 node 객체 생성과 두 번의 참조변경만으로 가능

➡️ 단점 : 데이터 접근성이 나쁨 (한 번에 가는 게 안 됨) ※ 이런 단점을 개선한 것이 : 이중 연결 리스트 

 

📍 이중 연결 리스트(doubleLinkedList) -> 연결이 두 개 (자바는 이렇게 구현)

class Node {
	Node next; // 다음 노드 참조변수
	Node previous; // 이전 노드 참조변수
	Object obj;
}
// 접근성 향상, 앞뒤로 이동가능하지만 배열에 비하면 아직 성능 좋지 않음
ArrayList(배열 기반, 연속적) vs LinkedList(연결 기반, 불연속적) => 성능 비교
1. 순차적으로 데이터를 추가/ 삭제 - ArrayList가 빠름
2. 비순차적으로 데이터를 추가/ 삭제(중간 추가/삭제) - LinkedList가 빠름
3. 접근 시간 - ArrayList가 빠름

 

 

3. Iterator

➡️ 컬렉션에 저장된 요소들을 순차적으로 읽어오는 역할

➡️ Collection 인터페이스에 정의된 iterator()를 호출하면 Iterator 타입의 인스턴스 반환됨 

➡️  Collection 인터페이스를 상속받는 List와 Set 인터페이스를 구현한 클래스들은 iterator() 메서드 사용가능

Iterator 인터페이스에 정의된 메서드

ArrayList<String> list = ...;
Iterator<String> iterator = list.iterator();

while(iterator.hasNext()){        // 다음 객체가 있다면
	String str = iterator.next();   // 객체를 읽어오고,
	if(str.equals("str과 같은 단어")){ // 조건에 부합한다면
		iterator.remove();            // 해당 객체를 컬렉션에서 제거합니다. 
	}
}
// hasNext()에서 true가 리턴될 때만 next() 메서드가 동작하도록 코드를 작성하는 것이 좋음
// next()메서드로 가져온 객체를 컬렉션에서 제거하고 싶다면 remove() 메서드 호출
// remove()메서드는 컬렉션에서 실제로 객체 삭제함
--------------------------------------------------------------
ArrayList<String> list = ...;
for(String str : list) {
	...
}
//Iterator 사용하지 않더라도 for-each 문 이용해 전체 객체 대상으로 반복 가능

 

 

4. Set<E>

➡️ 집합을 의미, 중복된 값을 허용하지 않음, 저장 순서를 유지하지 않는 컬렉션

 

🔎 HashSet

➡️ Set 인터페이스를 구현한 가장 대표적인 컬렉션 클래스 

➡️ 중복된 값을 허용하지 않으며 저장 순서 유지하지 않음 

➡️ 값을 추가할 때 해당 값이 중복된 값인지 판단하는 법 

  1. add(Object o)   통해 객체 저장
  2. 이때 저장하고자 하는 객체의 해시코드를 hashCode() 메서드로 얻어냄
  3. Set이 저장하고 있는 모든 객체의 해시코드를 HashCode() 메서드로 얻어냄
  4. 저장하고자 하는 객체의 해시코드와, Set에 이미 저장되어 있던 객체들의 해시코드 비교하여 같은 해시코드 있는지 검사 
    • 만약 같은 해시코드를 가진 객체가 존재한다면 5번으로
    • 같은 해시코드를 가진 객체가 존재하지 않는다면, Set에 객체 추가되고 add(Object o) 메서드가 true 리턴
  5. equals() 메서드 통해 객체 비교
    • true가 리턴 된다면 중복 객체로 간주하여   Set에 추가되지 않고 add(Object o)가 false 리턴
    • false가 리턴된다면 Set에 객체가 추가되며 add(Object o) 메서드가 true 리턴

HashSet  예시
출력 결과

📍 "Java"가 중복되니 한 번만 출력되고 마지막 "Java"는 출력되지 않음

 

🔎 TreeSet

➡️ 이진 탐색 트리 형태로 데이터 저장

➡️ 데이터의 중복 저장을 허용하지 않고 저장 순서를 유지하지 않는 Set 인터페이스의 특징 유지 

이진 탐색 트리(Binary Search Tree)란?
👉🏻 하나의 부모 노드가 최대 두 개의 자식 노드와 연결되는 이진트리의 일종, 정렬과 검색에 특화됨

class Node {
	Object element; // 객체의 주소값을 저장하는 참조변수
	Node left;      // 왼쪽 자식 노드의 주소값을 저장
	Node right;     // 오른쪽 자식 노드의 주소값을 저장
}
  • 모든 왼쪽 자식의 값이 루트나 부모보다 작고 모든 오른쪽 자식의 값이 루트나 부모보다 큰 값을 가지는 게 특징

 

5. Map<K, V>

➡️ Map 인터페이스는 키와 값으로 구성된 객체를 저장하는 구조로 되어있음 

➡️ 객체는 Entry 객체라고 하는데 이  Entry 객체는 키와 값을 각각 Key 객체와 Value 객체로 저장함 

➡️ 키는 중복으로 저장될 수 없지만 값은 중복 저장 가능 
     👉🏻 키의 역할이 값을 식별하는 것이기 때문에

➡️ 만약 기존에 저장된 키와 같은 키로 값을 저장하면 기존의 값이 새로운 값으로 대치됨

 

 

🔎 HashMap

➡️ Map 인터페이스를 구현한 대표적인 클래스 

➡️ 키와 값으로 구성된 객체 저장 Entry 객체 

➡️ 해시 함수를 통해 키와 값이 저장되는 위치를 결정하므로 사용자는 그 위치를 알 수 없고 삽입되는 순서와 위치 또한 관계 없음 

➡️ 해싱(Hashing)을 사용하기 때문에 많은 양의 데이터를 검색하는 데 있어 뛰어난 성능 보여줌

HashMap<String, Integer> hashmap = new HashMap<>();

// 키와 값의 타입을 따로 지정해야함

→ Map은 키와 값을 쌍으로 저장하기 때문에 iterator()를 직접 호출할 수 없음
    대신 keySet() 이나 entrySet() 메서드 이용해 Set 형태로 반환된 컬렉션에 iterator() 호출하여 반복자를 만든 후 반복자를 통해 순회가능

  • keySet() : 모든 키를 set 객체에 담아서 리턴(Set 타입)
  • entrySet() : 키와 값의 쌍으로 구성된 모든 Map.Entry 객체를 Set에 담아서 리턴

 

🔎 HashTable

➡️ HashMap과 내부 구조 동일, 사용방법 유사, 스레드와 관련

➡️  HashMap이 HashTable의 새로운 버전이라고 할 수 있음


컬렉션 대장정 끝! 코플릿도 여러 번 풀어봐야겠다 메서드는 다 외울 수 없으니 최대한 친해져야 할 듯!! 

BELATED ARTICLES

more