컬렉션(Collection)

- 여러 개의 다양한 데이터들을 쉽고 효과적으로 처리할 수 있도록 표준화 된 방법을 제공하는 클래스들의 집합

(데이터를 효율적으로 저장하는 자료구조와 데이터를 처리하는 알고리즘이 미리 구현되어 있음)

- Java.util 패키지에 포함

 

자료구조

- 데이터(자료)를 메모리에서 효율적으로 저장하기 위한 방법론

 

컬렉션의 주요 인터페이스

인터페이스 분류 특징 구현 클래스
Collection List 계열 순서를 유지하고 저장
중복 저장 가능
ArrayList, Vector, LinkedList
Set 계열 순서를 유지하지 않고 저장
중복 저장 안됨
HashSet, LinkedHashSet, TreeSet
Map 계열 키와 값의 쌍으로 저장
키는 중복 저장 안됨
HashMap, HashTable, TreeMap, Properties

List

- 자료들을 순차적으로 나열한 자료구조로 인덱스로 관리되며, 중복해서 인스턴스 저장이 가능

- List 계열의 주요 메소드

 

- toString 메소드가 오버라이딩 되어 있으며 저장 순번이 유지된다.

 

- 일부 예시

- size - 일부 예시메소드는 배열의 크기가 아닌 요소의 갯수를 반환한다.

내부적으로 관리되는 배열의 사이즈는 외부에서 알 필요가 없으므로 기능을 제공하지 않는다.

- 내부 배열에 인덱스가 지정 되어 있기 때문에 for문으로 접근 가능하며, 인덱스에 해당하는 요소를 가져올 때는 get 메소드를 사용한다.

for(int i = 0; i < alist.size(); i++) {
			
			System.out.println(i + " : " + alist.get(i));
		}

 

- ArrayList

  • 가장 많이 사용되는 컬렉션 클래스
  • 내부적으로 배열을 이용하여 요소를 관리하며, 인덱스를 이용해 배열 요소에 접근 가능
List<E> list = new ArrayList<E>();

 

- 인스턴스 생성 시 내부적으로 10칸짜리 배열을 생성해서 관리한다.

- 다형성을 적용하여 상위 레퍼런스로 ArrayList 객체를 참조할 수 있다.

  -> List 인터페이스 하위의 다양한 구현체들로 타입 변경이 가능하기 때문에 레퍼런스 타입은 List로 해두는 것이 더 유연한 코드를 작성하는 것

- 더 상위 타입인 Collection 타입을 이용할 수도 있다.

Collection clist = new ArrayList();
  • 배열과의 차이
배열 ArrayList
한번 크기를 지정하면 변경할 수 없음
(저장할 공간의 크기가 부족 시 에러 발생 -> 할당 시 넉넉한 크기로 할당 -> 메모리 낭비)
저장하는 크기의 제약이 없음
배열에 기록된 데이터에 대한 중간 위치의 추가, 삭제가 불편 (추가, 삭제 할 데이터부터 마지막 기록된 데이터까지 하나씩 뒤로 밀어내고 추가 -> 복잡한 알고리즘) 추가, 삭제, 정렬 등의 기능 처리가 간단하게 해결
(자료구조가 내장되어 있어 따로 복잡한 알고리즘 불필요)
한 타입의 데이터만 저장 가능 여러 타입의 데이터가 저장 가능
(다만 인스턴스만 저장할 수 있기 때문에 기본 자료형을 저장해야 할 경우 Wrapper 클래스 사용)

 

- 모든 컬렉션 프레임워크 클래스는 제네릭 클래스로 작성 되어 있다. -> 제네릭을 사용하여 선언하는 것이 보편적인 사용법

List<String> stringList = new ArrayList<>();
		stringList.add("banana");
		stringList.add("orange");
		stringList.add("mango");
		stringList.add("grape");
		/* 제네릭 타입을 지정하면 지정한 타입 외의 인스턴스는 저장하지 못한다. */
//		stringList.add(123);

- sort : 오름차순 정렬, list가 정렬 된 뒤 해당 상태가 유지 된다.

