chapter 11 컬렉션 프레임워크

JMG·2022년 2월 2일
0

자바의 정석

목록 보기
12/13

📖 컬렉션 프레임워크(collections framework)

📌 컬렉션

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

📌 프레임웍(framework)

표준화, 정형화된 체계적인 프로그래밍 방식(생산성이 올라간다),
기능들만 모아놓은 라이브러리보다 상위개념입니다.

📌 컬렉션 프레임웍(collections framework)

  • 컬렉션(다수의 객체)을 다루기 위한 표준화된 프로그래밍 방식입니다.
  • 컬렉션을 쉽고 편리하게 다룰 수 있는 다양한 클래스를 제공(저장, 삭제, 검색, 정렬..)
  • java.util패키지에 포함. JDK1.2부터 제공

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

여러 데이터(객체들)를 다루는데 있어 핵심적인 세가지 방식을 상위 인터페이스로 정의해놓았습니다.

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

📌Collection인터페이스의 메서드

메서드설명
(추가)boolean add(Object o)지정된 객체(o) 또는 Collectrion(c)의 객체들을 Collection에 추가한다.
(추가)boolean addAll(Collection c)
(삭제)boolean remove(Object o)지정된 객체를 삭제한다.
(삭제)boolean removeAll(Collection c)지정된 Collection에 포함된 객체들을 삭제한다.
(검색)boolean contains(Object o)지정된 객체(o) 또는 Collectrion의 객체들이 Collection에 포함되어 있는 지 확인한다.
(검색)boolean containsAll(Collection c)
void clear()Collection의 모든 객체를 삭제한다.
boolean isEmpty()Collection이 비어있는지 확인한다.
int size()Collection에 저장된 객체의 개수를 반환한다.
Iterator iterator()Collection의 Itrator를 얻어서 반환한다.

📌List인터페이스(순서O, 중복O)

  • Vector
  • ArrayList - Vector의 개선 버젼
  • LinkedList

ArrayList와 LinkedList가 핵심입니다.

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

📌Set인터페이스(순서X, 중복X)

  • HashSet
  • SortedSet
  • TreeSet

Set인터페이스의 메서드는 Collection인터페이스와 동일합니다.
그중 집합과 관련된 메서드(Collection에 변화가 있으면 true, 아니면 false를 반환.)만 정리해보았습니다.

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

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

  • Hashtable
  • HashMap(Hashtable의 개선버젼) - LinkedHashMap(순서O)
  • SortedMap - TreeMap

HashMap과 TreeMap이 핵심입니다.

메서드설명
(추가)Object put(Object key, Object value)Map에 value객체를 key객체에 연결(mapping)하여 저장한다.
(추가)void putAll(Map t)지정된 Map의 모든 key-value쌍을 추가한다.
(삭제)Object remove(Object key)지정한 key객체와 일치하는 key-value객체를 삭제한다.
(검색)boolean containsKey(Object key)지정된 key객체와 일치하는 Map의 key객체가 있는지 확인한다.
(검색)boolean containsValue(Object value)지정된 value객체와 일치하는 Map의 value객체가 있는지 확인한다.
(검색)Object get(Object key)지정한 key객체에 대응하는 value객체를 찾아서 반환한다.
(읽기)Set entrySet()(entry는 key와value의 한쌍을 뜻함)Map에 저장되어 있는 key-value쌍을 MapEntry타입의 객체로 저장한 Set으로 반환한다.
(읽기)Set keySet()Map에 저장된 모든 key객체를 반환한다.
(읽기)Collectrion values()Map에 저장된 모든 value객체를 반환한다.

📖 ArrayList

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

public class Vector extends AbstractList
	implements List, RandomAccess, Cloneable, java.io.Serializable {
	...
	protected Object[] elementData; // 다형성을 이용해 모든 객체배열 생성
	...
}

📌ArrayList의 생성자

ArrayList() - 기본 생성자
ArrayList(Collection c) - Collection을 바인딩 할수 있는 ArrayList생성가능
ArrayList(int initialCapacity) - 배열의 길이 설정기능.
만약 사용하지 않는다면 데이터의 변화가 있을때 배열을 계속 생성함

