11장 컬렉션 프레임웍

slee2·2021년 9월 14일
0

Java의 정석

목록 보기
21/28
post-thumbnail

여러번 반복. 빠르게. 전체적으로 하는것이 중요. 이렇게 분량이 많은 부분을 공부할때는 다 이해를 못해도 전체적인 목차를 적어본다던가 훑어보는것이 중요하다. 실습이 되게 중요하다. 실습을 통해 어떻게 언제 쓰는지 알아두는 것에 중점을 둬야한다.

컬렉션(collection)

여러 객체(데이터)를 모아 놓은 것을 의미

프레임웍(framework)

  • 표준화, 정형화된 체계적인 프로그래밍 방식
  • 기능뿐만 아니라 프로그래밍을 정해놓았기 때문에 자유도는 떨어지지만, 프로그래밍의 생산성이 올라감. 유지보수도 용이해짐.

컬렉션 프레임웍(collections framework)

  • 자바에서 컬렉션 프레임워크란 다수의 데이터를 쉽고 효과적으로 처리할 수 있는 표준화도니 방법을 제공하는 클래스의 집합을 의미한다.
  • 데이터를 저장하는 자료 구조와 데이터를 처리하는 알고리즘을 구조화하여 클래스로 구현해 놓은 것.

컬렉션 클래스(collection class)

  • 다수의 데이터를 저장할 수 있는 클래스

컬렉션 프레임웍의 핵심 인터페이스

List 인터페이스

Set 인터페이스

Map 인터페이스

인터페이스특징구현클래스
List순서가 있는 데이터의 집합. 데이터의 중복을 허용한다. 예) 대기자 명단ArrayList, LinkedList,
Stack, Vector 등
Set순서를 유지하지 않는 데이터의 집합. 데이터의 중복을 허용하지 않는다. 예) 양의 정수집합, 소수의 집합HashSet, TreeSet 등
Map키(key)와 값(Value)의 쌍(pair)으로 이루어진 데이터의 집합순서는 유지되지 않으며, 키는 중복을 허용하지 않고, 값은 중복을 허용한다. 예) 우편번호, 지역번호HashMap, TreeMap,
Hashtable, Properties 등

Collection인터페이스의 메서드

메서드설명
boolean add(Object o)
boolean addAll(Collection c)
지정된 객체(o) 또는 Collection(c)의 객체들을 Collection에 추가한다.
void clear()Collection의 모든 객체를 삭제한다.
boolean contains(Object o)
boolean containsAll(Collection c)
지정된 객체(o) 또는 Collection의 객체들이 Collection에 포함되어 있는지 확인한다.
boolean equals(Object o)동일한 Collection인지 비교한다.
int hashCode()Collection의 hash code를 반환한다.
boolean isEmpty()Collection이 비어있는지 확인한다.
Iterator iterator()Collection의 Iterator를 얻어서 반환한다.
boolean remove(Object o)지정된 객체를 삭제한다.
boolean removeAll(Collection c)지정된 Collection에 포함된 객체들을 삭제한다.
boolean retainAll(Collection c)지정된 Collection에 포함된 객체만을 남기고 다른 객체들은 Collection에서 삭제한다. 이 작업으로 인해 Collection에 변화가 있으면 true를 그렇지 않으며 false를 반환한다.
int size()Collection에 저장된 객체의 개수를 반환한다.
Object[] toArray()Collection에 저장된 객체를 객체배열(Object[])로 반환한다.
Object[] toArray(Object[] a)지정된 배열 Collection의 객체를 저장해서 반환한다.

List 인터페이스 - 순서O, 중복O

List와 Set은 Collection 인터페이스의 자손이기 때문에 Collection 인터페이스에 있는 메서드를 모두 가지고 있다.

