
데이터 군을 저장하는 클래스들을 표준화한 설계
즉 다수의 데이터를 다루는데 필요한 다양한 클래스 제공
ex)ArrayList, HashSet ...
출처 : https://kevinntech.tistory.com/16

인터페이스 List와 Set의 공통된 부분이 인터페이스인 Collection


중복을 허용하면서 저장순서가 유지되는 컬렉션을 구현하는 데 사용


저장순서가 유지되지 않는 컬렉션 클래스를 구현하는데 사용


키와 값을 하나의 쌍으로 묶어서 저장하는 컬렉션 클래스 구현에 사용

저장 순서를 유지해야 하는 경우, Map인터페이스의 구현체 중 LinkedHashMap 사용

값 중복 허용하기에 values()는 Collection 반환
키의 중복을 허용하지 않기에 KeySet()는 Set 반환
기존의 Vector에서 원리와 기능적인 부분에서 개선 된 것'
Object배열(모든 종류의 객체를 담을 수 있음)을 이용해서 데이터를 순차적으로 저장
활용 예시
package ch11;
import java.util.ArrayList;
import java.util.Collections;
public class Ex11_1
{
public static void main(String[] args)
{
//사이즈 지정하여 ArrayList 생성
ArrayList list1 = new ArrayList(10);
//컴파일러가 AutoBoxing에 의해 기본형을 참조형으로 변환
// add(5) -> add(new Integer(5));
list1.add(new Integer(5));
list1.add(new Integer(4));
list1.add(new Integer(2));
list1.add(new Integer(0));
list1.add(new Integer(1));
list1.add(new Integer(3));
// ArrayList(Collection c)
ArrayList list2 = new ArrayList(list1.subList(1, 4));
print(list1, list2);
//Collections 클래스
Collections.sort(list1);
Collections.sort(list2);
print(list1,list2);
System.out.println("list1.containsAll(list2):" + list1.containsAll(list2));
list2.add("B");
list2.add("C");
list2.add(3,"A");
print(list1, list2);
list2.set(3, "AA"); // 변경
print(list1, list2);
// 겹치는 부분만 남기고 나머지 삭제
System.out.println("list1.retainAll(list2):" + list1.retainAll(list2));
print(list1,list2);
// list2에서 list1에 포함된 객체들을 삭제
for(int i = list2.size() -1; i >= 0; i--)
{
if(list1.contains(list2.get(i)))
list2.remove(i);
}
print(list1,list2);
}
static void print(ArrayList list1, ArrayList list2)
{
System.out.println("list1:"+list1);
System.out.println("list2:"+list2);
System.out.println();
}
}
list1:[5, 4, 2, 0, 1, 3]
list2:[4, 2, 0]
list1:[0, 1, 2, 3, 4, 5]
list2:[0, 2, 4]
list1.containsAll(list2):true
list1:[0, 1, 2, 3, 4, 5]
list2:[0, 2, 4, A, B, C]
list1:[0, 1, 2, 3, 4, 5]
list2:[0, 2, 4, AA, B, C]
list1.retainAll(list2):true
list1:[0, 2, 4]
list2:[0, 2, 4, AA, B, C]
list1:[0, 2, 4]
list2:[AA, B, C]
ArrayList에 제거된 data[2]를 삭제하는 경우
list.remove(2) 호출

삭제할 데이터의 아래에 있는 데이터를 한 칸 씩 위로 복사해서 삭제할 데이터 덮음
데이터가 모두 한칸 씩 위로 이동한 후, 마지막 데이터 null로 변경
데이터가 삭제되어 데이터 갯수가 줄었음으로 size 1 감소

배열의 중간에 객체를 추가하거나 삭제하는 경우 작업 시간 오래 걸림
배열의 구조가 간단하고 데이터를 읽는 시간(Access time)이 짧다
배열을 한번 생성하면 크기를 변경할 수 없다
-> 변경 시 새로운 배열 생성 후 데이터를 복사한 후, 참조를 변경해야 함
배열의 중간에 값을 추가 또는 삭제하는 경우 오래 걸림
-> 데이터 추가,삭제 시 다른 데이터를 복사해서 이동시켜야함
순자적인 데이터 추가(끝에 추가) + 삭제(끝부터 삭제)는 빠르다
이러한 배열의 단점을 보완하기 위해 나타난 자료구조 -> LinkedList
불 연속적으로 존재하는 데이터 서로 연결