📌ArrayList의 메서드

  1. 추가 메서드
    boolean add(Object o)
    void add(int index, Object element)
    boolean addAdd(Collection c)
    boolean addAll(int index, Collection c)

  2. 삭제메서드
    boolean remove(Object o)
    Object remove(int index)
    boolean removeAll(Collection c)
    void clear()

  3. 검색
    int indexOf(Object o)
    int lastIndexOf(Object o)
    boolean contains(Object o)
    Object get(int index)
    Object set(int index, Object Element)

  4. 기타
    List subList(int fromIndex, int tolIndex) - 지정인덱스 범위의 리스트 새로 생성
    Object[] toArray() - ArrayList의 객체배열을 반환
    Object[] toArray(Object[] a)
    boolean isEmpty() - 비어있는지 확인
    void trimToSize() - 빈공간제거
    int Size() - 저장된 객체의 갯수반환

예제)

import java.util.*;

classEx11_1 {
	public static void main(String[] args) {
		ArrayList list1 = new ArrayList(10);
		
		list1.add(new Integer(5));
		list1.add(new Integer(4));
		list1.add(new Integer(2));
		list1.add(new Integer(0));
		list1.add(new Integer(1));
		list1.add(new Integer(3));
		//아래와 같이 작성해도 괜찮으나autoboxing에 의해 기본형이 참조형으로 자동변환
		//list1.add(8); 
		
		//subList()는 시작index와 끝index를 넣으면 리스트를 추출할 수 있다.
		//new ArrayList(Collections c);
		ArrayList list2 = new ArrayList(list1.subList(1, 4));
		
		System.out.println(list1);	//[5, 4, 2, 0, 1, 3]
		System.out.println(list2);	//[4, 2, 0]

		//오름차순 정렬
		//Collection은 인터페이스, Collections는 유틸 클래스
		Collections.sort(list1);	//[0, 1, 2, 3, 4, 5]
		Collections.sort(list2);	//[0, 2, 4]
		print(list1, list2);

		//containsAll()모든요소를 포함하고 있는지 물어보는 함수
		System.out.println(list1.containsAll(list2));	//true

		//add()는 요소를 추가할때 사용한다.
		list2.add("B");
		list2.add("C");
		//중간에 요소를 추가하는 작업
		list2.add(3, "A");
		System.out.println(list2);	//[0, 2, 4, A, B, C]

		//set()은 list안에있는 요소를 바꿔주는 함수이다.
		list2.set(3, "AA");	//[0, 2, 4, AA, B, C]			

		list1.add(0, "1");
		//1과 "1"은 다르기 때문에 indexof()함수를 사용해 출력하면 다른 인덱스를 출력한다.
		System.out.println(list1.indexOf(1));	//2
		System.out.println(list1.indexOf("1"));	//0
		
		//remove()함수는 2가지가 있다.
		System.out.println(list1);	//[1, 0, 1, 2, 3, 4, 5]
		//인덱스로 삭제
		list1.remove(5);
		System.out.println(list1);	//[1, 0, 1, 2, 3, 5]
		//동일한 타입의 객체와 값으로 삭제
		list1.remove(new Integer(5));
		System.out.println(list1);	//[1, 0, 1, 2, 3]
		
		//retainAll은 겹치는 요소들만 남기고 삭제
		//list1에서 list2와 겹치는 부분만 남기고 삭제
		System.out.println(list1.retainAll(list2));	//[0, 2]

		//contains()함수는 해당 객체가 리스트에 포함되어 있는지를 boolean으로 반환하는 함수
		//list2에서 list1에 포함된 객체들을 삭제한다.
		for(int i=list2.size()-1; i>=0; i--) {
			if(list1.contains(list2.get(i))) {
				list2.remove(i)	
			}
		}
//ArrayList에 저장된 객체를 삭제하는 과정은 끝 인덱스부터 작업해야한다.

		System.out.println(list2);	//[4, AA, B, C]
		
	}
}

📖 LinkedList

배열의 장단점
장점: 배열의 구조가 간단하고 데이터를 읽는 데 걸리는 시간이 짧다.
단점:

  • 크기를 변경할 수 없다.(프로그램 실행 중)
    (더 큰배열을 만들어야 한다면 배열을 새로만들고 복사한 후 새로만든 배열로 참조변경해야한다.)
  • 비순차적인 데이터의 추가, 삭제에 시간이 많이 걸린다.