메서드설명
void add(int index, Object element)
boolean addAll(int index, Collection c)
지정된 위치(index)에 객체(element) 또는 컬렉션에 포함된 객체들을 추가한다.
Object get(int index)지정된 위치(intdex)에 있는 객체를 반환한다.
int indexOf(Object o)지정된 객체의 위치(index)를 반환한다.
(List의 첫 번째 요소부터 순방향으로 찾는다.)
int lastIndexOf(Object o)지정된 객체의 위치(index)를 반환한다.
(List의 마지막 요소부터 역방향으로 찾는다.)
ListIterator ListIterator()
ListIlterator listIterator(int index)
List의 객체에 접근할 수 있는 ListIterator를 반환한다.
Object remove(int index)지정된 위치(index)에 있는 객체를 삭제하고 삭제된 객체를 반환한다.
Object set(int index, Object element)지정된 위치(index)에 객체(element)를 저장한다.
void sort(Comparator c)지정된 비교자(comparator)로 List를 정렬한다.
List subList(int fromIndex, int toIndex)지정된 범위(fromIndex부터 toIndex)에 있는 객체를 반환한다.

Set 인터페이스 - 순서X, 중복X

Set인터페이스의 메서드 - Collection 인터페이스와 동일

집합과 관련된 메서드(Collection에 변화가 있으면 true, 아니면 false)

메서드설명
boolean addAll(Collection c)지정된 Collection (c)의 객체들을 Collection에 추가한다.(합집합)
boolean containsAll(Collection c)지정된 Collection의 객체들이 Collection에 포함되어 있는지 확인한다.(부분집합)
boolean removeAll(Collection c)지정된 Collection에 포함된 객체들을 삭제한다.(차집합)
boolean retainAll(Collection c)지정된 Collection에 포함된 객체만을 남기고 나머지는 Collection에서 삭제한다.(교집합)

Map 인터페이스 - 순서X, 중복(키X값O)

메서드설명
void clear()Map의 모든 객체를 삭제한다.
boolean containsKey(Object key)지정된 key객체와 일치하는 Map의 key객체가 있는지 확인한다.
booleancontainsValue(Object value)지정된 value객체와 일치하는 Map의 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에 value객체를 key객체에 연결(mapping)하여 저장한다.
void putall(Map t)지정된 Map의 모든 key-value쌍을 추가한다.
Object remove(Object key)지정한 key객체와 일치하는 key-value객체를 삭제한다.
int size()Map에 저장된 key-value쌍의 개수를 반환한다.
Collection values()Map에 저장된 모든 value객체를 반환한다.

ArrayList

  • ArrayList는 기존의 Vector를 개선한 것으로 구현원리와 기능적으로 동일
  • ArrayList와 달리 Vector는 자체적으로 동기화처리가 되어있다.
  • List 인터페이스를 구현하므로, 저장순서가 유지되고 중복을 허용한다.
  • 데이터의 저장공간으로 배열을 사용한다.(배열기반)

ArrayList의 메서드

import java.util.*;

public class Hello {
    public static void main(String[] args) {
    	ArrayList list1 = new ArrayList(10);
    	list1.add(new Integer(5));
    	list1.add(new Integer(3));
    	list1.add(new Integer(4));
    	
    	ArrayList list2 = new ArrayList(list1.subList(1, 2));
    	System.out.println(list1);	// [5, 3, 4]
    	System.out.println(list2);	// [3]
    	
    	Collections.sort(list1);	// [3, 4, 5]
    	Collections.sort(list2);	// [3]
    	
    	System.out.println(list1.containsAll(list2));	// true 포함되어있는가
    	
    	list1.add(1, "A");	// [3, A, 4, 5]
    	
    	System.out.println(list1);
    	
    	list1.add(0, "1");	// 문자열 "1" 
    	list1.add(5, 1);	// Integer 1
    	System.out.println("index="+list1.indexOf("1"));	// 문자열 "1"
    	// [1, 3, A, 4, 5, 1]
    	list1.remove(1);	// [1, A, 4, 5, 1]
    	list1.remove(new Integer(1));	// [1, A, 4, 5]
    	System.out.println(list1);
    }
}

ArrayList에 저장된 객체의 삭제과정

첫번째 인덱스부터 삭제하는 경우(X)

for(int i=0;i<list.size();i++)
	list.remove(i);

