컬렉션 : 많은 데이터들을 효과적으로 처리할 수 있는 방법을 제공하는 클래스들의 집합

일관된 API
Collection 에서 제공하는 규격화된 메소드를 사용함으로 일관된 사용과 유지보수가 가능하다.
프로그래밍 비용 감소
이미 제공된 자료구조를 활용하는 것으로 low-level의 알고리즘을 고민할 시간과 노력을 아낄 수 있다.
프로그래밍 속도 및 품질 향상+
필요한 자료구조를 사용함으로써 프로그래밍의 속도 뿐만 아니라 기동 속도, 품질 향상을 기대할 수 있다.
| 인터페이스 | 설명 | 구현 클래스 |
|---|---|---|
| List | 순서가 있는 데이터의 집합으로, 데이터의 중복을 허용한다. | ArrayList, LinkedList, Stack, Queue, Vector |
| Set | 순서가 없는 데이터의 집합으로, 데이터 중복 허용하지 않는다. | HashSet, TreeSet |
| Map<K, V> | 키와 값이 쌍를 이루어 구성되는 데이터 집합으로 순서가 없다. 키의 중복은 허용되지 않지만, 값의 중복은 허용된다. | HashMap, TreeMap, Properties |
순서가 있는 데이터의 집합으로 같은 데이터의 중복 저장을 허용
위와 같은 것들이 있다.

간단한 메소드도 함께 알아보자.
Application
import java.util.ArrayList;
import java.util.List;
public class Application {
public static void main(String[] args) {
// 1. List
List list = new ArrayList<>(); // 자료형을 안 적으면 Object가 적힌거랑 같다.
// List로 선언하는 이유 : List 계열의 다른 인스턴스로 바뀌어도 영향을 주지 않기 위해 다형석 적용한 채로 사용한다.
list.add("apple");
list.add(123);
list.add(45.67);
list.add(new java.util.Date());
// 컬렉션들은 toString()이 잘 오버라이드 되어 있어 출력하기 편함
System.out.println("list 한 번에 출력 : " + list);
// 1. 특정 인덱스 값 반환
// 배열에서는 arr[0] 처럼 했다면 List에서는 get() 메소드를 사용한다.
System.out.println("list.get(0) : " + list.get(0));
System.out.println("list.get(2) : " + list.get(2));
// 2. 데이터의 크기 반환
// 배열에서는 length, length()를 사용했다면 List에서는 size() 메소드 사용
System.out.println("list에 담긴 데이터의 크기 : " + list.size());
// list에 있는 데이터 전체 확인해보는 방법
for (int i = 0; i < list.size(); i++) {
list.get(i);
}
// 3. ArrayList는 중복 허용이어서 동등값이 허용된다.
list.add("apple");
list.add(123);
// 실행결과 : [apple, 123, 45.67, Tue Jul 23 11:42:20 KST 2024, apple, 123]
// 4. 특정 인덱스의 값을 수정하기 위해서는 set() 사용
list.set(0, 777);
// 실행결과 : [777, 123, 45.67, Tue Jul 23 11:43:45 KST 2024, apple, 123]
// 5. 특정 인덱스 값 삭제를 위해서는 remove() 사용 -> size도 줄어든다.
list.remove(0);
System.out.println(list);
// 실행결과 : [123, 45.67, Tue Jul 23 11:44:40 KST 2024, apple, 123]
// + null도 add가 가능하다 (중간에 끼워넣고 싶으면 매개변수 2개 사용 add.(인덱스, 값))
list.add(0, null);
System.out.println(list);
// 실행결과 : [null, 123, 45.67, Tue Jul 23 11:46:24 KST 2024, apple, 123]
// 7. list 안에 특정한 값을 가지고 있는지 확인하기 위해서는 contains() 사용
System.out.println(list.contains(null));
// 실행결과 : true
}
}
배열보다 ArrayList가 나은 점
1. 처음부터 크기를 할당해줄 필요가 없다.
2. 중간에 값을 추가하거나 삭제하기가 상대적으로 용이하다.
import java.util.Arrays;
public class Application {
public static void main(String[] args) {
int[] intArr = new int[5];
int num = 0;
for (int i = 0; i < intArr.length; i++) {
intArr[i] = ++num;
}
System.out.println(Arrays.toString(intArr));
int[] newArr = new int[intArr.length +1];
System.arraycopy(intArr, 0, newArr, 0, intArr.length);
System.out.println(Arrays.toString(newArr));
// 2번 인덱스에 7 이라는 값 끼워넣기
for (int i = intArr.length - 1; i > 1; i--) {
newArr[i + 1] = newArr[i];
}
newArr[2] = 7;
System.out.println(Arrays.toString(newArr));
}
}
실행결과
[1, 2, 3, 4, 5]
[1, 2, 3, 4, 5, 0]
[1, 2, 7, 3, 4, 5]
import java.util.ArrayList;
import java.util.List;
public class Application {
public static void main(String[] args) {
List<Integer> intList = new ArrayList<>();
for (int i = 0; i < 5; i++) {
intList.add(i + 1);
}
System.out.println(intList);
intList.add(2,7);
System.out.println(intList);
}
}
실행결과
[1, 2, 3, 4, 5]
[1, 2, 7, 3, 4, 5]
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
public class Application {
public static void main(String[] args) {
List<String> stringList = new ArrayList<>();
stringList.add("apple");
stringList.add("orange");
stringList.add("banana");
stringList.add("mango");
stringList.add("grape");
System.out.println("초기화 된 stringList = " + stringList);
Collections.sort(stringList);
System.out.println("오름차순 정렬 후 stringList = " + stringList);
Collections.reverse(stringList); // 오름차순 후에 역순을 해주는 것
// Collections.sort(stringList, Collections.reverseOrder()); // 이건 바로 내림차순정렬이다.
System.out.println("내림차순 정렬은 오름차순 후 reverse -> stringList = " + stringList);
// 또다른 내림차순 방법
/* Iterator(반복자)는 hasNext()와 next()를 활용해 들어있는 data를 반복시킬 수 있는 타입 */
/* 다루는 Iterator와 관련된 컬렉션의 제네릭 타입과 일치하는 제네릭 타입을 꼭 써줘야 한다. (다운캐스팅에 대한 고민이 없도록) */
stringList = new LinkedList<>(stringList); // LinkedList 개념으로 바꾸기
Iterator<String> stringIterator = ((LinkedList<String>) stringList).descendingIterator();
while (stringIterator.hasNext()) {
System.out.print(stringIterator.next() + " ");
}
// 다시 오름차순으로 바뀐다.
}
}