📌LinkedList

LinkedList는 기존 배열의 단점을 보완하여 불연속적으로 존재하는 데이터를 연결합니다.
데이터의 삭제는 단 한번의 참조변경만으로 가능합니다.

//데이터를 아래와같은 노드에 저장하여 보관합니다.
class Node {
	Node next;	//다음노드
	Object o;		//데이터 저장을 위한 객체
}

배열은 기다란 박스에 담긴 작은 상자들과 같아서 중간의 인덱스에 삭제나 추가를 할 경우 데이터를 전부 이동시켜야 하지만 연결리스트는 하나씩 연결된 기차와 같아서 바로 접근이 가능합니다.

//데이터의 추가: 한번의 Node객체생성과 두 번의 참조변경만으로 가능하다.
linkedlist (0x100) -> (0x200, 0) -> (0x300, 1) -> (0x400, 2) -> (null, 3)
//데이터를 추가할 경우
linkedlist (0x100) -> (0x200, 0) -> (0x500, 1) -> "(0x300, 4)" -> (0x400, 2) -> (null, 3)

linkedlist의 단점
데이터가 연속적이여서 접근성이 나쁩니다.
다음 데이터의 주소밖에 모르기 때문입니다.

📌 double linked list - 이중 연결리스트, 접근성이 향상

다음 노드의 주소뿐만아니라 이전노드의 주소를 함께 저장합니다.

class Node {
	Node next;	//다음노드
	Node previous	//이전노드
	Object o;		//데이터 저장을 위한 객체
}


doubleLinkedList(0x200) -> (0x300, null, 0) -> (0x350, 0x300, 1) -> (0x380, 0x300, 2) -> (null, 0x350, 3)

📌double circular linked list - 이중 원형 연결리스트

이중 연결리스트에 첫노드와 끝노드를 연결시켜서 접근성을 좀더 높게 변경합니다.

doubleCircularLinkedList(0x200) -> (0x300, 0x380, 0) -> (0x350, 0x300, 1) -> (0x380, 0x300, 2) -> (0x200, 0x350, 3)

📌 자바의 LinkedList는 이중 연결리스트로 구현이 되어 있습니다.

📌 결론

순차적인 데이터를 추가, 삭제하거나 데이터를 읽기만 할때는 ArrayList,
중간에 있는 데이터를 자주 삭제하거나 추가할 때 LinkedList를 사용하면 바람직합니다.

📖스택과 큐(stack & queue)

스택(stack) : LIFO(Last In First Out)구조. 마지막에 저장된 것을 제일 먼저 꺼내게 됩니다.
밑이 막힌 상자같은 구조입니다.
저장(push), 추출(pop)

큐(queue):FIFO(First In First Out)구조. 제일 먼저 저장한 것을 제일 먼저 꺼내게 된다.
양끝이 뚫린 상자같은 구조입니다.
저장(offer), 추출(poll)

📌스택은 ArrayList, 큐는 LinkedList로 구현하는 것이 적합합니다.

📌stack의 메서드

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

📌queue의 메서드

메서드설명
boolean offer(Object o)queue에 객체를 저장 성공하면 true, 실패하면 false반환
Object poll()queue에서 객체를 꺼내서 반환. 비어있으면 null반환
Object peek()삭제없이 요소를 읽어온다. queue가 비어있으면 null반환
boolean add(Object o)지정된 객체를 queue에 추가한다. 성공하면 true반환(예외발생)
Object remove()queue에서 객체를 꺼내 반환(예외발생)
Object element()삭제없이 요소를 읽어온다.(예외발생)
boolean isEmpty()queue가 비어있는지 알려준다.

stack은 클래스 queue는 인터페이스로 구현되어 있습니다.
그래서 queue를 직접 구현하거나 구현한 클래스(LinkedList)를 사용하면 됩니다.

Stack st = new Stack();
Queue que = new LinkedList();

예제)

import java.util.*;