마지막 인덱스부터 삭제하는 경우(O)

for(int i=list.size()-1;i>=0;i--)
	list.remove(i);

Java API 소스 보기

/jdk설치경로/src/java/util/...
이클립스에서는 클래스를 드래그 후에 F3

LinkedList

배열의 장단점

장점 : 배열은 구조가 간단하고 데이터를 읽는데 걸리는 시간(접근시간, access time이 짧다.
단점1 : 크기를 변경할 수 없다. 크기를 변경해야 하는 경우 새로운 배열을 생성 후 데이터를 복사해야함.크기 변경을 피하기 위해 충분히 큰 배열을 생성하면, 메모리가 낭비됨.
단점2 : 비순차적인 데이터의 추가, 삭제에 시간이 많이 걸린다. 데이터를 추가하거나 삭제하기 위해, 다른 데이터를 옮겨야 함. 그러나 순차적인 데이터 추가(끝에 추가)와 삭제(끝부터 삭제)는 빠르다.

이 단점을 보안하기 위해 LinkedList를 사용한다. 구조체의 연결 리스트를 생각하면 될 것 같다.

class Node {
	Node	next;
   	Object	obj;
}

단점

  • 연결리스트. 데이터 접근성이 나쁨(한 번에 이동이 힘듬). 징검다리처럼 연결해서 이동해야됨.

이중 연결리스트

위의 단점을 보안하기 위해 나옴. 앞 뒤로 이동 가능.

더블리 링크드 리스트(doubly linked list)

class Node {
	Node	next;
   	Node	previous;
   	Object	obj;
}

그래도 한번에 2,3칸 이동은 안된다.

더블리 써큘러 링크드 리스트(doubley circular linked list)
위에서 마지막 노드의 next를 처음 노드로 연결. 처음 노드의 previous를 마지막 노드로 연결.

자바는 더블리 링크드 리스트로 구현이 되어있다.

성능비교 - ArrayList vs LinkedList

== 순차적으로 추가하기 ==
ArrayList : 406
LinkedList : 606

== 순차적으로 삭제하기 ==
ArrayList : 11
LinkedList : 46

== 중간에 추가하기 ==
ArrayList : 7382
LinkedList : 31

== 중간에서 삭제하기 ==
ArrayList : 6694
LinkedList : 380

== 접근시간테스트 ==
ArrayList : 1
LinkedList : 432

순차적 데이터관리, 데이터 접근 -> ArrayList가 빠름
비순차적 데이터 관리 -> LinkedList가 빠름

스택과 큐(Stack & Queue)

스택(Stack): LIFO구조. 마지막에 저장된 것을 제일 먼저 꺼내게 된다.

큐(Queue): FIFO구조. 제일 먼저 저장한 것을 제일 먼저 꺼내게 된다.

스택은 배열이 좋고, 큐는 링크드리스트가 좋다.

스택(Stack) 메서드

메서드설명
boolean empty()Stack이 비어있는지 알려준다.
Object peek()Stack의 맨 위에 저장된 객체를 반환. pop()과 달리 Stack에서 객체를 꺼내지는 않음.
Object pop()Stack의 맨 위에 저장된 객체를 꺼낸다.
Object push(Object item)Stack에 객체(item)를 저장한다.
int search(Object o)Stack에서 주어진 객체(o)를 찾아서 그 위치를 반환. 못찾으면 -1을 반환.

큐(Queue) 메서드

메서드설명
boolean add(Object o)지정된 객체를 Queue에 추가한다. 성공하면 true를 반환. 저장공간이 부족하면 lllegalStateException발생
Object remove()Queue에서 객체를 꺼내 반환. 비어있으면 NoSuchElementException발생(try-catch처리)
Object element()삭제없이 요소를 읽어온다. peek와 달리 Queue가 비었을 때 NoSuchElementException발생
boolean offer(Object o)Queue에 객체를 저장. 성공하면 true. 실패하면 false를 반환
Object poll()Queue에서 객체를 꺼내서 반환. 비어있으면 null을 반환
Object peek()삭제없이 요소를 읽어 온다. Queue가 비어있으면 null을 반환
import java.util.*;

public class Hello {
    public static void main(String[] args) {
    	Stack st = new Stack();
    	Queue q = new LinkedList();
    	
    	st.push("0");
    	st.push("1");
    	st.push("2");
    	
    	q.offer("0");
    	q.offer("1");
    	q.offer("2");
    	
    	System.out.println("== Stack ==");
    	while(!st.empty()) {
    		System.out.println(st.pop());
    	}
    	System.out.println("== Queue ==");
    	while(!q.isEmpty()) {
    		System.out.println(q.poll());
    	}
    }
}
== Stack ==
2
1
0
== Queue ==
0
1
2

스택과 큐(Stack & Queue)의 활용

  • 스택의 활용 예 - 수식계산, 수식괄호 검사, 워드프로세서의 undo/redo, 웹 브라우저의 뒤로/앞으로
  • 큐의 활용 예 - 최근사용문서, 인쇄작업 대기목록, 버퍼(buffer)

Iterator, ListIterator, Enumeration

컬렉션에 저장된 데이터를 접근하는데 사용되는 인터페이스

메서드설명
boolean hasNext()읽어 올 요소가 남아있는지 확인한다. 있으면 true, 없으면 false반환
Object next()다음 요소를 읽어온다. next()를 호출하기 전에hasNext()를 호출해서 읽어올 요소가 있는지 확인하는 것이 안전하다.

메서드설명
boolean hasMoreElements()hasNext()와 같다.
Object nextElement()next()와 같다.

평소에 Iterator을 쓰다가 Enumeration을 사용해야할때 Iterator메서드와 같다라는 걸 알고있으면 됨.
ListIterator는 Iterator의 접근성을 향상시킨 것(단방향 -> 양방향)
왜 사용하냐. List, Set, Map 전부 사용법이 달라서 표준화해서 쓰려고. 그냥 확인하고 다음거 읽어오는 용도.

List list = new ArrayList();	// 다른 컬렉션으로 변경할 때는 이 부분만 고치면 된다.
Iterator it = list.iterator();

while(it.hasNext()) {
	System.out.println(it.next());
}

Map과 Iterator

Map에는 iterator()가 없다. (Collection의 자손이 아님). keySet(), entrySet(), values()를 호출해야한다.

Map map = new HashMap();
	...
Iterator it = map.entrySet().iterator();

Arrays

배열을 다루기 편리한 메서드(static) 제공

  1. 배열의 출력 - toString()
  2. 배열의 복사 - copyOf(), copyOfRange()
  3. 배열 채우기 - fill(), setAll()
  4. 배열의 정렬과 검색 - sort(), binarySearch()
  5. 다차원 배열의 출력 - deepToString()
  6. 다차원 배열의 비교 - deepEquals()
  7. 배열을 List로 변환 - asList(Object...a)
  8. 람다와 스트림(14장)관련 - parallelXXX(), spliterator(), stream()

Comparator와 Comparable

객체 정렬에 필요한 메서드를 정의한 인터페이스

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

모르겠다 인생 이게뭐람

Integer와 Comparable

public final class Integer extends Number implements Comparable {
	public int compareTo(Object o) {
   		return compareTo((Integer)o);
   	}
    
   	public int compareTo(Integer anotherInteger) {
   		int thisVal = this.value;
 		int anotherVal = anotherInteger.value;
        	
   		return (thisVal < anotherVal ? -1 : (thisVal==anotherVal ? 0 : 1));
   	}
}

HashSet - 순서X, 중복X

HashSet

  • Set인터페이스를 구현한 대표적인 컬렉션 클래스
  • 순서를 유지하려면, LinkedHashSet클래스를 사용하면 된다.

TreeSet

  • 범위 검색과 정렬에 유리한 컬렉션 클래스
  • HashSet보다 데이터 추가, 삭제에 시간이 더 걸림

HashSet - 주요 메서드

Object[] obj = {"1", new Integer(1), "2", "3", "3", "3", "4", "4", "4"};
Set set = new HashSet();

for(int i=0; i < obj.length; i++) {
	set.add(obj[i]);	// HasSet에 obj의 요소들을 저장한다.
}
System.out.println(set);

--- 결과 ---
[1, 1, 2, 3, 4]
  • HashSet은 객체를 저장하기전에 기존에 같은 객체가 있는지 확인 같은 객체가 없으면 저장하고, 있으면 저장하지 않는다.
  • boolean add(Object o)는 저장할 객체의 equals()와 hashCode()를 호출. equals()와 hashCode()가 오버라이딩 되어 있어야 함.
import java.util.*;

public class Ex11_11 {

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		HashSet set = new HashSet();
		
		set.add("abc");
		set.add("abc");	// 중복이라 저장안됨.
		set.add(new Person("David", 10));
		set.add(new Person("David", 10));
		
		System.out.println(set);
	}
}