/* 저장 순서를 유지하고 있는 stringList를 오름차순 정렬한다. */
		Collections.sort(stringList);

->ArrayList에는 역순 정렬 기능이 제공 되지 않고 LinkedList에는 정의되어 있다. 

 

- LinkedList

  • 인접 참조를 링크해서 체인처럼 관리
  •  특정 인덱스에서 인스턴스를 제거하거나 추가하게 되면 바로 앞/뒤 링크만 변경하면 되기 때문에 인스터스 삭제와 삽입이 빈번하게 일어나는 곳에서는 ArrayList보다 성능이 뛰어남.
  • 대신 참조되어 있기 때문에 특정 값을 찾아가기엔 시간이 걸릴 수 있으므로,  값들을 저장해놓고 조회하는 용도로 사용할 경우에는 연속되어 저장되어 있는 ArrayList가 유용함

 

현재의 ArrayList를 LinkedList로 변경해본다.

stringList = new LinkedList<>(stringList);

 

- Iterator : Collection 인터페이스의 iterator() 메소드를 이용해서 생성하는 인스턴스

반복자라고 불리우며 반복문을 이용해서 목록을 하나씩 꺼내는 방식으로 사용하기 위함이다.

인덱스로 관리 되는 컬렉션이 아닌 경우 반복문을 사용해서 요소에 하나씩 접근할 수 없으므로  인덱스를 사용하지 않고 반복문을 사용하기 위한 목록을 만들어주는 역할을 한다.

iterator는 한 번 꺼내면 다시 쓸 수 없다. (hasNext가 false로 반환되기 때문)

Iterator<String> iter = stringList.iterator();
		while(iter.hasNext()) {	// 다음 요소를 가지고 있는 경우 true, 더 이상 요소가 없는 경우 false 반환
			System.out.println(iter.next()); //다음 요소를 반환
		}

인덱스에 커서가 있다고 생각하고 그 다음에 값이 있는지

 

- descendingIterator : 역순으로 된 이더레이터