class StackQueueEx {
	public static void main(String[] args) {
		Stack st = new Stack();
		Queue q = new LinkedList();	 // Queue인터페이스의 구현체인 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

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

📖Iterator, ListIterator, Enumeration

컬렉션에 저장된 데이터를 접근하는데 사용되는 인터페이스입니다.
Enumeration은 Iterator의 구버젼입니다.
ListIterator는 Iterator의 접근성을 향상시킨 것입니다.(단방향 -> 양방향)
Iterator가 가장 많이 쓰입니다.

📌 Iterator의 메서드

메서드설명
boolean hasNext()읽어 올 요소가 남아있는지 확인한다. 있으면 true, 없으면 false
Object next()다음 요소를 읽어 온다. next()를 호출하기전에 hasNext()를 호출해서 읽어올 요소가 있는지 확인할 때 주로 사용.

📌 Enumeration의 메서드

boolean hasMoreElements()
Object nextElement()

📌 왜 Iterator를 사용하는가??

컬렉션(List, Set, Map)에 저장된 요소들을 읽어오는 방법을 표준화한 것입니다.
컬렉션에 iterator()를 호출해서 Iterator를 구현한 객체를 얻어서 사용합니다.
컬렉션을 개발도중 다른 컬렉션으로 바꿔야할 때 유용합니다.

List list = new ArrayList();	//다른 컬렉션으로 변경시 new ~ 부분만 수정
Iterator it = list.iterator();

while(it.hasNext()) {		//읽어올 요소가 있는지 boolean으로 확인
	System.out.println(it.next());	//Object next() 다음요소를 읽어옴
}

📌 Map과 Iterator

Map에는 Iterator가 없습니다.
keySet(), entrySet(), values()를 호출해서 사용해야 합니다.

Map map = new HashMap();
Iterator it = map.entrySet().iterator();
//Set e = map.entrySer();
//Iterator it = e.iterator();

📖Arrays

배열을 다루기 편리한 메서드(static)을 제공합니다.
(Objects, Collectrions등 처럼 util메서드를 제공합니다.)

  1. 배열의 출력 - toString()

2.배열의 복사 - copyOf(), copyOfRange()

int[] arr = {0, 1, 2, 3, 4};
int[] arr2 = Arrays.copyOf(arr, arr.length);	//[0, 1, 2, 3, 4]
int[] arr3 = Arrays.copyOf(arr, 2, 4);	//[2, 3]
  1. 배열 채우기 - fill(), setAll()
int[] arr = new int[5];
Arrays.fill(arr, 9);	//[9, 9, 9, 9, 9]
//람다식을 이용하여 채우기
Arrays.setAll(arr, (i) -> (int)((Math.random()*5)+1)	//[1, 3, 4, 2, 1]
  1. 배열의 정렬과 검색 - sort(), binarySearch()
    binarySearch()는 정렬이 되어 있을때만 위치를 정확히 반환해준다.
int[] arr = {3, 2, 0, 1, 4};
int idx = Arrays.binarySearch(arr, 2);	//-5 -> 잘못된 결과

Arrays.sort(arr);
System.out.println(Arrays.toString(arr));		//[0, 1, 2, 3, 4]
int idx = Arrays.binarySearch(arr, 2);	//2 -> 올바른 결과
  1. 다차원 배열의 출력 - deepToString()
int[] arr2D = {{11, 12}, {21, 22}};
System.out.println(Arrays.deepToString(arr2D));	//[[11, 12], [21, 22]]
  1. 다차원 배열의 비교 - deepEquals()
int[] arr2D1 = {{11, 12}, {21, 22}};
int[] arr2D2 = {{11, 12}, {21, 22}};
System.out.println(Arrays.deepEquals(arr2D1, arr2D2));	//true
  1. 배열을 List로 변환 - asList(Object o)
List list = Arrays.asList(new Integer[]{1, 2, 3, 4, 5}); // list = [1, 2, 3, 4, 5]
List list = Arrays.asList(1, 2, 3, 4, 5); // list = [1, 2, 3, 4, 5]
list.add(6); //UnsupportOperationException발생. 읽기전용이라서

//추가, 삭제등과 같은 메서드를 사용할 경우 아래와 같이 작성
List list = new ArrayList(Arrays.asList(1, 2, 3, 4, 5));
  1. 람다와 스트림 관련 - paralleXXX(), spliterator(), stream()

📖Comparator와 Comparable

객체 정렬에 필요한 메서드(정렬기준 제공)를 정의한 인터페이스
Comparable - 기본 정렬기준을 구현하는데 사용.
Comparator - 기본 정렬기준 외에 다른 기준으로 정렬하고자할 때 사용

public interface Comparator {
	//o1, o2, 두객체를 비교
	int compare(Object o1, Object2);
	//equals를 오버라이딩 하라는 뜻
	boolean equals(Object obj);
}

public interface Comparable {
	//주어진 객체(o)를 자신과 비교
	int compareTo(Object o);
}

compare()와 compareTo()는 두 객체의 비교결과를 반환하도록 구현되어 있습니다.

public final class Integer extends Number implements Comparable {
	public int compareTo(Integer anotherInteger) {
		int v1 = this.value;
		int v2 = anotherInteger.value;
		//같으면 0, 오른쪽 값이 크면 -1, 작으면 1을 반환
		return (v1 < v2 ? -1 : (v1==v2 ? 0 : 1));
	}
	. . .
}

예제)

import java.util.*;


class Ex11_7 {
	public static void main(String[] args) {
		String [] strArr = {"cat", "Dog", "lion", "tiger"};

		Arrays.sort(strArr);
		System.out.println(Arrays.toString(strArr));
		
		//대소문자 구별안함
		Arrays.sort(strArr, String.CASE_INSENSITIVE_ORDER);
		System.out.println(Arrays.toString(strArr));
		
		//역순 정렬
		Arrays.sort(strArr, new Descending());
		System.out.println(Arrays.toString(strArr));

	}
}

class Descending implements Comparator {
	public int compare(Object o1, Object o2) {
		if(o1 instanceof Comparable && o2 instanceof Comparable) {
			
			Comparable c1 = (Comparable)o1;
			Comparable c2 = (Comparable)o2;
			//-1을 곱해서 정렬방식의 역으로 변경한다.
			return c1.compareTo(c2) * -1;
		}
		return -1;
	}
}
결과)
[Dog, cat, lion, tiger]

[cat, Dog, lion, tiger]

[tiger, lion, cat, Dog]

📌정렬 로직

기본적으로 정렬이란 두 대상을 비교해서 자리를 바꾸는 로직을 반복하는 것입니다.
여러가지 정렬방법(버블, 퀵...등등)이 있지만 두대상을 비교하는 방법만 바뀌고 자리를 바꾸는
방식은 동일합니다.

예제)