// equals()와hashCode()를 오버라이딩해야 HashSet이 바르게 동작.
class Person {
	String name;
	int age;
	
	@Override
	public int hashCode() {
		return Objects.hash(name, age);
	}
	@Override
	public boolean equals(Object obj) {
		if(!(obj instanceof Person)) return false;
		
		Person p = (Person)obj;
		//나 자신(this)의 이름과 나이를 p와 비교
		return this.name.contentEquals(p.name)&& this.age==p.age; 
	}
	Person(String name, int age) {
		this.name = name;
		this.age = age;
	}
	public String toString() {
		return name + ":" + age;
	}
}
-- 결과 --
[David:10, abc]

이클립스에서 오버라이딩 하는 방법




TreeSet - 범위 탐색, 정렬

이진 탐색 트리(binary search tree)로 구현. 범위 탐색과 정렬에 유리.
이진 트리는 모든 노드가 최대 2개의 하위 노드를 갖음.

class TreeNode {
	TreeNode left;	// 왼쪽 자식노드
   	Object element;	// 저장할 객체
   	TreeNode right;	// 오른쪽 자식노드
}

이진 탐색 트리(binary search tree)

부모보다 작은 값은 왼쪽, 큰 값은 오른쪽에 저장
데이터가 많아질 수록 추가, 삭제에 시간이 더 걸림(비교 횟수 증가)