ArrayList는 안에 들어있는 데이터 타입에 따라 정의된 기준대로 정렬을 한다.
그래서 String에 문자열 오름차순에 대한 정의가 있어서 그거대로 정렬을 한 것.
String 처럼 Wrapper 클래스는 전부 다 정의돼 있다.
우리가 원하는 필드의 오름차순, 내림차순을 할 수 있다.
필드가 n개면 총 (n * 2) 가지의 정렬기준을 가질 수 있다.. 오름차순 내림차순 2개씩
정렬은 compareTo() 메소드가 반환하는 int형의 부호에 따라 정해지게 된다.
(해당 필드가 String형일 경우 String의 compareTo() 메소드를 활용하자)
BookDTO
public class BookDTO implements Comparable<BookDTO> {
private int number;
private String title;
private String author;
private int price;
public BookDTO() {
}
public int getNumber() {
return number;
}
public void setNumber(int number) {
this.number = number;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public String getAuthor() {
return author;
}
public void setAuthor(String author) {
this.author = author;
}
public int getPrice() {
return price;
}
public void setPrice(int price) {
this.price = price;
}
public BookDTO(int number, String title, String author, int price) {
this.number = number;
this.title = title;
this.author = author;
this.price = price;
}
@Override
public String toString() {
return "BookDTO{" +
"number=" + number +
", title='" + title + '\'' +
", author='" + author + '\'' +
", price=" + price +
'}';
}
@Override
public int compareTo(BookDTO o) {
// 가격에 대한 오름차순
// return this.price - o.getPrice();
// 가격에 대한 내림차순
// return o.getPrice() - this.price;
// 책 제목에 대한 오름차순
// return this.title.compareTo(o.getTitle());
// 책 제목에 대한 내림차순
return -this.title.compareTo(o.getTitle());
}
}
Comparable 인터페이스를 구현하게끔 하는건데 BookDTO 타입으로 제네릭해주지 않으면 Object로 들어가서 다운캐스팅으로 인한 문제가 생길 수 있기 때문에 적어줘야 한다.
주석처리 된 가격 오름, 내림차순 / 제목 오름, 내림차순에 대한 것들을 꼭 실행해보는 것이 좋다.
Application
import {패키지 구조}.BookDTO;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
public class Application {
public static void main(String[] args) {
List<BookDTO> bookList = new ArrayList<>();
bookList.add(new BookDTO(1, "홍길동전", "허균", 50000));
bookList.add(new BookDTO(2, "목민심서", "정약용", 30000));
bookList.add(new BookDTO(3, "동의보감", "허준", 40000));
bookList.add(new BookDTO(4, "삼국사기", "김부식", 46000));
bookList.add(new BookDTO(5, "삼국유사", "일연", 58000));
Collections.sort(bookList);
for(int i = 0; i < bookList.size(); i++) {
System.out.println(bookList.get(i));
}
}
}
이번엔 Comparable이 아닌 Comparator를 사용해보자.
AscendingPrice
import {패키지구조}.BookDTO;
import java.util.Comparator;
public class AscendingPrice implements Comparator<BookDTO> {
// 가격 오름차순이 가능하도록 compare() 메소드 오버라이딩
@Override
public int compare(BookDTO o1, BookDTO o2) {
return o1.getPrice() - o2.getPrice();
}
}
Application
import {패키지구조}.AscendingPrice;
import {패키지구조}.BookDTO;
import java.util.ArrayList;
import java.util.List;
public class Application {
public static void main(String[] args) {
List<BookDTO> bookList = new ArrayList<>();
bookList.add(new BookDTO(1, "홍길동전", "허균", 50000));
bookList.add(new BookDTO(2, "목민심서", "정약용", 30000));
bookList.add(new BookDTO(3, "동의보감", "허준", 40000));
bookList.add(new BookDTO(4, "삼국사기", "김부식", 46000));
bookList.add(new BookDTO(5, "삼국유사", "일연", 58000));
// Comparable 방식
// Collections.sort(bookList);
// Comparator 방식
// Collections.sort(bookList, new AscendingPrice());
bookList.sort(new AscendingPrice());
for(int i = 0; i < bookList.size(); i++) {
System.out.println(bookList.get(i));
}
}
}
실행결과
BookDTO{number=2, title='목민심서', author='정약용', price=30000}
BookDTO{number=3, title='동의보감', author='허준', price=40000}
BookDTO{number=4, title='삼국사기', author='김부식', price=46000}
BookDTO{number=1, title='홍길동전', author='허균', price=50000}
BookDTO{number=5, title='삼국유사', author='일연', price=58000}
만약 위와 같이 나오는 것이 아니라, 주소값이 반환된다면 BookDTO에 toString을 추가해주자.

이번엔 List 계열을 출력하는 4가지 방법에 대해 알아본다.
주석으로 적어두고 만들어뒀다.
Application
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
public class Application {
public static void main(String[] args) {
List<String> arrList = new ArrayList<>();
arrList.add("apple");
arrList.add("orange");
arrList.add("banana");
arrList.add("mango");
arrList.add("grape");
/* 설명 1. toString() 활용하기 */
System.out.println("arrList = " + arrList);
/* 설명 2. for문 활용하기 */
for (int i = 0; i < arrList.size(); i++) {
System.out.println(arrList.get(i));
}
/* 설명 3. for-each문 활용하기 */
for(String str : arrList) {
System.out.println(str);
}
/* 설명 4. iterator 활용하기 */
Iterator<String> iterator = arrList.iterator();
while (iterator.hasNext()) {
System.out.println(iterator.next());
}
}
}