//버블 정렬
static void sort(int[] intArr) {
	for(int i=0; i<intArr.length-1; i++) {
		for(int j=0; j<intArr.length-1-i; j++) {
			int tmp = 0;
			
			if(intArr[j] > intArr[j+1]) {
				//비교방식이 달라질 뿐 자리를 바꾸는 건 동일
				tmp =intArr[j];
				intArr[j] = intArr[j+1];
				intArr[j+1] = tmp;
			}
		}
	}
}

📖HashSet 순서X, 중복X

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

📌HashSet의 생성자

HashSet()
HashSet(Collection c)
HashSet(int initialCapacity) - 초기 용량 지정
HashSet(int initialCapacity, float loadFactor) - 초기 용량 지정, 언제용량을 늘릴지 지정

📌HashSet의 주요 메서드

boolean add(Object o)
boolean addAll(Collection c) - 합집합
boolean remove(Object o)
boolean removeAll(Collection c) - 차집합
boolean retainAll(Collection c) - 교집합
void clear() - 모두삭제

boolean contains(Object o) - 포함되어 있는지 확인
boolean containsAll(Collection c)
Iterator iterator()

boolean isEmpty() - 비어있는지 확인
int size() - 저장된 객체수
Object[] toArray() - 객체배열로 반환
Object[] toArray(Object[] a)

예제)

import java.util.*;


class Ex11_9 {
	public static void main(String[] args) {
		Object[] objArr = {"1", new Integer(1), "2", "2", "3", "3", "4", "4"};
		Set set = new HashSet();

		for(int i=0; i<objArr.length; i++) {
			set.add(objArr[i]);
		}
		System.out.println(set);
		
		//HashSet에 저장된 요소들을 출력한다.(Iterator이용)
		Iterator it = set.iterator();
		while(it.hasNext()) {
			System.out.println(it.next());
		}
	}
}

결과)
[1, 1, 2, 3, 4]                                                                              1                                                                                            1                                  1
1
2
3
4