class TreeNode {
	TreeNode left;
   	Object element;
   	TreeNode right;
}

데이터 저장 과정 boolean add(Object o)

TreeSet에 7, 4, 9, 1, 5의 순서로 데이터를 저장하면, 아래의 과정을 거친다.

메서드

생성자 또는 메서드설명
TreeSet()기본 생성자
TreeSet(Collection c)주어진 컬렉션을 저장하는 TreeSet을 생성
TreeSet(Comparator comp)주어진 정렬기준으로 정렬하는 TreeSet을 생성
Object first()정렬된 순서에서 첫 번째 객체를 반환한다.
Object last()정렬된 순서에서 마지막 객체를 반환한다.
Object ceiling(Object o)지정된 객체와 같은 객체를 반환. 없으면 큰 값을 가진 객체 중 제일 가까운 값의 객체를 반환. 없으면 null
Object floor(Object o)지정된 객체와 같은 객체를 반환. 없으면 작은 값을 가진 객체 중 제일 가까운 값의 객체를 반환. 없으면 null
Object higher(Object o)지정된 객체보다 작은 값을 가진 객체 중 제일 가까운 값의 객체를 반환. 없으면 null
SortedSet subSet(Object fromElement, Object toElement)범위 검색(fromElement와 toElement사이)의 결과를 반환한다.
SortedSet headSet(Object toElement)지정된 객체보다 작은 값의 객체들을 반환한다.
SortedSet tailSet(Object fromElement)지정된 객체보다 큰 값의 객체들을 반환한다.

subSet(), headSet(), tailSet() - 범위 검색

HashMap과 Hashtable - 순서X, 중복(키X,값O)

