위로
아래
콜렉션 프레임워크
콜렉션 (collerction) 프레임워크
- 배열의 한계를 극복하면서, 일반적인 자료구조(data structure)도 쉽게 이용할 수 있도록 다양한 클래스와 인터페이스를 정의한 프레임워크.
- 콜렉션 : 데이터를 한 곳에 모아 편리하게 저장 및 관리하는 가변 크기의 객체 컨테이너.
- 콜렉션 프레임워크 : 객체를 한 곳에 모아 효율적으로 관리하고 편리하게 사용할 수 있도록 제공하는 환경.
특징
- 많은 데이터 요소를 효율적으로 관리하기 위한 자료 구조
- 콜렉션은 제네릭(generics) 형식으로 구현되어 있다.
- 콜렉션 클래스가 데이터를 다룰 때, 데이터는 기본적으로 객체만 가능 (기본형 사용 불가. 대신 포장 클래스 이용해야 한다)
- 콜렉션 인터페이스는 java.util에 포함되어 있다.
- 콜렉션 프레임워크는 인터페이스와 구현 클래스들로 구성되어 있다. (밑에 표 외에도 Iterator, Enumeration 인터페이스도 포함된다)
종류
- List : 이름과 같이 목록처럼 데이터 순서에 따라 관리
- Set : 중복이 허용되지 않는 데이터를 관리
- Map : 데이터를 Key와 Value로 짝을 이루어 관리하며, Key값은 중복을 허용 X
- Queue : 데이터를 FIFO 방식으로 관리
- Stack : 데이터를 LIFO 방식으로 관리
- ArrayList, LinkedList, Vector, Stack, HashSet, TreeSet, HashMap, TreeMap 등
인터페이스 | 특징 | 구현 클래스 | |
Collection | List | 객체의 순서가 있고, 중복될 수 있다. | ArrayList, Stack, Vector, LinkedList |
Queue | 입력한 순서대로 저장되며, 객체가 중복될 수 있다. | DelayQueue, PriorityQueue, LinkedList | |
Set | 순서가 없으며, 객체가 중복될 수 없다. | HashSet, TreeSet, EnumSet | |
Map | 키-값이 쌍으로 저장되며, 키는 중복될 수 없다. | HashMap, Hashtable, TreeMap, Properties |
Collections 클래스
- Collection을 다루기 위한 클래스
- java.util 패키지에 들어 있다.
- Collection 인터페이스와는 다른 것.
- 콜렉션 원소 정렬, 원소 돌리기, 원소 섞기, 원소 탐색을 쉽게 해결할 수 있다.
원소 정렬
- 매개변수가 제네릭 타입<>이지만 편의상 생략한다
- sort(), reverse(), reverseOrder() 메소드 제공
import java.util.*;
public class SortDemo {
public static void main(String[] args) {
String[] fruits = {"포도","수박","사과","키위","망고"};
List<String> list = Arrays.asList(fruits);
Collections.sort(list,Collections.reverseOrder());
System.out.println(list);
Collections.reverse(list);
System.out.println(list);
}
}
원소 돌리기, 섞기
- 원소 돌리기 : 명시된 거리만큼 원소를 돌려 나열
- 섞기 : 원소를 무작위로 나열
- rotate() 메소드 : 돌리기
- shuffle()메소드 : 섞기
import java.util.*;
public class ShuffleDemo {
public static void main(String[] args) {
List<Character> list = new ArrayList<>();
for(char c='A' ; c <= 'G' ; c++) {
list.add(c);
}
System.out.println("최초 리스트 : \t" + list);
Collections.rotate(list, 3);
System.out.println("돌린 리스트 : \t" + list);
Collections.shuffle(list);
System.out.println("섞은 리스트 : \t" + list);
}
}
원소 탐색
- 조건을 만족하는 원소 찾기
- 정렬된 리스트라면, binarySearch() 메소드를 이용해 원하는 원소를 찾을 수 있다
- 인덱스 값이 반환된다
import java.util.*;
public class SearchDemo {
public static void main(String[] args) {
String[] s = {"황금을","돌","같이","보라"};
List<String> list = Arrays.asList(s);
Collections.sort(list); // 탐색 전에는 정렬이 먼저 되어 있어야 한다
System.out.println(list);
System.out.println(Collections.binarySearch(list, "보라")); // 인덱스 번호를 반환
}
}
Collections 클래스의 여러 메소드들
- addAll() : 명시된 원소들을 컬렉션에 삽입
- copy() : 리스트를 다른 리스트로 복사
- disjoint() : 2개의 컬렉션에서 공통된 원소가 없으면 true, 있으면 false를 반환
- fill() : 리스트의 모든 원소를 특정 값으로 덮어쓰기
- frequency() : 컬렉션에 주어진 원소의 빈도수 반환
- max() : 리스트에서 최대값을 반환
- min() : 리스트에서 최솟값을 반환
- nCopies() : 매개변수 값으로 주어진 객체를 주어진 횟수만큼 복사해 List 객체를 반환
- reverse() : 리스트의 원소들을 역순으로 정렬
- swap() : 리스트에서 주어진 위치에 있는 두 원소를 교체
frequency 예시
더보기
import java.util.*;
public class EtcDemo {
public static void main(String[] args) {
List<String> list1 = List.of("사과","포도","수박","사과","키위","포도","망고","사과");
HashSet<String> set = new HashSet<>(list1);
List<String> list2 = new ArrayList<>(list1);
Collections.sort(list2);
for(String fruit : list2) {
System.out.printf("%s : %d\n", fruit, Collections.frequency(list1,fruit));;
}
}
}
반복자 Iterator
- 반복자.
- Collection 인터페이스에서 iterator() 메소드로 제공.
- iterator를 이용하면 콜렉션에 포함된 원소를 순차적으로 순회할 수 있다. (Map 콜렉션은 반복자를 제공하지 않는다)
Iterator 인터페이스주요 메소드
- hasNext() : 다음 원소의 존재 여부를 반환
- next() : 다음 원소를 반환
- remove() : 마지막에 순회한 콜렉션의 원소를 삭제
모든 원소를 순회하는 Iterator 반복문
Iterator<String> iterator = collection.iterator();
while(iterator.hasNext()){
String s = iterator.next();
}
for(String s : collection) {
}
Iterator 예시
더보기
import java.util.*;
public class IteratorDemo {
public static void main(String[] args) {
Collection<String> list = Arrays.asList("다람쥐","개구리","나비"); // 콜렉션이라는 가장 상위 인터페이스 자료형으로 만들었다
Iterator<String> iterator = list.iterator(); // 순서대로 정렬 (인덱스 번호는 없다)
while (iterator.hasNext())
System.out.print(iterator.next() + " - ");
System.out.println();
// 요소를 사용해서 iterator가 비어 있음
while(iterator.hasNext())
System.out.print(iterator.next() + " + ");
System.out.println();
// iterator가 비어 있으므로 아무 것도 출력되지 않음
iterator = list.iterator();
// iterator 다시 채워줌
while (iterator.hasNext())
System.out.print(iterator.next() + " = ");
}
}
List 인터페이스
// 생성 방법 1
String[] animal = {"사슴","호랑이","바다표범","곰");
List<String> s1 = Arrays.asList(animal);
// 생성 방법 2
List<Integer> s2 = List.of(10,20,30);
- 순서가 있는 객체를 중복 여부와 상관 없이 저장하는 리스트 자료구조를 지원
- 배열과 유사하지만 크기가 가변적(동적)
- 대표적인 List 콜렉션으로는 ArrayList, LinkedList, Stack, Vector가 있다
List 인터페이스 주요 메소드
- add(인덱스, 객체) : 인덱스 위치에 객체를 추가
- get(인덱스) : 인덱스에 있는 객체를 반환
- indexOf(객체) : 명시한 객체가 있는 첫 번째 인덱스 반환
- remove(인덱스) : 인덱스에 있는 객체를 제거
- set(인덱스, 객체) : 인덱스에 있는 객체와 주어진 객체를 교환
- of() : 불변 리스트. 수정할 수 없고 원소로 null을 사용할 수 없다.
List : ArrayList
// ArrayList 생성 방법
ArrayList<String> a1 = new ArrayList<String>(50); //capacity를 50으로 설정. (기본값 10)
// List를 ArrayList 타입으로 생성
List<String> s1 = new ArrayList<>(list);
- List 인터페이스의 구현 클래스
- Arrays 클래스의 메소드가 아니다. 별개의 것.
- 배열을 기반으로 한 콜렉션의 하나.
- 배열 안의 중간 데이터를 추사하거나 삭제할 시, 동적으로 배열의 길이가 조절된다.
- 초기 용량은 10, 용량을 초과할 경우 배열의 크기를 1.5배로 증가시킨다
- 배열과의 다른 점 : 배열은 길이가 고정되어 있으나, ArrayList는 배열의 길이를 자동으로 조절해주어 가변적이다
List : Linked List
- List 인터페이스의 구현 클래스
- 이중 연결 리스트
- 이웃한 원소를 이중으로 연결한다.
- 원소를 추가하거나 할 때 인덱스 조정 없이 전후 원소의 참조 값만 수정하면 되므로 효율적이다
- 메모리 부담이 크다
- 빠르게 자주 조회해야 하면 ArrayList가 좋고, 읽어오는 방향이 매번 순방향 역방향 바뀌면 LinkedList가 좋다
구분 | ArrayList 클래스 | LinkedList 클래스 |
구현 | 가변 크기 배열 (동적) | 이중 연결 리스트 |
초기 용량 | 10 | 0 |
get() 연산 | 빠름 | 느림 |
add(), remove() 연산 | 느림 | 빠름 |
메모리 부담 | 적음 | 많음 |
Iterator | 순방향 | 순방향, 역방향 |
예시
더보기
import java.util.*;
public class PerfomanceDemo {
public static void main(String[] args) {
ArrayList<Integer> al = new ArrayList<>();
LinkedList<Integer> ll = new LinkedList<>();
long start = System.nanoTime();
for(int i=0;i<100000;i++)
al.add(0,i);
long end = System.nanoTime();
long duration = end - start;
System.out.println("ArrayList로 삽입한 시간 : " + duration);
start = System.nanoTime();
for(int i=0;i<100000;i++)
ll.addFirst(i);
end = System.nanoTime();
duration = end - start;
System.out.println("LinkedList로 삽입한 시간 : " + duration);
start = System.nanoTime();
for(int i=0;i<al.size();i++)
al.get(i);
end = System.nanoTime();
duration = end - start;
System.out.println("ArrayList로 조회한 시간 : " + duration);
start = System.nanoTime();
for(int i=0;i<100000;i++)
ll.get(i);
end = System.nanoTime();
duration = end - start;
System.out.println("LinkedList로 조회한 시간 : " + duration);
}
}
List : Stack
//문자열 스택 생성
Stack<String> s1 = new Stack<>();
- List 인터페이스의 구현 클래스
- LIFO(Last In First Out) 방식 (후입선출)
- stack은 인덱스 번호가 1부터 시작한다
Stack 주요 메소드
- empty() : 스택이 비어 있는지 확인하고 true 또는 false 반환
- peek() : 스택의 최상위 원소를 제거하지 않고, 반환만 한다
- pop() : 스택의 최상위 원소를 스택에서 제거하고, 반환한다
- push(원소) : 스택의 최상위에 원소를 추가한다
- search(원소) : 주어진 원소의 인덱스값(1부터 시작)을 반환한다
예시
더보기
import java.util.Stack;
public class StackDemo {
public static void main(String[] args) {
Stack<String> s1 = new Stack<>();
s1.push("사과");
s1.push("바나나");
s1.push("체리");
System.out.println(s1.peek());
System.out.println(s1.pop());
System.out.println(s1.pop());
System.out.println(s1.pop());
Stack<Integer> s2 = new Stack<>();
s2.add(10);
s2.add(20);
s2.add(1,100);
for(int x:s2)
System.out.print(x + " ");
System.out.println();
while(!s2.empty())
System.out.print(s2.pop() + " ");
}
}
Queue 인터페이스
- FIFO(First In First Out) tjsdlqtjscnf
- 후단(tail)에서 원소를 추가하고, 전단(head)에서 원소를 제거
- 큐의 중간에서는 원소를 추가하거나 제거할 수 없다
- Queue에 포함된 구현 클래스 종류 : ArrayDeque, DelayQueue, LinkedList (LinkedList는 다중 구현)
Queue 인터페이스 주요 메소드
- offer() : 삽입
- poll() : 삭제
- peek() : 검색
- add(), remove(), element() 메소드도 사용할 수 있지만, 큐 크기를 초과하거나 해당 요소가 없으면 예외를 발생시킨다.
예시
더보기
import java.util.*;
public class QueueDemo {
public static void main(String[]args) {
Queue<String> q = new LinkedList<>();
//q.remove() // 요소가 없을 때 remove 쓰면 예외 발생
System.out.println(q.poll()); // poll은 예외를 발생하지 않고 null을 반환
q.offer("사과");
System.out.println("바나나를 추가했나요?" + q.offer("바나나"));
head = q.poll();
System.out.println(head + "제거하기");
System.out.println("새로운 헤드 : " + q.peek());
System.out.println("체리를 포함하고 있나요?" + q.contains("체리"));
System.out.println("사과를 포함하고 있나요?" + q.contains("사과"));
}
}
Set 인터페이스
// 생성
Set<String> s = new HashSet<>();
// 불변 Set (of 사용)
Set<String> s = Set.of("포도","수박","사과","키위","망고");
// HashSet 생성
Set<String> s = Set.of("포도","수박","사과","키위","망고");
HashSet<String> hs = new HashSet<>(s);
// TreeSet 생성
Set<String> s = Set.of("포도","수박","사과","키위","망고");
TreeSet<String> ts = new TreeSet<>(s);
- 순서가 없으며, 중복되지 않는 원소를 저장하는 자료구조를 지원한다.
- Set에서 같은 객체란, 두 객체의 hashCode() 값이 같고 equals()의 반환 값이 true인 객체이다.
- Set에 포함된 구현 클래스 종류
- HashSet : 내부적으로 해싱(hashing)을 이용한 Set 구현체. null도 원소로 추가할 수 있다. 해시 테이블을 이용하기 때문에 탐색 속도가 빠르다.
- TreeSet : 이진탐색트리 형태를 이용한 Set 구현체. 오름차순으로 원소를 저장. 이진 탐색 트리를 사용하기 때문에 데이터 정렬이 가능.
Set 인터페이스 주요 메소드
- add(요소) : Set에 요소 추가 (이미 있는 개체는 추가 요청 무시됨. null도 추가 가능)
- remove(요소) : Set에 있는 해당 요소 제거
- contains(요소) : Set이 해당 요소를 포함하고 있으면 true, 아니면 false 반환
- addAll(배열 혹은 리스트) : 배열이나 리스트에 있는 모든 요소를 Set에 추가
- clear() : Set의 모든 요소 제거
HashSet 예시
더보기
import java.util.*;
public class HashSet1Demo {
public static void main(String[] args) {
String[] fruits = {"사과", "바나나", "포도", "수박"};
Set<String> h1 = new HashSet<>();
Set<String> h2 = new HashSet<>();
for(String s:fruits)
h1.add(s);
System.out.println("1단계 : " + h1);
h1.add("바나나");
h1.remove("포도");
h1.add(null);
System.out.println("2단계 : " + h1);
System.out.println(h1.size());
System.out.println(h1.contains("수박"));
List<String> list = Arrays.asList(fruits);
h2.addAll(list);
System.out.println("3단계 : " + h2);
h2.clear();
System.out.println("h2가 비었는지? " + h2.isEmpty());
}
}
TreeSet 예시
더보기
import java.util.*;
public class TreeSetDemo {
public static void main(String[] args) {
Set<String> s = Set.of("포도","수박","사과","키위","망고");
HashSet<String> hs = new HashSet<>(s); // 무질서
System.out.println(hs);
TreeSet<String> ts = new TreeSet<>(s); // String 가나다 순서로 정렬
System.out.println(ts);
System.out.println(ts.first());
System.out.println(ts.last());
System.out.println(ts.lower("사과"));
System.out.println(ts.higher("사과"));
}
}
Map 인터페이스
// 기본형
Map<String, Integer> fruits = new HashMap<>();
// .of() 사용 불변 map 생성
Map<String, Integer> fruits = Map.of("사과",5,"바나나",3,"포도",10,"딸기",1);
// Map은 인터페이스라 객체 생성 불가능. 타입으로는 쓸 수 있으니까, HashMap으로 구현하고 Map을 인터페이스로 쓸 수는 있음
- 키-값으로 구성된 객체를 저장하는 자료구조.
- Map이 사용하는 키와 값도 모두 객체이다.
- 순서가 없다. (랜덤으로 나온다)
- 키는 중복되지 않고 하나의 값에만 매핑되어 있다. (키가 있다면 대등하는 값을 얻을 수 있다)
- 중복을 허용하지 않기 위해 hashCode()와 equals() 메소드를 오버로딩한다
- 키와 밸류를 모두 저장하느라 메모리 낭비가 많다는 단점이 있다.
- Map에 포함된 구현 클래스 종류
- HashMap : 키-값으로 null 사용 가능.
- Hashtable : 키-값으로 null 사용 불가능. 동기화된 메소드로 구현되어 스레드에 안전
- 일반적으로 동기화가 필요 없다면 굳이 Hashtable을 이용하지 않아도 된다.
Map 인터페이스 주요 메소드
- clear() : 모든 키값을 제거
- containsKey(키) : 키의 존재 여부를 조사해서 true, false로 반환
- containsValue(값) : 값의 존재 여부를 조사해서 true, false로 반환
- entrySet() : 모든 키-값을 Set 타입으로 반환
- get(키) : 키에 해당하는 값을 반환
- isEmpty() : Map이 비어 있는지 여부를 조사해서 true, false로 반환
- keySet() : 모든 키를 Set 타입으로 변환
- put(키, 값) : 주어진 키-값을 저장하고 값을 반환
- remove(키) : 키에 대응하는 원소를 삭제하고 값을 반환
- size() : Map의 크기를 반환
- of() : 수정할 수 없는 맵 (자바 9부터)
Map 메소드 예시
Map<String, String> map = new HashMap<String, String>();
map.put("key1", "value1");
map.put("key2", "value2");
map.put("key3", "value3");
map.put("key4", "value4");
map.put("key5", "value5");
entrySet(): key, value 모두 출력
for (Map.Entry<String, String> entry : map.entrySet()) {
System.out.println("[key]:" + entry.getKey() + ", [value]:" + entry.getValue());
}
keySet() : key 값만 출력
for (String key : map.keySet()) {
String value = map.get(key);
System.out.println("[key]:" + key + ", [value]:" + value);
}
entrSet().Iterator() : entrySet 컬렉션 순회
while (iteratorE.hasNext()) {
Map.Entry<String, String> entry = (Map.Entry<String, String>) iteratorE.next();
String key = entry.getKey();
String value = entry.getValue();
System.out.println("[key]:" + key + ", [value]:" + value);
}
keySet().iterator() : keySet 컬렉션 순회
Iterator<String> iteratorK = map.keySet().iterator();
while (iteratorK.hasNext()) {
String key = iteratorK.next();
String value = map.get(key);
System.out.println("[key]:" + key + ", [value]:" + value);
}
https://tychejin.tistory.com/31
Map 예시
더보기
import java.util.*;
public class MapDemo {
public static void main(String[] args) {
Map<String, Integer> fruits = Map.of("사과",5,"바나나",3,"포도",10,"딸기",1);
System.out.println(fruits.size() + "종류의 과일이 있다.");
System.out.println(fruits);
for(String key : fruits.keySet()) {
System.out.println(key + "의 개수 : " + fruits.get(key));
}
String key = "바나나";
if(fruits.containsKey("바나나"))
System.out.println(key + "가 " + fruits.get(key) + "개 있다.");
fruits.forEach((k,n) -> System.out.print(k+"("+ n + ")"));
}
}
HashMap 예시
더보기
import java.util.*;
public class HashMap1Demo {
public static void main(String[]args) {
Map<String, Integer> map = Map.of("사과",5,"바나나",3,"포도",10,"딸기",1);
Map<String, Integer> fruits = new HashMap<>(map);
fruits.put("귤", 2);
System.out.println("지금 과일 종류 개수 : " + fruits.size());
fruits.remove("바나나");
System.out.println("나중 과일 종류 개수 : " + fruits.size());
fruits.put("망고", 2);
System.out.println("현재 과일 종류 : " + fruits);
fruits.clear();
System.out.println("clear 후 과일 종류 : " + fruits);
}
}