결과가 저장한 순서와 일치하지 않을수도 있습니다.(Set의 특징)
만약 정렬하고 싶다면 list로 변환한뒤 Collections의 sort()를 이용해야합니다.

HashSet은 객체를 저장하기전에 기존에 같은 객체가 있는지 확인한 후
같은 객체가 없으면 저장하고, 있으면 저장하지 않습니다.
그래서 boolean add(Object o)는 저장할 객체의 equals()와 hashCode()를 호출하여 확인합니다.
equals()와 hashCode()가 오버라이딩 되어 있어야 add()가 올바르게 작동합니다.

예제)

class Person {
	String name;
	int age;

	Person(String name, int age) {
		this.name = name;
		this.age = age;
	}
	//오버라이딩 메서드들
	public String toString() {
		return name + " : " + age;
	}
	
	public boolean equals(Object obj) {
		if(!(obj instanceof Person)) return false;
		
		Person tmp = (Person) obj;
		return name.equals(tmp.name) && age == tmp.age;
	}

	public int hashCode() {
		//int hash(Object... values) ...은 파라미터가 여러개 수용이 가능한 가변인자라는뜻
		return Object.hash(name, age);
	}

}

메서드 활용 예제)

import java.util.*;



class Ex11_12 {
	public static void main(String[] args) {
		HashSet setA = new HashSet();
		HashSet setB = new HashSet();
		HashSet setHab = new HashSet();
		HashSet setKyo = new HashSet();
		HashSet setCha = new HashSet();

		for(int i=1; i<=5; i++) {
			setA.add(Integer.toString(i));
		}
		for(int i=4; i<=8; i++) {
			setB.add(Integer.toString(i));
		}

		System.out.println(setA + " " +setB);

		//합집합
		setHab.addAll(setA);
		setHab.addAll(setB);
		System.out.println("합집합: " + setHab);
		
		//교집합
		setKyo.addAll(setA);
		setKyo.retainAll(setB);
		System.out.println("교집합: " + setKyo);
		
		//차집합
		setCha.addAll(setA);
		setCha.removeAll(setB);
		System.out.println("차집합: " + setCha);
	}
}

결과)
[1, 2, 3, 4, 5] [4, 5, 6, 7, 8]                                                              
합집합: [1, 2, 3, 4, 5, 6, 7, 8]                                                             
교집합: [4, 5]                                                                               
차집합: [1, 2, 3] 

📖TreeSet

이진 탐색 트리(binary search tree)로 구현, 범위탐색과 정렬에 유리합니다.
이진 트리는 모든 노드가 최대 2개의 하위 노드를 갖습니다.
각 요소(node)가 나무(tree)형태로 연결되어있습니다.(LinkedList의 변형)

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

부모보다 작은 값은 왼쪽, 큰 값은 오른쪽에 저장합니다.
데이터가 많아질 수록 추가, 삭제에 시간이 더걸립니다.

📌 TreeSet의 생성자

TreeSet()
TreeSet(Collection c) - 주어진 컬렌션을 저장하는 TreeSet을 생성
TreeSet(Comparator comp) - 주어진 정렬 기준으로 정렬하는 TreeSet을 생성

📌 TreeSet의 메서드

(add(), size(), remove()등과 같은 collection의 메서드들은 제외)

메서드설명
Object first()정렬된 순서에서 첫 번째 객체를 반환한다.
Obejct last()정렬된 순서에서 마지막 객체를 반환한다.
Object ceiling(Object o)지정된 객체와 같은 객체를 반환, 없으면 큰 값을 가진 객체 중 제일 가까운 객체를 반환
Object floor(Obejct o)지정된 객체와 같은 객체를 반환, 없으면 작은 값을 가진 객체 중 제일 가까운 객체를 반환
Object higher(Object o)지정된 객체보다 큰 값을 가진 객체중 제일 가까운 값의 객체를 반환
Object lower(Object o)지정된 객체보다 작은 값을 가진 객체중 제일 가까운 값의 객체를 반환
SortedSort subSet(Object fromElement, Object toElement)범위 검색(fromElement와 toElement사이)의 결과를 반환한다.
SortedSet headSet(Object toElement)지정된 객체보다 작은 값의 객체들을 반환한다.
SortedSet tailSet(Object fromElement)지정된 객체보다 큰 값의 객체들을 반환한다.

예제)