하지만 첫 노드 부터 접근해야 하기에 데이터의 접근성이 나쁘다!
이동 방향이 단방향이기 때문에 다음 요소에 대한 접근은 쉽지만 이전 요소에 대한 `접근 어렵'

참조 변수를 하나 더 추가하여 다음 요소에 대한 참조 + 이전 요소 참조
Java의 LinkedList는 이중 연결 리스트로 구현

이중 연결 리스트의 첫번째 요소와 마지막 요소를 연결시켜 접근성 향상

순차적으로 데이터 추가/삭제 -> ArrayList가 빠름
비순차적 데이터 추가/삭제 -> LinkedList가 빠름
데이터 접근 -> ArrayList가 빠름
배열의 접근 시간
인덱스 n의 데이터 주소 = 배열의 주소 + n * 데이터 타입의 크기

LIFO(Last in First Out)
위와 같이 0,1,2 순서로 넣었다면 꺼낼땐 2,1,0 순서로 꺼내게 된다
수식계산, 수식 괄호 검사, 워드프로세서의 undo/redo, 웹브라우저의 앞/뒤로

FIFO(First In First Out)
최근 사용 문서, 인쇄작업 대기 목록, 버퍼(buffer)
순차적으로 데이터 추가 삭제할 때(Stack)는 ArrayList가 적합
삭제 시 처음 데이터를 삭제하는 경우(Queue)는 LinkedList가 적합
Queue는 인터페이스라서 구현한 클래스를 사용하면 됨!
import java.util.*;
public class Ex11_2 {
public static void main(String[] args) {
Stack st = new Stack();
Queue q = new LinkedList(); // Queue인터페이스의 구현체는 LinkedList 사용
st.push("0");
st.push("1");
st.push("2");
q.offer("0");
q.offer("1");
q.offer("2");
System.out.println(" =stack=");
while(!st.empty())
{
System.out.println(st.pop()); // 요소 하나씩 출
}
System.out.println(" = Queue = ");
while(!q.isEmpty())
{
System.out.println(q.poll());
}
}
}
=stack=
2
1
0
= Queue =
0
1
2
인터페이스 구현한 클래스를 찾을 때는 Java API 문서에서
All Known Implementing Classes 항목 참고
unix의 history 명령어 Queue로 구현
package ch11;
import java.util.*;
public class Ex11_4 {
static Queue q = new LinkedList();
static final int MAX_SIZE = 5; // Queue에 최대 5개만 저장되도록
public static void main(String[] args) {
System.out.println("help를 입력하면 도움말을 볼 수 있습니다.");
while(true)
{
System.out.print(">>");
try
{
// 화면으로 부터 라인단위 입력 받음
Scanner s = new Scanner(System.in);
String input = s.nextLine().trim();
if ("".equals(input)) continue;
if(input.equalsIgnoreCase("q"))
{
System.exit(0);
}else if(input.equalsIgnoreCase("help")) {
System.out.println(" help - 도움말을 보여줍니다.");
System.out.println(" q또는 Q - 프로그램을 종료합니다.");
System.out.println(" history - 최근 입력한 명령어를 " + MAX_SIZE + "개 보여줍니다.");
} else if(input.equalsIgnoreCase("history")) {
int i = 0;
// 입력받은 명령어를 저장
save(input);
//LinkedList의 내용을 보여줌
LinkedList tmp = (LinkedList) q;
ListIterator it = tmp.listIterator();
while(it.hasNext())
System.out.println(++i+"." + it.next());
} else {
save(input);
System.out.println(input);
} }catch (Exception e) {
System.out.println("입력오류입니다. ");
}
}
}
public static void save(String input)
{
//queue에 저장
if(!"".equals(input))
q.offer(input);
if(q.size() > MAX_SIZE)
q.remove();
}
}
Iterator, ListIterator, Enumeration 모두 컬렉션에 저장된 요소를 접근하는데 사용되는 인터페이스
컬렉션에 저장된 요소들을 읽어오는 방법 표준화 (각각의 자료구조가 다르기에!)
Iterator : 컬렉션 요소 접근
ListIterator : Iterator의 양방향 조회 기능 추가
Enumeration : Iterator 구버젼
Iterator는 Collection 인터페이스에 정의 된 메서드이며, List,Set 인터페이스를 구현하는 컬렉션은 iterator()가 특성에 맞게 작성되어 있음
package ch11;
import java.util.*;
public class Ex11_5 {
public static void main(String[] args) {
ArrayList list = new ArrayList();
list.add("1");
list.add("2");
list.add("3");
list.add("4");
list.add("5");
// Iterator는 1회용이라 한번 쓰면 다시 호출해야함!
Iterator it = list.iterator();
while(it.hasNext())
{
Object obj = it.next();
System.out.println(obj);
}
// list요소를 읽어 올때는 for문 또는 list.get(i)를 통해 모든 요소를 출력할 수도 있다.
}
}
Map에는 Iterator -> X , keySet() + entrySet() + values()와 같은 메서드 사용해야 함
여기서 entry는 <K,V> 형태
Map map = new HashMap();
...
Iterator it = map.entrySet().Iterator();
// 위 문장은 밑 두문장을 하나로 합친것
Set eSet = map.entrySet();
Iterator it = eSet.Iterator();
배열을 다루는데 유용한 메서드(모두 static)
static String toString(boolean[] a)
static String toString(byte[] a)
static String toString(char[] a)
static String toString(short[] a)
static String toString(int[] a)
static String toString(long[] a)
static String toString(double[] a)
static String toString(Object[] a)
copyOf()는 배열 전체, copyOfRange()는 배열 일부
int[] arr = {0,1,2,3,4};
int[] arr2 = Arrays.copyOf(arr, arr.length); // arr2 = [0,1,2,3,4]
int[] arr3 = Arrays.copyOf(arr, 3); // arr3 = [0,1,2]
int[] arr4 = Arrays.copyOf(arr, 7); // arr4 = [0,1,2,3,4,0,0]
int[] arr5 = Arrays.copyOfRange(arr, 2, 4); // arr5 = [2,3]
int[] arr6 = Arrays.copyOfRange(arr, 0, 7); // arr6 = [0,1,2,3,4,0,0]
fill()은 배열의 모든 요소를 지정된 값으로 채운다.
setAll() 배열을 채우는데 사용할 함수형 인터페이스를 매개변수로 받는다.
이 메서드를 호출할 때는 함수형 인터페이스를 구현한 객체를 매개변수로 지정하던가 아니면 람다식을 지정해야한다.
int [] arr = new int[5];
Arrays.fill(arr,9); // arr = [9,9,9,9,9]
Arrays.setAll(arr, (i) -> (int)(Math.random()*5)+1); //arr=[1,5,2,1,1]
sort()는 배열을 정렬할 때
binarySearch()는 배열에 저장된 요소를 검색
이진 검색은 배열의 검색할 범위를 반복적으로 절반으로 줄여 나가기에 검색속도가 빠르다
binarySearch()는 배열에서 지정된 값이 저장된 위치(index)를 찾아서 반환하는데, 반드시 배열이 정렬된 상태이어야 올바른 결과를 얻는다.
만일 검색한 값과 일치하는 요소들이 여러 개 있다면, 이 중에서 어떤 것의 위치가 반환될지는 알 수 없다.
int [] arr = {3,2,0,1,4};
int idx = Arrays.binarySearch(arr,2); // idx = -5 <-- 잘못된 결과
Arrays.sort(arr); // 배열 arr을 정렬한다.
System.out.println(Arrays.toString(arr)); // [0,1,2,3,4]
int idx = Arrays.binarySearch(arr, 2); // idx=2 <-- 올바른 결과
toString()배열의 모든 요소를 문자열로 편하게 출력할 수 있다(일차원 배열에만 사용)
deepToString() 다차원 배열에 사용
2차원뿐만 아니라 3차원 이상의 배열에도 동작
int [] arr = {0,1,2,3,4};
int[][] arr2D = {{11,12}, {21,22}};
System.out.println(Arrays.toString(arr)); // [0,1,2,3,4]
System.out.println(Arrays.deepToString(arr2D)); // [[11,12],[21,22]]
String[][] str2D = new String[][]{{"aaa","bbb"},{"AAA","BBB"}};
String[][] str2D2 = new String[][]{{"aaa","bbb"},{"AAA","BBB"}};
// equals()로 비교 시 문자열을 비교하는 것이 아니라 배열의 주소를 비교
System.out.println(Arrays.equals(str2D, str2D2)); // false
System.out.println(Arrays.deepEquals(str2D, str2D2); // true
List list = Arrays.asList(new Integer[]{1,2,3,4,5}); // list =[1,2,3,4,5]
List list = Arrays.asList(1,2,3,4,5); // lsit =[1,2,3,4,5]
list.add(6); // UnsupportedOperationException 예외 발생
asList()가 반환한 List의 크기를 변경할 수 없다는 것
추가 또는 삭제가 불가능하다.
저장된 내용은 변경가능
List list = new ArrayList(Arrays.asList(1,2,3,4,5));