Iterator<String> dIter = ((LinkedList<String>)stringList).descendingIterator(); //LinkedList로 다운캐스팅
		while(dIter.hasNext()) {
			System.out.println(dIter.next());

 

 

- Comparable과 Comparator

  Comparable Comparator
패키지 java.lang java.util
사용 메소드 compareTo() compare()
정렬 기존의 정렬기준을 구현하는데 사용 그 외 다른 여러 기준으로 정렬하고자 할 때 사용
사용법 정렬하고자 하는 인스턴스에 Comparable를 상속받아 compareTo() 메소드를 오버라이딩해 기존의 정렬 기준 재정의 → 한 개의 정렬만 가능 vo 패키지 안에 필요한 정렬 기준에 맞춘 클래스들을 생성하고 Comparator를 상속받아 compare() 메소드를 오버라이딩해 기존의 정렬 기준 재정의 → 별도 클래스에 여러 개의 정렬 기준 작성

 

<Comparator>

/* 가격 오름차순이라는 정렬 기준을 작성하는 용도의 클래스 */
public class AscendingPrice implements Comparator<BookDTO> {

	/* Comparator 인터페이스를 상속 받으면 오버라이딩 해야 하는 메소드가 강제화 된다. - compare 메소드
	 * 제네릭 작성 시 Object가 아닌 구체화 된 타입으로 매개변수가 선언 되어 다운 캐스팅할 필요가 없어진다.
	 * */
	@Override
	public int compare(BookDTO o1, BookDTO o2) {
		
		/* sort()에서 내부적으로 사용 되는 메소드이다.
		 * 비교 대상 두 인스턴스의 가격이 오름차순 정렬이 되기 위해서는 앞의 가격이 더 작은 가격이어야 하고
		 * 만약 뒤의 가격이 더 작은 경우 두 인스턴스의 순서를 바꿔야 한다.
		 * 그 때 두 값을 바꾸라는 신호로 양수를 보내주게 되면 정렬 시 순서를 바꾸는 조건으로 사용된다.
		 * */
		
		int result = 0;
		
		if(o1.getPrice() > o2.getPrice()) {
			/* 오름차순을 위해 순서를 바꿔야 하는 경우 양수 반환 */
			result = 1;
		} else if(o1.getPrice() < o2.getPrice()) {
			/* 이미 오름차순으로 정렬 되어 있는 경우 음수 반환 */
			result = -1;
		} else {
			/* 두 값이 같은 경우 0을 반환 */
			result = 0;
		}
		
		return result;
	}

 

가격 순으로 오름차순 정렬 - AscendingPrice 클래스 추가 

public class Application2 {

	public static void main(String[] args) {
    
    	List<BookDTO> bookList = new ArrayList<>();
    	 ... 생략...
     
     
		Collections.sort(bookList, new AscendingPrice());

 

- 익명클래스 사용

인터페이스를 구현할 클래스를 재사용하는 경우 AscendingPrice 클래스처럼 작성하면 되지만, 한 번만 사용하고 더 이상 재사용할 일이 없을 경우에는 조금 더 간편한 방법을 이용할 수 있다.

익명 클래스(Anonymous)를 이용한 방법이다. 익명클래스는 뒤에 {}를 만들어서 Comparator 인터페이스를 상속 받은 클래스인데 이름이 없다고 생각하고 사용하는 것이다.

		Collections.sort(bookList, new Comparator<BookDTO> () {

			@Override
			public int compare(BookDTO o1, BookDTO o2) {
				/* 가격 내림차순 기준 작성 
				 * 가격 오름차순과는 반대로 뒤에 있는 값인 o2의 price가 더 클 경우 양수를 반환하여 순서를 바꾸게 한다. */
				return o2.getPrice() - o1.getPrice();
			}
			
		});

 

<Comparable>

public class BookDTO implements Comparable<BookDTO> {
...생략


@Override
	public int compareTo(BookDTO o) {
		// this와 비교 대상 객체 BookDTO o를 비교하여 number 오름차순 정렬
		return number - o.number;
	}

	
}

 

- BookDTO implements Comparable<BookDTO> 를 작성하고나면 sort 메소드 호출을 할 수 있다.

 -> 내부적인 정렬 기준이 정의됨.

Collections.sort(bookList);

 


Stack

- Stack은 리스트 계열의 클래스 Vector 클래스를 상속 받아 구현하였다.

- 스택 메모리 구조는 선형 메모리 공간에 데이터를 저장하며 후입 선출(LIFO - Last In First Out) 방식의 자료구조라 부른다.

리턴 타입 메소드 설명
E push(E item) 주어진 인스턴스를 스택에 넣는다
E peek() 스택의 맨 위 인스턴스를 가져온다. 인스턴스를 스택에서 제거하지 않는다.
E pop() 스택의 맨 위의 인스턴스를 가져온다. 인스턴스를 스택에서 제거한다.

 

/* Stack 인스턴스 생성 */
		Stack<Integer> integerStack = new Stack<>();
		
		/* stack에 값을 넣을 때는 push() 메소드를 사용한다.
		 * add()도 사용 가능하지만 Stack의 기능이므로 push()를 사용하는 것이 좋다. 
		 * */
		integerStack.push(1);
		integerStack.push(2);
		integerStack.push(3);
		integerStack.push(4);
		integerStack.push(5);
		
		System.out.println(integerStack);  //[1, 2, 3, 4, 5]
		
		/* 스택에서 요소를 찾을 때 search()를 이용할 수 있다. 
		 * 인덱스가 아닌 위에서부터의 순번을 의미하며 가장 상단의 위치가 0이 아닌 1부터 시작한다. */
		System.out.println(integerStack.search(5));  //1
		System.out.println(integerStack.search(1));  //5
		
		/* 스택에서 값을 꺼내는 메소드는 크게 2가지로 볼 수 있다.
		 * peek() : 해당 스택의 가장 마지막에(상단에 있는) 요소 반환
		 * pop() : 해당 스택의 가장 마지막에(상단에 있는) 요소 반환 후 제거 
		 * */
		
		System.out.println("peek() : " + integerStack.peek());  //5
		System.out.println(integerStack);                       //[1, 2, 3, 4, 5]
	
		System.out.println("pop() : " + integerStack.pop());   //5
		System.out.println(integerStack);                      //[1, 2, 3, 4]
		
		/* pop()은 꺼내면서 요소를 제거하기 때문에 스택이 비어있는 경우 에러가 발생할 수 있다. */
		System.out.println("pop() : " + integerStack.pop());   //4
		System.out.println("pop() : " + integerStack.pop());   //3
		System.out.println("pop() : " + integerStack.pop());   //2
		System.out.println("pop() : " + integerStack.pop());   //1
		System.out.println("pop() : " + integerStack.pop()); //java.util.EmptyStackException 발생

 

Queue

- Queue는 선형 메모리 공간에 데이터를 저장하는 선입 선출(FIFO - First Input First Out) 방식의 자료구조이다.

- Queue 인터페이스를 상속 받는 하위 인터페이스들은 Deque, BlockingQueue, TransferQueue 등 다양하지만  대부분의 큐는 LinkedList를 구현체로서 이용한다.

리턴 타입 메소드 설명
Boolean offer(E e) 주어진 인스턴스를 넣는다
E peek() 인스턴스를 하나 가져온다. 인스턴스를 큐에서 제거하지 않는다
E Poll() 인스턴스를 하나 가져온다. 인스턴스를 큐에서 제거한다.
/* Queue 자체로는 인터페이스이기 때문에 인스턴스 생성이 불가능하다. */
//		Queue<String> que = new Queue<>();
		
		/* LinkedList로 인스턴스 생성 */
		Queue<String> que = new LinkedList<>();
		
		/* 큐에 데이터를 넣을 때에는 offer()를 사용한다. */
		que.offer("first");
		que.offer("second");
		que.offer("third");
		que.offer("fourth");
		que.offer("fifth");
		
		System.out.println(que);  //[first, second, third, fourth, fifth]
		
		/* 큐에서 데이터를 꺼낼 때는 2가지 메소드가 있다.
		 * peek() : 해당 큐의 가장 앞에 있는 요소(먼저 들어온 요소)를 반환
		 * poll() : 해당 큐의 가장 앞에 있는 요소(먼저 들어온 요소)를 반환하고 제거 
		 * */
		
		System.out.println("peek() : " + que.peek()); //first
		System.out.println(que);				//[first, second, third, fourth, fifth]
		
		System.out.println("poll() : " + que.poll()); //first
		System.out.println(que);                 //[second, third, fourth, fifth]
		
		System.out.println("poll() : " + que.poll());  //second
		System.out.println("poll() : " + que.poll());  //third
		System.out.println("poll() : " + que.poll());  //fourth
		System.out.println("poll() : " + que.poll());  //fifth
		System.out.println("poll() : " + que.poll()); //반환 값이 없을 경우 null로 반환

 


SET

1. 요소의 저장 순서를 유지하지 않는다.

2. 같은 요소의 중복 저장을 허용하지 않는다. (null 값도 중복 되지 않아 하나의 null만 저장한다.

 

HashSet

Set 컬렉션 클래스에서 가장 많이 사용 되는 클래스 중 하나이다.

JDK 1.2부터 제공되고 있으며 해시 알고리즘을 사용하여 검색 속도가 빠르다는 장점을 가진다.

동일 인스턴스 뿐 아니라 동등 인스턴스도 중복하여 저장하지 않음

- 동일 : 완전히 같은 인스턴스

- 동등 : 다른 인스턴스이지만 특정한 기준들의 속성 값이 같음

/* HashSet 인스턴스 생성 */
		Set<String> hset = new HashSet<>();
		
		hset.add(new String("java"));
		hset.add(new String("oracle"));
		hset.add(new String("jdbc"));
		hset.add(new String("html"));
		hset.add(new String("css"));
		
		/* 저장 순서가 유지 되지 않는다. */
		System.out.println(hset); //[css, java, oracle, jdbc, html]
		
		/* 값이 같은 동등 객체를 저장하고자 했을 때 중복 저장 되지 않는다. */
		hset.add(new String("java"));
		System.out.println(hset); //[css, java, oracle, jdbc, html]
		
		/* 값이 같은 동등 객체를 이용해 포함 여부 확인이 가능하다. */
		System.out.println("포함 여부 확인 : " + hset.contains(new String("oracle")));
        //포함 여부 확인 : true

 

저장 된 객체를 하나씩 꺼내는 기능이 따로 없다. 반복문(인덱스) 사용이 불가

방법1.toArray()로 배열로 변경한 뒤 for loop 사용

	Object[] arr = hset.toArray();
		for(int i = 0; i < arr.length; i++) {
			System.out.println(i + " : " + arr[i]);
		}

 

 방법2.iterator()로 목록 만들어 연속 처리

	Iterator<String> iter = hset.iterator();
		
		while(iter.hasNext()) {
			System.out.println(iter.next());
		}

 

방법3.향상 된 for문 사용

for(String str : hset) {
			System.out.println("str : " + str);
		}

 

 

 

LinkedHashSet

HashSet이 가지고 있는 기능을 모두 가지고 있고 추가적으로 저장 순서를 유지하는 특징을 가지고 있다.

*JDK 1.4부터 제공하고 있다.

 

TreeSet

* 데이터가 정렬 된 상태로 저장 되는 이진 검색 트리의 형태로 요소를 저장한다.

* 이진 검색 트리는 데이터를 추가하거나 삭제하는 등의 기본 동작 시간이 매우 빠르다.

* JDK 1.2부터 제공 되고 있으며 Set 인터페이스가 가지는 특징을 그대로 가지지만 정렬 된 상태를 유지한다는 점이 다른 점이다. (오름차순 정렬)


 

Map 

- Collection 인터페이스와는 다른 저장 방식을 가진다. ->  key, value를 하나의 쌍으로 저장하는 방식을 사용한다.

- key란? value를 찾기 위한 이름 역할을 하는 객체를 의미한다.

Map 인터페이스의 특징

1. 요소의 저장 순서를 유지하지 않는다.

2. 키는 중복 허용하지 않지만, 키가 다르면 중복 값은 저장 가능하다.

* HashMap, HashTable, TreeMap 등의 대표적인 클래스가 있다.

 

       /* HashMap 인스턴스 생성 */
		Map hmap = new HashMap();
		
		/* 키, 값 쌍으로 저장한다. 둘 다 반드시 객체여야 한다. 기본 자료형은 오토 박싱 되어 Wrapper 클래스로 저장되고 있다. */
		hmap.put("one", new Date());
		hmap.put(12, "red apple");
		hmap.put(33, 123);
		
		/* 저장 순서를 유지하지 않는다. */
		System.out.println("hmap : " + hmap);
        //hmap : {33=123, one=Mon Feb 27 20:55:13 KST 2023, 12=red apple}
		
		/* 키는 중복 저장 되지 않으며 value 값만 덮어쓰기 된다. */
		hmap.put(12, "yellow banana");
		System.out.println("hmap : " + hmap);
        //hmap : {33=123, one=Mon Feb 27 20:55:13 KST 2023, 12=yellow banana}

		/* 키가 다르면 값 객체 저장은 중복으로 가능하다. */
		hmap.put(11, "yellow banana");
		System.out.println("hmap : " + hmap);
        //hmap : {33=123, one=Mon Feb 27 20:55:13 KST 2023, 11=yellow banana, 12=yellow banana}
		
		/* 값 객체의 내용을 가져올 때 */
		System.out.println("키 11에 대한 객체 : " + hmap.get(11));
        //키 11에 대한 객체 : yellow banana
		
		/* 키 값을 가지고 삭제할 때 */
		hmap.remove(11);
		System.out.println("hmap : " + hmap);
        //hmap : {33=123, one=Mon Feb 27 20:55:13 KST 2023, 12=yellow banana}
		
		/* 저장 된 객체 수를 확인할 때 */
		System.out.println("hmap 저장 된 객체 수 : " + hmap.size());
        //hmap 저장 된 객체 수 : 3

 

- 제네릭 설정한 HashMap

 

		 // Map의 key 타입은 가장 보편적으로 String 타입을 사용한다. */
		Map<String, String> hmap2 = new HashMap<>();
		
		hmap2.put("one", "java");
		hmap2.put("two", "oracle");
		hmap2.put("three", "jdbc");
		hmap2.put("four", "html");
		hmap2.put("five", "css");
		
		System.out.println(hmap2);


//출력
four = html
one = java
two = oracle
three = jdbc
five = css

 

1. keySet()을 이용해서 키만 따로 Set으로 만들고, iterator로 키에 대한 목록을 만든다. or 향상 된 for문을 사용한다.

Set<String> keys = hmap2.keySet();
		
		/* iterator */
		Iterator<String> keyIter = keys.iterator();
		while(keyIter.hasNext()) {
			String key = keyIter.next();
			String value = hmap2.get(key);
			System.out.println(key + " = " + value);
		}
		
		/* 향상 된 for문 */
		for(String key : keys) {
			String value = hmap2.get(key);
			System.out.println(key + " = " + value);
		}

 

2. entrySet()을 이용해서 Entry를 Set으로 만들고 iterator로 Entry에 대한 목록을 만든다. or 향상 된 for문을 사용한다

Set<Entry<String, String>> set = hmap2.entrySet();
		
		/* iterator */
		Iterator<Entry<String, String>> entryIter = set.iterator();
		while(entryIter.hasNext()) {
			Entry<String, String> entry = entryIter.next();
			System.out.println(entry.getKey() + " = " + entry.getValue());
		}
		
		/* 향상 된 for문 */
		for(Entry<String, String> entry : set) {
			System.out.println(entry.getKey() + " = " + entry.getValue());
		}

 

3. 저장 된 value 객체들만 values로 Collection으로 만든다.

		Collection<String> values = hmap2.values();
		
		Iterator<String> valueIter = values.iterator();
		while(valueIter.hasNext()) {
			System.out.println(valueIter.next());
		}
        
        
//출력
html
java
oracle
jdbc
css

Properties

 

키와 값을 String 타입으로 제한한 Map 컬렉션

설정 파일(프로퍼티)의 값을 읽어서 어플리케이션에 적용할 때 사용한다

 

        Properties prop = new Properties();
		
		prop.setProperty("driver", "oracle.jdbc.driver.OracleDriver");
		prop.setProperty("url", "jdbc:oracle:thin:@127.0.0.1:1521:xe");
		prop.setProperty("user", "student");
		prop.setProperty("password", "student");

 

	try {
			prop.store(new FileOutputStream("driver.dat"), "jdbc driver");
			prop.store(new FileWriter("driver.txt"), "jdbc driver");
			prop.storeToXML(new FileOutputStream("driver.xml"), "jdbc driver");
		} catch (IOException e) {
			e.printStackTrace();
		}

 

 

- 파일로부터 읽어와서 Properties에 기록한다

		Properties prop2 = new Properties();
		
		try {
			//prop2.load(new FileInputStream("driver.dat"));
			//prop2.load(new FileReader("driver.txt"));
			prop2.loadFromXML(new FileInputStream("driver.xml"));
			
			/* Properties의 모든 키 값 목록을 대상 스트림에 내보내기 한다. */
			prop2.list(System.out);
            
//출력
-- listing properties --
password=student
driver=oracle.jdbc.driver.OracleDriver
user=student
url=jdbc:oracle:thin:@127.0.0.1:1521:xe
            
			
			System.out.println(prop2.getProperty("driver"));
			System.out.println(prop2.getProperty("url"));
			System.out.println(prop2.getProperty("user"));
			System.out.println(prop2.getProperty("password"));
			
		} catch (IOException e) {
			e.printStackTrace();
		}
        
//출력
oracle.jdbc.driver.OracleDriver
jdbc:oracle:thin:@127.0.0.1:1521:xe
student
student

'LECTURE > JAVA' 카테고리의 다른 글

11.제네릭  (0) 2023.01.06
08.상속  (0) 2023.01.06
07. 객체 배열  (0) 2023.01.06
06.클래스와 객체  (0) 2023.01.06
05.배열  (0) 2023.01.06

+ Recent posts