import java.util.*;


class Ex11_13 {
	public static void main(String[] args) {
		Set set = new TreeSet();	//정렬이 필요가 없음

		for (int i=0; set.size()<6; i++) {
			int num = (int)(Math.random() * 45) + 1;
			set.add(num);	// set.add(new Integer(num);
		}

		System.out.println(set);
	}
}

//만약 사용자 정의 클래스를 넣고 싶다면 비교기준을 구현해야합니다.
class Test implements Comparable {
	public int compareTo(Object o) {
		return -1;
	}
}

class TestComp implements Comparator {
	public int compare(Object o1, Object o2) {
		return 1;
	}
}

메서드 예제)

import java.util.*;



class Ex11_15 {
        public static void main(String[] args) {
                TreeSet set = new TreeSet();
                int[] score = {80, 95, 50, 35, 45, 65, 10, 100};

                for(int i=0; i<score.length; i++) {
                        set.add(new Integer(score[i]));
                }

                System.out.println("50보다 작은 값: " + set.headSet(50));
                System.out.println("50보다 큰 값: " + set.tailSet(50));
                System.out.println("40과 80사이의 값: " + set.subSet(40, 80));

        }
}

결과)
50보다 작은 값: [10, 35, 45]
50보다 큰 값: [50, 65, 80, 95, 100]
4080사이의 값: [45, 50, 65]

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

Map인터페이스로 구현, 데이터를 키와 값의 쌍으로 저장합니다.
HashMap(동기화X)은 Hashtable(동기화O)의 신버젼
만약 순서를 유지하려면, LinkedHashMap클래스를 사용하면 됩니다.

📌HashMap의 키(key)와 값(value)

해싱(hashing)기법으로 데이터를 저장하고 데이터가 많아도 검색이 빠릅니다.

public class HashMap extends AbstractMap
	implements Map, Cloneable, Serializable {
	//Entry는 key와 value의 묶음입니다.
	transient Entry[] table;

	. . .
	static class Entry implements Map.Entry {
		final Object key;
		Object value;
		. . .
	}
}

hashing은 해쉬함수를 이용해서 해시테이블에 데이터를 저장하고 읽어오는 것을 의미합니다.
예를 들어 어떤 키값(주민번호)를 해시함수에 넣으면 해시코드(저장위치)를 반환해주고 그걸 이용하여 해시코드와 동일한 배열의 인덱스 찾아서 링크드 리스트에서 데이터를 찾아내면 됩니다.
해시테이블은 배열의 장점(빠른 검색)과 링크드리스트의 장점(변경이 용이)이 조합된 형태입니다.
각배열의 인덱스안에 링크드리스트가 구현되어 있습니다.

해시함수는 같은 키에 대해 항상 같은 해시코드를 반환해야 합니다.
서로 다른 키일지라도 같은 값의 해시코드를 반환할 수도 있습니다.(주민번호: 72, 74, 78...)

📌 HashMap의 생성자

HashMap()
HashMap(int initialCapacity) - 배열의 초기용량을 지정
HashMap(int initialCapacity, float loadFactor)
HashMap(Map m) - 다른 맵을 HashMap으로 변경

📌 HashMap의 메서드

Object put(Object key, Object value) - 1개의 entry저장
void putAll(Map m) - 여러개의 entry를 map으로 묶어서 저장
Object remove(Object key) - 삭제
Object replace(Object key, Object value) - 변경
boolean replace(Object key, Object oldValue, Object newValue)

Set entrySet() - entry로 읽어오기
Set keySet() - key값만 읽어오기
Collection values() - 순수 값으로만 읽어오기

Object get(Object key)
Object getOrDefault(Object key, Object defaultValue)
boolean containsKey(Object key)
boolean containsValue(Object value)

int size()
boolean isEmpty()
void clear()
Object clone()

예제)

import java.util.*;



class Ex11_16 {
	public static void main(String[] args) {
		HashMap map = new HashMap();
		map.put("myId", "1234");
		map.put("asdf", "1111");
		map.put("asdf", "1234");

		Scanner s = new Scanner(System.in);

		while(true) {
			System.out.println("id와 password를 입력해주세요.");
			System.out.print("id :");
			String id = s.nextLine().trim();

			System.out.print("password :");
			String password = s.nextLine().trim();
			System.out.println();

			if(!map.containsKey(id)) {
				System.out.println("입력하신 id는 존재하지 않습니다.");
				continue;
			}

			if(!(map.get(id)).equals(password)) {
				System.out.println("비밀번호가 일치하지 않습니다.");
				continue;
			} else {
				System.out.println("id 와 비밀번호가 일치합니다. ");
				break;
			}

			
		}
		
	}
}


