컬렉션 프레임워크(collection framework)란?
자바에서 컬렉션 프레임워크(collection framework)란 다수의 데이터를 쉽고 효과적으로 처리할 수 있는 표준화된 방법을 제공하는 클래스의 집합을 의미한다. 즉, 데이터를 저장하는 자료 구조와 데이터를 처리하는 알고리즘을 구조화하여 클래스로 구현해놓은 것이다. 이러한 컬렉션 프레임워크는 자바의 인터페이스(interface)를 사용하여 구현된다.
인터페이스(interface)란?
- 구현된 것은 아무것도 없는 밑그림만 있는 기본 설계도
- 일반 메소드 또는 멤버 변수를 가질 수 없고, 오직 추상메소드와 상수만을 멤버로 가질 수 있다. -> 추상클래스보다 추상화가 더 높다.
- 인터페이스는 표준, 약속, 규칙이다.
인터페이스 작성 방법
interface 인터페이스명 {
public static final 타입 상수명 = 값;
public abstract 메소드명(매개변수목록);
}
인터페이스 구현
class 클래스명 implements 인터페이스명{
// 인터페이스에 정의된 추상메소드를 구현
}
abstract class 클래스명 implements 인터페이스명 {
// 인터페이스에 정의된 추상메소드의 일부만 구현
}
class 클래스명 extends 조상클래스명 implements 인터페이스명{
}
인터페이스의 장점
- 개발시간을 단축시킬 수 있음
- 표준화 가능
- 서로 관계없는 클래스들에게 관계를 맺어줄 수 있다. -> 하나의 인터페이스를 공통적으로 구현하도록 함으로써 관계를 맺어줄 수 있다.
- 독립적인 프로그래밍이 가능하다. -> 클래스와 클래스간의 직접적인 관계를 인터페이스를 이용하여 간접적인 관계로 변경하면 한 클래스의 변경이 관련된 다른 클래스에 영향을 미치지 않도록 독립적인 프로그래밍이 가능하다.
컬렉션 프레임워크의 주요 인터페이스
1. List 인터페이스
2. Set 인터페이스
3. Map 인터페이스
이중에서 List와 Set 인터페이스는 모두 Collection을 상속받지만, 구조상의 차이로 Map 인터페이스는 별도로 정의된다.
따라서 List인터페이스와 Set인터페이스의 공통된 부분을 Collection 인터페이스에서 정의하고 있다.
List Interface
- 순서가 있는 데이터의 집합
- 데이터의 중복을 허용하는 인터페이스
- 객체가 추가되어 용량을 초과하면 자동으로 부족한 크기만큼 용량이 늘어남
1. ArrayList
- 데이터 삽입, 삭제가 느리다.
- 데이터 검색이 빠르다.
- 배열을 기반으로 데이터를 저장한다.
import java.util.ArrayList;
class GFG{
pulbic static void main(String[] args){
//ArrayList 선언
ArrayList<Integer> integers1 = new ArrayList<Integer>(); // 타입 지정
ArrayList<Integer> integers2 = new ArrayList<>(); // 타입 생략 가능
ArrayList<Integer> integers3 = new ArrayList<>(10); // 초기용량 설정
ArrayList<Integer> integers4 = new ArrayList<>(integers1); // 다른 Colloection값으로 초기화
}
}
보통 생성할때는 new ArrayList<>()와 같이 타입을 생략해서 작성한다.
ArrayList 값 추가하기
ArrayList의 값을 추가하기 위해서는 add() 메소드를 사용한다.
1. add(Object) : ArrayList의 마지막에 데이터를 추가
2. add(int index, Object) : ArrayList의 index에 데이터를 추가
import java.util.ArrayList;
public class ArrayListDemo{
public static void main(String[] args) {
ArrayList<String> al = new ArrayList<>();
al.add("Hello");
al.add(1, "world");
}
}
ArrayList 값 변경하기
ArrayList의 값 변경은 set() 메소드를 사용한다.
set()을 사용해서 변경하려면 데이터의 index를 알아야 변경이 가능하다.
set(int index, Object)를 사용한다.
import java.util.ArrayList;
public class ArrayListDemo{
public static void main(String[] args) {
ArrayList<String> al = new ArrayList<>();
al.add("Hello");
al.add(1, "world");
al.set(1, "World!1");
}
}
ArrayList 값 삭제하기
ArrayList 값을 삭제하는 방법에는 remove()와 clear()가 있다.
clear()은 ArrayList의 모든 값을 삭제할 때 사용한다.
remove()는 값을 하나씩 제거할 때 사용한다.
remove()는 두개의 사용방법이 있는데,
remove(Object) : Object를 파라미터로 넘기는 경우 해당 ArrayList의 Object와 같은 값을 삭제한다.
만약 값이 두개인 경우 첫번째로 같은 값을 제거한다.
remove(int index) : ArrayList의 index에 해당하는 값을 삭제한다.
ArrayList 크기 구하기
ArrayList의 크기를 구하는 방법은 size()메서드를 사용하여 구할 수 있다.
import java.util.ArrayList;
public class ArrayListDemo{
public static void main(String[] args) {
ArrayList<String> al = new ArrayList<>();
al.add("Hello");
al.add(1, "world");
System.out.println("ArrayList의 크기 : " + al.size());
}
}
ArrayList 값 출력하기
ArrayList의 결과를 출력하는 방법에는 get(int index) 메소드가 있다.
index를 입력하면 해당 index의 데이터가 출력된다.
전부 출력하고 싶다면 for문과 향상된 for문을 사용하여 출력할 수 있다.
import java.util.ArrayList;
import java.util.Iterator;
public class ArrayListDemo {
public static void main(String[] args) {
ArrayList<String> al = new ArrayList<>();
al.add("Hello");
al.add("World");
al.add("Hello");
al.add("World");
for (int i = 0; i < al.size(); i++) {
System.out.print(al.get(i) + " ");
}
}
}
2. LinkedList
- 노드(Node)와 포인터(Pointer)를 이용하여 만든 리스트로 next와 prev로 양방향 포인터를 가진다.
포인터로 각각의 노드들을 연결하고 있어, 삽입/삭제가 빠르다는 장점이 있다. (단순히 기존 포인터를 끊고 새로운 노드에 연결하면 되기 때문)
하지만, 특정 원소를 조회하기 위해서는 첫 노드부터 순회해야하기 때문에 ArrayList에 비해 느리다는 단점이 있다.
LinkedList는 조회보다 삽입/삭제가 많은 경우에 사용하는 것이 좋다.
3. vector
- 과거에 대용량 처리를 위해 사용
- 내부에서 자동으로 동기화처리가 일어나 비교적 성능이 좋지 않고 무거워 잘 쓰이지 않음
4. Stack
-스택 클래스 모델 및 스택 데이터 구조를 구현할 때 주로 사용
- 후입선출을 기본 원칙
Set Interface
- 데이터의 집합이며 순서가 없고 중복된 데이터를 허용하지 않음
- 빠른 검색속도를 가짐
- 인덱스가 따로 존재하지 않기 때문에 interator를 사용
- 중복을 방지하고 고유한 데이터만 저장해야하는 경우에 사용됨
1. HashSet
- 집합의 특징 때문에 중복을 허용하지 않고, 순서를 가지지 않음
- 대표적으로 많이 사용하는 집합(Set) 자료구조
- Null 요소 삽입을 허용함
@Test
@DisplayName("Collection의 HashSet 테스트")
void hashSetTest() {
Set<Integer> hashSet = new HashSet<>();
hashSet.add(10);
hashSet.add(20);
hashSet.add(30);
hashSet.add(10); // 중복된 수 추가
assertEquals(3, hashSet.size());
assertEquals("[20, 10, 30]", hashSet.toString()); // 순서가 없음
}
2. LinkedHashSet
- HashSet처럼 중복을 허용하지 않지만 데이터를 저장하는 순서를 유지
@Test
@DisplayName("Collection의 LinkedHashSet 테스트")
void linkedHashSetTest() {
Set<Integer> linkedHashSet = new LinkedHashSet<>();
linkedHashSet.add(10);
linkedHashSet.add(20);
inkedHashSet.add(30);
linkedHashSet.add(10); // 중복된 수 추가
assertEquals(3, linkedHashSet.size());
// 들어온 순서대로, 순서를 가짐
Iterator<Integer> it = linkedHashSet.iterator();
while(it.hasNext())
System.out.println(it.next());
}
3. TreeSet
- 중복을 허용하지 않고, 순서를 가지지 않음
- 이진 탐색 트리(Red-Black Tree)를 기반
- 데이터들이 오름차순으로 정렬
- 데이터 삽입, 삭제에는 시간이 걸리지만 검색, 정렬이 빠름
@Test
@DisplayName("Collection의 TreeSet 테스트")
void treeSetTest() {
Set<Integer> treeSet = new TreeSet<>();
treeSet.add(20);
treeSet.add(1);
treeSet.add(100);
treeSet.add(33);
treeSet.add(1); // 중복 제거 됨
assertEquals(4, treeSet.size());
// 기본적으로는 오름차순으로 정렬 됨
Iterator<Integer> it = treeSet.iterator();
while(it.hasNext()) {
System.out.println(it.next());
}
}
Map이란?
- key와 Value 한 쌍으로 이루어진 자료형.
- Map은 리스트나 배열처럼 순차적으로 해당 요소 값을 구하지 않고 key를 통해 value를 얻음.
- Key에 대한 중복이 없으며 순서를 보장하지 않음
- 인덱스가 따로 존재하지 않기 때문에 iterator를 사용
정리하자면 Map은 저장 순서를 유지할 필요가 없고, key를 통해 value를 얻어내기 때문에 key는 중복을 허용하지 않는다. 이미 존재하는 key값과 동일한 key값을 put하면 새로운 key값으로 갱신된다.
1. HashMap
- Key에 대한 중복이 없으며 순서를 보장하지 않는다.
- key와 value 값으로 NULL을 허용한다.
- 동기화가 보장되지 않는다.
- 검색에 가장 뛰어난 성능을 가진다.
@Test
@DisplayName("Map의 HashMap 테스트")
void hashMapTest() {
Map<Integer, String> hashMap = new HashMap<>();
hashMap.put(1, "one");
hashMap.put(2, "two");
Iterator<Integer> it = hashMap.keySet().iterator();
while(it.hasNext()) {
int key = it.next();
System.out.println("key: " + key + ", value: " + hashMap.get(key));
}
}
key: 1, value: one
key: 2, value: two
HashMap<String, String> map = new HashMap<String, String>();
map.put("people", "사람");
map.put("baseball", "야구");
key와 value가 String 형태인 HashMap을 만들고 위에서 보았던 예제의 항목값들을 입력해 보았다. key와 value는 위 예제에서 보듯이 put메소드를 이용하여 입력한다.
key에 해당되는 값을 얻기 위해서는 다음과 같이 한다.
System.out.println(map.get("people"));
containsKey 메소드는 맵(Map)에 해당 키(key)가 있는지를 조사하여 그 결과값을 리턴한다.
System.out.println(map.containsKey("people"));
"people"이라는 키는 존재하므로 true가 출력될 것이다.
remove 메소드는 맵(Map)의 항목을 삭제하는 메소드로 key값에 해당되는 아이템(key, value)을 삭제한 후 그 value 값을 리턴한다.
System.out.println(map.remove("people"));
"people"에 해당되는 아이템(people:사람)이 삭제된 후 "사람"이 출력될 것이다.
size 메소드는 Map의 갯수를 리턴한다.
System.out.println(map.size());
"people", "baseball" 두 값을 가지고 있다가 "people"항목이 삭제되었으므로 1이 출력될 것이다.
2. LinkedHashMap과 TreeMap
Map의 가장 큰 특징은 순서에 의존하지 않고 key로 value를 가져오는데 있다. 하지만 가끔은 Map에 입력된 순서대로 데이터를 가져오고 싶은 경우도 있고 때로는 입력된 key에 의해 소트된 데이터를 가져오고 싶을 수도 있을 것이다. 이런경우에는 LinkedHashMap과 TreeMap을 사용하는 것이 유리하다.
- LinkedHashMap은 입력된 순서대로 데이터가 출력되는 특징을 가지고 있다.
- TreeMap은 입력된 key의 소트순으로 데이터가 출력되는 특징을 가지고 있다.
'program > Java, Spring' 카테고리의 다른 글
[Spring boot] Spring boot 프로젝트 간편하게 만들기(start.spring.io) (0) | 2023.07.05 |
---|---|
[Spring] Maven, pom.xml 이란? (2) | 2023.01.30 |
[Spring] @Configuration 안에 @Bean을 사용해야 하는 이유, proxyBeanMethods - (2/2) (0) | 2022.04.26 |
[Spring] 빈 등록을 위한 어노테이션 @Bean, @Configuration, @Component 차이 및 비교 - (1/2) (0) | 2022.04.26 |
DAO, DTO, VO, Entity 차이 (0) | 2022.04.19 |