늦은 프로그래밍 이야기
컬렉션, 제네릭스 본문
컬렉션 (Collection)
- 자바에서 자료구조를 표현하는 인터페이스.
- 컬렉션 프레임워크 : 다수의 데이터를 다루기 위한 자료구조를 표현하고 사용하는 클래스의 집합.
- 컬렉션 인터페이스 : 컬렉션 클래스에 저장된 데이터를 읽고, 추가하고, 삭제하는 등 데이터를 다루는 기본적인 메소드들을 정의.
- 컬렉션 프레임워크를 구성하는 모든 클래스가 제네릭으로 표현(<E>, <K,V>)되어 있다.

자료구조
1) List : 순서가 있는 데이터의 집합. 데이터의 중복을 허용. (Vector, ArrayList, LinkedList, Stack, Queue)
2) Set : 순서를 유지하지 않는 데이터의 집합. 데이터의 중복을 허용하지 않음. (HashSet, TreeSet)
3) Map : 키와 값의 쌍으로 이루어진 데이터의 집합. 순서는 유지하지 않음. 키는 중복이 허용되지 않고 값은 중복을 허용. (HashMap, TreeMap, Hashtable, Properties)
4) Stack : 마지막에 넣은 데이터를 먼저 꺼내는 자료구조. LIFO(Last In First Out). 후입선출
5) Queue : 먼저 넣은 데이터를 먼저 꺼내는 자료구조. FIFO(First In First Out). 선입선출
리스트 (List)
1) 생성
List<자료형> 변수명 = new ArrayList<>();
2) 메소드
- add(값) : 리스트에 입력한 순서대로 값을 입력한다.
- Collection.sort() : 리스트를 오름차순으로 정렬한다.
- remove(인덱스) : 인덱스에 해당하는 데이터를 제거한다.
- size() : 리스트의 전체길이를 반환한다.
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
public class Main {
public static void main(String[] args) {
List<Integer> integerList = new ArrayList<>();
integerList.add(1);
integerList.add(5);
integerList.add(4); // 리스트에 1개씩 입력
integerList.add(11);
integerList.add(10);
System.out.println(integerList); // [1, 5, 4, 11, 10]
Collections.sort(integerList); // 리스트 정렬
System.out.println(integerList); // [1, 4, 5, 10, 11]
System.out.println(integerList.size()); // 5
integerList.remove(4); // 4번째 인덱스 제거
System.out.println(integerList); // [1, 4, 5, 10]
for(int i = 0; i < integerList.size(); i++) { // .size() = 리스트 전체길이
System.out.println(integerList.get(i)); // 리스트 내의 원소 반복 (for문)
}
for(int current: integerList) {
System.out.println(current); // 리스트 내의 원소 반복 (for-each문)
}
}
}
셋 (Set)
- 오름차순으로 자동 정렬.
1) 생성
Set<자료형> 변수명 = new HashSet<>();
2) 메소드
- add(값) : 셋에 입력한 순서에 상관 없이 추가한다.
- remove(값) : 해당 값의 데이터를 제거한다.
- removeAll() : ArrayList에 삽입한 데이터를 한번에 제거한다.
- contains(값) : 해당 값의 유무를 True or False로 반환한다.
- size() : Set의 길이를 반환한다.
- clear() : Set에 저장되어 있는 데이터를 모두 제거한다.
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
public class Main {
public static void main(String[] args) {
Set<Integer> integerSet = new HashSet<>();
integerSet.add(1);
integerSet.add(1);
integerSet.add(3);
integerSet.add(2); // 1개씩 입력.
integerSet.add(9);
integerSet.add(8);
System.out.println(integerSet); // [1, 2, 3, 8, 9]
Set<String> stringSet = new HashSet<>();
stringSet.add("LA");
stringSet.add("New York");
stringSet.add("LasVegas");
stringSet.add("San Francisco");
stringSet.add("Seoul");
System.out.println(stringSet); // ["LA", "LasVegas", "New York", "San Francisco", "Seoul"]
stringSet.remove("Seoul"); // 해당 값을 제거
System.out.println(stringSet); // ["LA", "LasVegas", "New York", "San Francisco"]
List<String> target = new ArrayList<>();
target.add("New York");
target.add("LasVegas"); // 제거할 데이터를 ArrayList에 삽입
stringSet.removeAll(target); // 삽입한 데이터를 한번에 삭제
System.out.println(stringSet); // ["LA", "San Francisco"]
System.out.println("LA 포함되어있나요? " + stringSet.contains("LA")); // True
System.out.println("Seoul 포함되어있나요? " + stringSet.contains("Seoul")); // False
System.out.println(stringSet.size()); // 2
stringSet.clear(); // 모두 제거
System.out.println(stringSet); // []
}
}
맵 (Map)
1) 생성
Map<Key자료형, Value자료형> 변수명 = new HashMap<>();
2) 메소드
- put(키, 밸류) : 키(Key)와 밸류(Value)를 입력한다.
- get(키) : 해당 키의 밸류를 보여준다.
- containsKey(키) : 해당 키값의 유무를 True or False로 반환한다.
- containsValue(밸류) : 해당 밸류값의 유무를 True or False로 반환한다.
- clear() : map의 데이터를 모두 제거한다.
import java.util.HashMap;
import java.util.Map;
public class Main {
public static void main(String[] args) {
Map<Integer, String> map = new HashMap<>();
map.put(1, "apple");
map.put(2, "berry");
map.put(3, "cherry");
System.out.println(map);
System.out.println("1st in map : " + map.get(1));
map.remove(2);
System.out.println(map);
System.out.println(map.containsKey(2));
System.out.println(map.containsValue("cherry"));
map.clear();
System.out.println(map);
}
}
스택 (Stack)
1) 생성
Stack<자료형> 변수명 = new Stack<>();
2) 메소드
- push(값) : Stack에 데이터를 입력.
- peek() : 맨 마지막에 넣은 데이터를 보여준다. (제거되지 않음.)
- pop() : 맨 마지막에 넣은 데이터를 꺼내어 반환한다. (제거됨.)
- contains(값) : 해당 값의 유무를 True of False로 반환한다.
- empty(), isEmpty() : 스택이 비어있는지 여부를 True of False로 반환한다.
- clear() : 스택의 데이터를 모두 제거한다.
import java.util.Stack;
public class Main {
public static void main(String[] args) {
Stack<Integer> stack = new Stack<>();
stack.push(1);
stack.push(3);
stack.push(7);
stack.push(5);
System.out.println(stack); // [1, 3, 7, 5]
System.out.println(stack.peek()); // 5 (마지막에 입력한 데이터)
System.out.println("size : " + stack.size()); // size : 5
System.out.println(stack.pop()); // 5 (마지막에 입력한 데이터)
System.out.println("size : " + stack.size()); // size : 4
System.out.println(stack.contains(1)); // True
System.out.println(stack.empty()); // False
stack.clear(); // 모두 제거
System.out.println(stack.isEmpty()); // True
}
}
큐 (Queue)
1) 생성
Queue<자료형> 변수명 = new LinkedList<>();
2) 메소드
- add(값) : Queue에 데이터를 입력.
- poll() : 맨 처음 입력한 데이터를 꺼내어 반환한다. (제거됨)
- peek() : 맨 처음 입력한 데이터를 보여준다. (제거되지 않음.)
- isEmpty() : Queue가 비어있는지 여부를 True or False로 반환한다.
- clear() : Queue의 데이터를 모두 제거한다.
import java.util.LinkedList;
import java.util.Queue;
public class Main {
public static void main(String[] args) {
Queue<Integer> queue = new LinkedList<>();
queue.add(1);
queue.add(5);
queue.add(3);
System.out.println(queue); // [1, 5, 3]
System.out.println(queue.poll()); // 1
System.out.println(queue); // [5, 3]
System.out.println(queue.peek()); // 5
System.out.println(queue); // [5, 3]
System.out.println(queue.isEmpty()); // false
queue.clear();
System.out.println(queue.isEmpty()); // true
}
}
어레이디큐 (ArrayDeque)
- 양 끝에서 삽입과 삭제가 가능하다.