결과)
id와 password를 입력해주세요.
id :asdf
password :1111

비밀번호가 일치하지 않습니다.   
id와 password를 입력해주세요.
id :asdf
password :1234

id 와 비밀번호가 일치합니다.   

메서드 예제)

import java.util.*;



class Ex11_17 {
	public static void main(String[] args) {
		HashMap map = new HashMap();
		map.put("김자바", new Integer(90));
		map.put("김자바", new Integer(100));
		map.put("이자바", new Integer(100));
		map.put("강자바", new Integer(80));
		map.put("안자바", new Integer(90));
		
		//entry로 가져오기
		Set set = map.entrySet();
		Iterator it = set.iterator();

		while(it.hasNext()) {
			Map.Entry e = (Map.Entry)it.next();
			System.out.println("이름: " + e.getKey() + ", 점수: " + e.getValue());
		}

		//key만 가져오기
		set = map.keySet();
		System.out.println("참가자 명단: " + set);
		
		//value만 가져오기
		Collection values = map.values();
		it = values.iterator();

		int total = 0;

		while(it.hasNext()) {
			Integer i = (Integer)it.next();
			total +=i.intValue();
		}

		System.out.println("총점: " + total);
		System.out.println("평균: " + (float)total/set.size());
		System.out.println("최고점수: " + Collections.max(values));
		System.out.println("최저점수: " + Collections.min(values));

	}
}

결과)
이름: 안자바, 점수: 90
이름: 김자바, 점수: 100
이름: 강자바, 점수: 80
이름: 이자바, 점수: 100
참가자 명단: [안자바, 김자바, 강자바, 이자바]
총점: 370
평균: 92.5
최고점수: 100
최저점수: 80

📌

📖Collections

컬렉션을 위한 메서드(static)를 제공합니다.

1.컬렉션 채우기, 복사, 정렬, 검색 - fill(), copy(), sort(), binarySearch()등
2. 컬렉션 동기화 - synchronizedXXX()
static Collection synchronizedCollection(Collection c)
static List synchronizedList(List list)
static Set synchronizedSet(Set s)
static Map synchronizedMap(Map m)
static SortedSet synchronizedSortedSet(SortedSet s)
static SortedMap synchronizedSortedMap(SortedMap m)

//vector는 동기화, ArrayList는 비동기화되어 있습니다.
List syncList = Collections.synchronizedList(new ArrayList());

  1. 변경불가(readOnly) - unmodifiableXXX()
    static Collection unmodifiableCollection(Collection c)
    static List unmodifiableList(List list)
    static Set unmodifiableSet(Set s)
    static Map unmodifiableMap(Map m)
    static SortedSet unmodifiableSortedSet(SortedSet s)
    static SortedMap unmodifiableSortedMap(SortedMap m)
    static NavigableSet unmodifiableNavigableSet(NavigableSet s)
    static NavigableMap unmodifiableNavigableMap(NavigableMap m)

  2. 싱글톤 컬렉션 만들기 - singletonXXX()
    객체를 1개만 저장하는 컬렉션을 만들때사용
    static List singletonList(Object o)
    static Set singleton(Object o)
    static Map singletonMap(Object key, Object value)

  3. 한 종류의 객체만 저장하는 컬렉션 만들기 - checkedXXX()
    static Collection checkedCollection(Collection c)
    static List checkedList(List list, Class type)
    static Set checkedSet(Set s, Class type)
    static Map checkedMap(Map m, Class type)
    static SortedSet checkedSortedSet(SortedSet s, Class type)
    static SortedMap checkedSortedMap(SortedMap m, Class type)
    static NavigableSet checkedNavigableSet(NavigableSet s, Class type)
    static NavigableMap checkedNavigableMap(NavigableMap m, Class type)

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

📖컬렉션 클래스 정리 & 요약

profile
초보개발 블로그입니다~

0개의 댓글