Map인터페이스를 구현. 데이터를 키와 값의 쌍으로 저장
HashMap(동기화X)은 Hashtable(동기화O)의 신버젼

HashMap

  • Map인터페이스를 구현한 대표적인 컬렉션 클래스
  • 순서를 유지하려면, LinkedHashMap클래스를 사용하면 된다.
  • 해싱(hashing)기법으로 데이터를 저장. 데이터가 많아도 검색이 빠르다.
  • 키(key)와 값(value)를 한 쌍으로 저장(Entry라고 부른다)
  • 만약 키를 중복으로 입력하면 그 키와 값이 새로 덮어씌워진다.

TreeMap

  • 범위 검색과 정렬에 유리한 컬렉션 클래스
  • HashMap보다 데이터 추가, 삭제에 시간이 더 걸림

해싱(hashing)

해쉬함수(hash function)로 해시테이블(hash table)에 데이터를 저장 검색
해시테이블은 링크드 리스트를 배열로 조합한 형태이다.(링크드 리스트로 한 이유는 변경에 유리하기 때문)

헤시테이블에서 저장된 데이터를 가져오는 과정

  1. 키로 해시함수를 호출해서 해시코드를 얻는다.(해시코드는 배열의 인덱스)
  2. 해시코드(해시함수의 반환값)에 대응하는 링크드리스트를 배열에서 찾는다.
  3. 링크드리스트에서 키와 일치하는 데이터를 찾는다.

메서드

생성자/메서드설명
HashMap()HashMap 객체를 생성
HashMap(int initialCapacity)지정된 값을 초기용량으로 하는 HashMap 객체를 생성
HashMap(int initialCapacity, float
loadFactor
지정된 초기용량과 load factor의 HashMap 객체를 생성
HashMap(Map m)지정된 Map의 모든 요소를 포함하는 HashMap을 생성
void clear()HashMap에 저장된 모든 객체를 제거
Object clone()현재 HashMap을 복제해서 반환
boolean containsKey(Object key)HashMap에 지정된 키(key)가 포함되어있는지 알려준다.
(포함되어 있으면 true)
boolean containsValue(Object value)HashMap에 지정된 값(value)이 포함되어있는지 알려준다.
(포함되어 있으면 true)
Set entrySet()HashMap에 저장된 키와 값을 엔트리(키와 값의 결합)의 형태로 Set에 저장해서 반환
Object get(Object key)지정된 키(key)의 값(객체)을 반환. 못찾으면 null 반환
Object getOrDefault(Object key, Object
defaultValue)
지정된 키(key)의 값(객체)을 반환한다. 키를 못찿으면, 기본값(dafaultValue)으로 지정된 객체를 반환
boolean isEmpty()HashMap이 비어있는지 알려준다.
Set keyset()HashMap에 저장된 모든 키가 저장된 Set을 반환
Object put(Object key, Object value)지정된 키와 값을 HashMap에 저장
void putAll(Map m)Map에 저장된 모든 요소를 HashMap에 저장
Object remove(Object key)HashMap에서 지정된 키로 저장된 값(객체)을 제거
Object replace(Object Key, Object
value
지정된 키의 값을 지정된 객체(value)로 대체
int size()HashMap에 저장된 요소의 개수를 반환
Collection values()HashMap에 저장된 모든 값을 컬렉션의 형태로 반환

Collections

컬렉션을 위한 메서드(static)를 제공
1. 컬렉션 채우기, 복사, 정렬, 검색 - fill(), copy(), sort(), binarySearch() 등
2. 컬렉션의 동기화 - synchronizedXXX()

3. 변경불가(readOnly) 컬렉션 만들기 - unmodifableXXX()

4. 싱글톤 컬렉션 만들기 - singletonXXX()

5. 한 종류의 객체만 저장하는 컬렉션 만들기 - checkedXXX()

List list = new ArrayList();
List checkedList = checkedList(list, String.class);	// String만 저장가능
checkedList.add("abc");			// OK.
checkedList.add(new Integer(3));	// 에러. ClassCastException 발생

마무리 && 요약


0개의 댓글