1) 생성
ArrayDeque<자료형> 변수명 = new ArrayDeque<>();
2) 메소드
- addFirst(값) : 어레이디큐에 데이터를 앞으로 입력. (크기 문제가 생길때 Exception을 반환)
- addLast(값) : 어레이디큐에 데이터를 뒤로 입력. (크기 문제가 생길때 Exception을 반환)
- offerFirst(값) : 어레이디큐에 데이터를 앞으로 입력 (크기 문제가 생길때 False를 반환)
- offerLast(값) : 어레이디큐에 데이터를 뒤로 입력. (크기 문제가 생길때 False를 반환)
- push(값) : 데이터를 앞으로 입력.
- pop() : 데이터를 앞에서 꺼내어 반환한다. (제거됨)
- removeFirst(), removeLast() : 맨 앞, 맨 뒤의 데이터를 제거하고 반환한다.
- pollFirst(), pollLast() : 맨 앞, 맨 뒤의 데이터를 꺼내어 반환한다. (제거됨)
- peekFirst(), peekLast() : 맨 앞, 맨뒤의 데이터를 보여준다. (제거되지 않음.)
- size() : 어레이디큐의 길이를 반환한다.
import java.util.ArrayDeque;
public class Main {
public static void main(String[] args) {
ArrayDeque<Integer> arrayDeque = new ArrayDeque<>();
arrayDeque.addFirst(1);
arrayDeque.addFirst(2);
arrayDeque.addFirst(3);
arrayDeque.addFirst(4);
System.out.println(arrayDeque); // [4, 3, 2, 1]
arrayDeque.addLast(0);
System.out.println(arrayDeque); // [4, 3, 2, 1, 0]
arrayDeque.offerFirst(10);
System.out.println(arrayDeque); // [10, 4, 3, 2, 1, 0]
arrayDeque.offerLast(-1);
System.out.println(arrayDeque); // [10, 4, 3, 2, 1, 0, -1]
arrayDeque.push(22);
System.out.println(arrayDeque); // [22, 10, 4, 3, 2, 1, 0, -1]
System.out.println(arrayDeque.pop()); // 22
System.out.println(arrayDeque); // [10, 4, 3, 2, 1, 0, -1]
System.out.println(arrayDeque.removeFirst()); // 10
System.out.println(arrayDeque.removeLast()); // -1
System.out.println(arrayDeque); // [4, 3, 2, 1, 0]
System.out.println(arrayDeque.size()); // 5
System.out.println(arrayDeque.peekFirst()); // 4
System.out.println(arrayDeque); // [4, 3, 2, 1, 0]
System.out.println(arrayDeque.size()); // 5
System.out.println(arrayDeque.pollFirst()); // 4
System.out.println(arrayDeque); // [3, 2, 1, 0]
System.out.println(arrayDeque.size()); // 4
arrayDeque.clear();
System.out.println(arrayDeque.isEmpty()); // true
}
}
제네릭스 (Generics)
- 데이터의 타입을 일반화(generalize)한다는 뜻.
- 다양한 타입의 객체들을 다루는 메소드나 컬렉션 클래스의 컴파일 시의 타입체크를 해주는 기능
- 객체의 타입을 컴파일 시에 미리 타입 검사를 하기 때문에 안정성이 높아진다.
선언
- 클래스와 메소드에만 선언할 수 있다.
class MyArray<T> {
T element;
void setElement(T element) {
this.element = element;
}
T getElement() {
return element;
}
}
- 'T'를 타입 변수(type variable)라 하고, 임의의 참조형 타입을 의미.
- 여러 개의 타입 변수는 쉼표(,)로 구분하여 명시.
- 클래스뿐만 아니라 메소드의 매개변수나 반환값으로 사용.
생성
MyArray<Integer> myArr = new MyArray<Integer>();
MyArray<Integer> myArr = new MyArray<>(); // 타입을 추정할 수 있는경우 타입을 생략할 수 있다.
- 클래스를 생성할 때 실제 타입을 명시하면, 내부적으로 정의된 타입변수가 명시된 실제 타입으로 변환되어 처리된다.
- 타입변수 자리에 사용할 실제 타입을 명시할 때 기본 타입을 바로 사용할 수 없다.
타입인자 약어
- <T> == Type
- <E> == Element
- <K> == Key
- <V> == Value
- <N> == Number
- <R> == Result 리턴타입
제거시기
- 자바 코드에서 선언되고 사용된 제네릭 타입은 컴파일 시 컴파일러에 의해 자동으로 검사되어 타입 변환된다.
- 코드 내의 모든 제네릭 타입은 제거되어, 컴파일된 class 파일에는 어떠한 제네릭 타입도 포함되지 않게 된다.
제한
- 제네릭은 'T'와 같은 타입변수를 사용하여 타입을 제한한다.
- extends 키워드를 사용하여 타입변수에 특정 타입만을 사용하도록 제한할 수 있다.
- 클래스 내부에서 사용된 모든 타입변수에 제한이 걸린다.
class AnimalList<T extends LandAnimal> {
...
}
- 인터페이스를 구현할 경우에도 implements 키워드가 아닌 extends 키워드를 사용해야 한다.
interface WarmBlood {
...
}
...
class AnimalList<T extends WarmBlood> {
...
}
- 클래스와 인터페이스를 동시에 상속받고 구현해야 하면 엠퍼센트(&)를 사용하면 된다.
class AnimallList<T extends LandAnimal & WarmBlood> {
...
}
'내일배움캠프 > Java 기초' 카테고리의 다른 글
| 실수의 표현 방식 (0) | 2022.11.17 |
|---|---|
| 기본 자료형의 메모리 크기와 데이터 표현 범위 (0) | 2022.11.17 |
| 객체지향 (3) 추상클래스, 인터페이스 (0) | 2022.11.16 |
| 객체지향 (2) 상속, 접근제어자 (1) | 2022.11.15 |
| 객체지향 (1) 클래스, 인스턴스, 메소드, 생성자 (0) | 2022.11.15 |