[JAVA] 컬렉션 프레임워크 1 - List, Stack
안녕하세요. 이번 글은 컬렉션 프레임워크의 시작 List에 대한 설명입니다.
- 컬렉션 프레임워크란?
컬렉션 프레임워크 (Collection Framework)란 동일한 타입끼리 관리하는 자료구조인 컬렉션을 기반으로 객체를 효율적으로 관리 및 제어하기 위한 클래스 및 인터페이스들을 모아둔 집합체를 의미한다. 배열과 다른 점이 있다면 배열은 정적인 크기를 지닌 반면 컬렉션 프레임워크는 동적인 크기 변화가 가능하다는 점이다.
컬렉션 프레임워크는 상단의 구조도와 같이 Collection이라는 인터페이스를 기반으로 제작되었으며 각 자료구조 (List, Queue, Set)이 자식 인터페이스가 탄생됨을 바탕으로 이들을 각각 상속받아서 바로 적용가능한 ArrayList, Stack, HashSet 등의 클래스가 있다. 지금부터 List를 시작으로 가장 많이 쓰이는 클래스 위주로 천천히 살펴볼 전망이다. 나중에 쓰레드와 제너릭을 포스팅할 예정인데 이때에도 이들을 활용하여 설명할 예정이다.
- List 인터페이스 - ArrayList
List 컬렉션은 배열과 가장 유사한 구조를 지닌 자료구조다. 차이점은 동적인 크기이냐 정적인 크기이냐 단 하나뿐이다.
그 중에서 가장 많이 쓰이는 자료구조를 위주로 설명할텐데 그것은 바로 ArrayList이다.
List<String> list = new ArrayList<String>();
다음 코드는 List 자료구조를 사용하기 위한 객체를 생성하기 위한 소스코드이다. 먼저 <>안에는 어떤 데이터 형식을 저장할 것인지를 지정해주는 공간이다. 이 부분을 제너릭(Generic)이라고 하는데 지금은 안에 어떤 타입의 데이터를 저장할 것인지를 지정해줘야 하는 곳이라고만 생각하자.
List라는 것 자체가 인터페이스라서 이것만 가지고는 직접적으로 객체를 생성할 수는 없다. 그렇기 때문에 자료구조를 활용하려면 List 인터페이스를 상속받은 자식 클래스인 ArrayList의 생성자를 활용해서 객체를 생성해야 한다.
메서드명 | 설명 |
.add(E element) | 리스트의 맨 끝에 요소를 추가한다. |
.add(int index, E element) | 리스트의 인덱스 위치에 요소를 추가한다. |
.addAll(Collection <? extends E> c) | 매개변수로 된 특정 컬렉션 전체를 추가한다. |
.set(int index, E element) | 인덱스 위치의 데이터를 입력된 요소로 변경 |
.get(int index) | 특정 인덱스 위치에 있는 데이터 반환 |
.remove(int index) | 특정 인덱스 위치의 데이터를 삭제한다. |
.remove(Object o) | 데이터 값을 찾아서 삭제한다. |
.clear() | 리스트 내 모든 데이터를 삭제한다. |
.size() | 리스트의 데이터 갯수를 정수형으로 반환 |
.isEmpty() | 리스트가 빈 공간인지를 논리형으로 반환 |
다음은 List 자료구조에서 사용할 수 있는 메서드 목록이다. 전반적으로 추가, 수정, 삭제, 조회가 주요 메서드로 구성되어있는 점을 확인할 수 있다.
1) .add(), size()
package classes;
import java.util.*;
public class CFrame_List {
public static void main(String[] args) {
List<String> list = new ArrayList<String>();
list.add("JAVA");
list.add("Python");
list.add("C");
list.add("C++");
list.add("C#");
list.add("Haskell");
list.add("PHP");
list.add("JSP");
list.add("ASP");
list.add("HTML/CSS/JS");
System.out.println(list.size()); // 10
System.out.println(list); // [JAVA, Python, C, C++, C#, Haskell, PHP, JSP, ASP, HTML/CSS/JS]
list.add(6, "WEB : ");
System.out.println(list.size()); // 11
System.out.println(list); // [JAVA, Python, C, C++, C#, Haskell, WEB : , PHP, JSP, ASP, HTML/CSS/JS]
}
}
다음은 .add(E element), add(int index, E element), .size()을 실습하고 리스트 내 전체 목록을 출력하는 것을 실습한 코드이다. 실행 결과는 주석에 입력해두었다. 다음과 같이 add 메서드를 통해 리스트 내 맨 마지막에 요소를 추가할 수 있을 뿐만 아니라 특정 위치를 지정해서 데이터를 저장할 수 있음을 확인 가능하다. 이때 중간에 지정해서 저장하면 그 뒤에 있던 요소들은 하나씩 뒤로 밀려나가는 방식을 사용하고 있다.
2) .get(), .set()
package classes;
import java.util.*;
public class CFrame_List {
public static void main(String[] args) {
List<String> list = new ArrayList<String>();
list.add("JAVA");
list.add("Python");
list.add("C");
list.add("C++");
list.add("C#");
list.add("Haskell");
list.add("PHP");
list.add("JSP");
list.add("ASP");
list.add("HTML/CSS/JS");
System.out.println(list); // [JAVA, Python, C, C++, C#, Haskell, PHP, JSP, ASP, HTML/CSS/JS]
list.set(2, "C Language");
System.out.println(list); // [JAVA, Python, C Language, C++, C#, Haskell, PHP, JSP, ASP, HTML/CSS/JS]
System.out.println(list.get(0) + " " + list.get(5)); // JAVA Haskell
}
}
다음 소스코드를 통해 .get()을 통해 인덱스 위치 값으로 해당 위치에 있는 데이터가 무엇인지를 확인할 수 있으며 .set()을 통해 특정 인덱스 값의 데이터를 새로운 값으로 변경할 수 있다는 점도 확인 가능하다.
3) remove()
package classes;
import java.util.*;
public class CFrame_List {
public static void main(String[] args) {
List<String> list = new ArrayList<String>();
list.add("JAVA");
list.add("Python");
list.add("C");
list.add("C++");
list.add("C#");
list.add("Haskell");
list.add("PHP");
list.add("JSP");
list.add("ASP");
list.add("HTML/CSS/JS");
System.out.println(list.size()); // 10
System.out.println(list); // [JAVA, Python, C, C++, C#, Haskell, PHP, JSP, ASP, HTML/CSS/JS]
list.remove("C");
list.remove(5);
System.out.println(list.size()); // 8
System.out.println(list); // [JAVA, Python, C++, C#, PHP, JSP, ASP, HTML/CSS/JS]
}
}
다음 소스코드와 같이 .remove()를 통해 원하는 데이터를 삭제할 수 있다는 점을 알 수 있다. 이때 삭제하는 방법은 2가지로 되어있는데 하나는 소괄호 안에 요소의 데이터를 입력하는 방법인데 리스트 안에 해당되는 데이터가 있으면 삭제하는 방식이다. 다른 하나는 인덱스 값을 통해서 삭제하는 방법인데 배열처럼 지우고자 하는 인덱스 위치값을 지정해서 메서드를 실행하면 해당 위치의 데이터를 삭제할 수 있는 방식이다.
4) .clear(), isEmpty()
package classes;
import java.util.*;
public class CFrame_List {
public static void main(String[] args) {
List<String> list = new ArrayList<String>();
list.add("JAVA");
list.add("Python");
list.add("C");
list.add("C++");
list.add("C#");
list.add("Haskell");
list.add("PHP");
list.add("JSP");
list.add("ASP");
list.add("HTML/CSS/JS");
System.out.println(list.size()); // 10
System.out.println(list); // [JAVA, Python, C, C++, C#, Haskell, PHP, JSP, ASP, HTML/CSS/JS]
System.out.println(list.isEmpty()); // false
list.clear();
System.out.println(list); // []
System.out.println(list.isEmpty()); // true
}
}
다음 소스코드와 같이 .clear()를 통해 리스트 내의 데이터를 모두 삭제할 수 있다는 점을 확인할 수 있다. 이때 모두 삭제하기 전과 후를 비교하기 위해 .isEmpty() 메서드를 활용했다. .clear()를 사용하기 전에 .isEmpty()를 사용하면 빈 값이 아니라는 점에서 false가 출력되고 리스트 내 데이터를 모두 삭제하고 난 후 다시 사용하면 true인 점을 확인할 수 있다. true가 나왔다는 점은 곧 해당 리스트에 데이터가 하나도 없다는 뜻이다.
5) addAll()
package classes;
import java.util.*;
public class CFrame_List {
public static void main(String[] args) {
List<String> list = new ArrayList<String>();
list.add("JAVA");
list.add("Python");
list.add("C");
list.add("C++");
list.add("C#");
list.add("Haskell");
list.add("PHP");
list.add("JSP");
list.add("ASP");
list.add("HTML/CSS/JS");
List<String> list02 = new ArrayList<String>();
System.out.println(list02);
list02.addAll(list);
System.out.println(list02);
}
}
addAll()은 다른 리스트의 값을 모두 가져와서 자기 자신의 리스트에 추가하는 메서드이다. 상단의 소스코드를 통해 addAll() 메서드를 통해 다른 리스트의 데이터를 모두 순차적으로 적용할 수 있다는 점을 확인할 수 있다.
package classes;
import java.util.*;
public class CFrame_List {
public static void main(String[] args) {
List<String> list = new ArrayList<String>();
list.add("JAVA");
list.add("Python");
list.add("C");
list.add("C++");
list.add("C#");
list.add("Haskell");
list.add("PHP");
list.add("JSP");
list.add("ASP");
list.add("HTML/CSS/JS");
List<String> list02 = new ArrayList<String>();
list02.add("First");
list02.add("Second");
list02.add("Third");
list02.add("Fourth");
list02.add("Fifth");
System.out.println(list02); // [First, Second, Third, Fourth, Fifth]
list02.addAll(1, list);
System.out.println(list02); // [First, JAVA, Python, C, C++, C#, Haskell, PHP, JSP, ASP, HTML/CSS/JS, Second, Third, Fourth, Fifth]
}
}
또한 복사받고자 하는 리스트에 데이터가 이미 존재한다는 전제 하에 복사하고자 하는 인덱스 위치 값을 지정하고 그 자리에 그대로 추가할 수도 있다는 점을 상단 코드를 통해서 확인 가능하다.
- 요소와 요소가 연결고리가 있는 LinkedList
LinkedList는 List의 전반적인 모든 특징(메서드 내지 사용법 등등..)을 지니고 있으면서 ArrayList와 다르게 동기화를 진행하지 않는다는 점에서 싱글 쓰레드 (Thread)에서 사용하기 적합하다는 특징을 지니고 있다. 또한 객체를 생성할 때 먼저 저장 용량을 지정할 수 없다. 그리고 데이터를 저장할 때 인덱스 위치 값을 사용하지 않고 링크를 한다는 점에서 앞과 뒤의 객체에 대한 정보를 저장하면서 이들을 기반으로 데이터를 관리하는 것이 링크드 리스트이다.
다음과 같이 링크드 리스트는 앞 뒤의 요소에 대한 정보가 유기적으로 연결되는 방식으로 작동하는 자료구조인 점을 확인할 수 있다. 이때 링크드 리스트에서 자료를 추가, 삭제, 수정할 때는 앞서 말한 앞뒤 요소에 대한 정보를 끊어내고 새로운 정보를 연결해야 한다. 이는 어떻게 보면 일부분만 수정하는 것이 아닌 전체에 걸쳐서 정보를 수정해야 될 수도 있다.
이러한 점에서 단순히 데이터를 검색할 때는 인덱스 번호를 사용한다는 점에서 ArrayList가 속도가 빠르지만 데이터를 추가 및 삭제할 때는 링크드 리스트가 상대적으로 속도가 빠르다는 점을 확인할 수 있다.
+ Vector 클래스에 대한 설명
Vector는 전반적으로 List의 모든 특징을 가지고 있다. 차이점이 존재한다면 벡터는 동기화가 구현되어있다는 점에서 멀티 쓰레드에서 사용하기 적합하다는 점이 있다. 이때 동기화 메서드는 하나의 객체를 두 개 이상의 쓰레드가 사용할 수 없도록 되어있는 메서드를 의미한다. 만약 이러한 점이 존재하지 않는다면 한 곳에서 수정하면 다른 쪽에서는 추가 내지 삭제같은 다른 작업을 동시에 하게 될 때 데이터의 불일치와 충돌이 발생할 수 있다.
- 층층이 쌓다. Stack
Stack 자료구조란 말 그대로 쌓는 방식의 자료구조이다. 후입선출(LIFO)을 원칙으로 하는 자료구조이다.
이때 LIFO란 Last in First Out의 약자로서 나중에 입력된 데이터가 제일 먼저 출력되는 방식을 의미한다.
다음과 같이 스택은 층층이 탑 쌓듯이 데이터를 적재하는 방식이며 맨 밑에 있는 것 또는 중간에 끼어있는 것부터 먼저 꺼낼 수 없는 구조인 점을 확인할 수 있다. push와 pop 메서드를 통해 최근 요소를 맨 위에 쌓고 제일 위에 있는 요소를 빼낼 수 있는 자료구조가 스택이다.
메서드 | 설명 |
push(E item) | item을 스택에 추가 (데이터의 갯수 증가) |
pop() | 최상위 요소 추출 (데이터의 갯수 감소) |
emtpy() | 해당 스택 객체가 비어있는지를 확인 (boolean 반환형) |
peek() | 스택 객체 내 최상위 데이터 리턴 |
search(Object o) | 스택 내 요소의 위치값 반환 |
상단의 표는 Stack 자료구조의 메서드이다.
package classes;
import java.util.*;
public class CFrame_List {
public static void main(String[] args) {
Stack<String> stacking = new Stack<String>();
stacking.push("First");
stacking.push("Second");
stacking.push("Third");
System.out.println(stacking.size()); // 3
System.out.println(stacking); // [First, Second, Third]
System.out.println(stacking.peek()); // Third
System.out.println(stacking.search("Second")); // 2
stacking.pop();
System.out.println(stacking); // [First, Second]
System.out.println(stacking.empty()); // False
stacking.pop();
System.out.println(stacking); // [First]
stacking.pop();
System.out.println(stacking); // []
System.out.println(stacking.empty()); // trur
}
}
상단의 소스코드는 Stack이라는 자료구조를 실습한 것이다. push(), pop(), peek(), empty(), search() 메서드들을 사용하면서 제대로 작동되는지를 출력문을 통해 검증하는 과정이 존재한다는 점 또한 확인 가능하다.
다음 글은 컬렉션 프레임워크의 두 번째 시리즈인 Set에 대한 설명입니다. 감사합니다.