이번 글에선 컬렉션 프레임워크에 대해서 정리해보려고 한다. 컬렉션 프레임워크는 프로그래밍에 있어서 필수불가결한 요소라고 생각한다.
저번에 설명한 스트림도 컬렉션을 활용할 수 있는 것이고, 기본적으로 배열같은 데이터는
실무에서나, 혼자 코딩할 때나, 코딩테스트를 할 때도 거의 항상 들어가기 때문이다.
그렇기에 더 자세히 이해하고 활용할 수 있어야겠다는 생각을 하게 되었다. 그렇다면 한번 시작해보자.
일단 컬렉션에 대해 설명하기 전에 사진을 보며 종류에 대해서 살펴보자.
컬렉션 프레임워크는 인터페이스로 구현되어있다.
그 인터페이스(컬렉션)으로 구현되어있는 것들이 List, Set, Map인데 이 컬렉션 인터페이스들을 통해 구현한 것들(ArrayList, HashMap 등)을
컬렉션 클래스라고 불린다.
각 인터페이스들의 특징들에 대해서 살펴보자.
List
List<E> - 순서가 있는 데이터의 집합으로, 중복을 허용한다.
종류 : ArrayList, Vector, LinkedList, (Stack, Queue) = 자료구조 등
Set
Set<E> - 순서가 없는 데이터의 집합으로, 중복을 허용하지 않는다.
종류 : HashSet, TreeSet 등
Map
Map<K, V> - Key와 Value의 한 쌍으로 이루어진 데이터의 집합으로 순서가 없다. Key는 중복이 불가능하지만 Value는 중복이 가능하다.
종류 : HashMap, TreeMap, Hashtable, Properties
이런 식으로 이루어져있다.
옛날부터 있던걸 사용하는 것 보다는 주로 새로 추가된 ArrayList와 HashMap을 사용하는게 좋다고 한다.
이러한 컬렉션 클래스들은 컬렉션에서 제공하는 주요 메소드들을 사용할 수 있다.
아래 코드를 주로 설명할 것이다.
List list = new ArrayList<>(); // 선언
// 밑에 예제가 들어갈 자리
list.stream().forEach(System.out::println); // 출력
*** List list = new ArrayList(); 로 선언하는 이유에 대해서 ***
이는 자바의 다형성에 관한 얘기인데, 이렇게 선언해서 사용하는 경우 후에 클래스를 바꿀 때 용이하기 때문이다.
같은 인터페이스를 상속받기에 교체도 쉽다는 것이다.
add() - 해당 컬렉션에 해당 요소를 추가함
list.add("abc");
list.add("def");
list.add("ghi");
clear() - 해당 컬렉션에 해당 요소를 제거함
list.clear();
contains() - 해당 컬렉션에 해당 객체를 포함하고 있는지를 확인함
list.contains("abc");
equals() - 해당 컬렉션과 해당 객체가 같은지를 확인함
list.equals(list);
isEmpty() - 해당 컬렉션이 비어있는지를 확인함
list.isEmpty();
iterator() - 해당 컬렉션의 이터레이터(반복자)를 반환함
list.iterator();
remove() - 해당 컬렉션에서 해당 객체를 제거함
list.remove("abc");
list.remove(0);
size() - 해당 컬렉션 요소의 총 개수를 반환함
list.size();
toArray() - 해당 컬렉션의 모든 요소를 Object 타입의 배열로 반환함
list.toArray();
위에 기능들을 컬렉션 클래스에서 공통적으로 사용하기위해 컬렉션 인터페이스로 상속받아서 사용하는 것이다.
그러면 다음으로는 컬렉션 클래스들의 메소드들과 쓰임새를 살펴보겠다. (정리한 메소드는 간략 작성만 하겠다.)
List
list는 우리가 흔히 사용하는 순차적이고 중복을 허용하는 배열이다.
값을 넣음으로써 인덱스가 붙고 그것을 활용해 여러가지 기능을 만들 수 있다.
ArrayList
arraylist는 배열의 크기가 가변적으로 변하는 배열이다.
밑에서 소개할 vector 보다 속도가 빠르기에 더 많이 사용되기도 한다.
우리가 흔히 접할 수 있으며, 그만큼 많이 사용되는 것이기에 제대로 다룰 줄 알아야 될 것이다.
add(), remove(), contains(), toArray(), clear(), isEmpty(), size() (설명 생략)
get() - 인덱스를 제공하면 해당 값을 반환한다.
list.get(0);
set() - 인덱스와 바꿀 값을 제공하면 값을 바꿔준다.
list.set(0, "a");
indexOf(), lastIndexOf() - 값을 제공하면 해당 값의 인덱스를 제공, last는 끝에서 검색 (값은 같다)
list.indexOf("abc"); list.lastIndexOf("abc");
addAll() - 두 컬렉션을 합침
List addlist = new ArrayList<>();
addlist.add("jkl");
addlist.add("mno");
addlist.add("pqr");
list.addAll(addlist);
containsAll() - 해당 컬렉션 안에 모든 요소가 포함되어 있는지 여부를 확인
list.containsAll(addlist); // 위에 addAll을 실행했다면 true, 아니라면 false
Vector
vector 도 arraylist와 비슷한 가변 배열이다.
vector는 동기화된 메소드로 구성되어 있어 여러 스레드에서 동시에 사용하지 못하고,
한 곳에서 작업을 끝내야 작업을 할 수 있기에,멀티 스레드 환경에서 안정적이라는 장점이 있다.
add(), get(), set(), toArray(), clear(), remove(), size() (설명 생략)
// add 와 addElement, get 과 elementAt, set 과 setElement 는 같은 역할을 하므로 따로 정리하지 않음
벡터 생성 후 값은 똑같이 넣는다.
Vector list = new Vector(); // 이하 생략
firstElement(), lastElement() - 첫번째 값과 마지막 값을 반환한다.
System.out.println(list.firstElement());
System.out.println(list.lastElement());
capacity() - 현재 배열의 크기 반환
( size와는 다르다는 것을 알아야한다. 배열을 10으로 생성한뒤 값을 3개만 넣은 상태라면 capacity는 10, size는 3이다. )
System.out.println(list.capacity());
trimToSize() - 배열에 저장된 값의 갯수 만큼 배열 크기를 줄임
( 위에 내용을 예로들면 trimToSize를 사용했을 때 배열의 크기는 3으로 줄어든다.)
list.trimTosize();
LinkedList
위에서 설명한 두 List는 순서대로 나열되어 있다고한다면, LinkedList는 주소와 데이터가 연결되어 있는 구조이다.
그렇기에 적은 횟수와 순차적으로 탐색을 할 시에는 Arraylist가 유리하지만,
그렇지않고 많은 탐색과 중간에서의 탐색이 필요할 시에는 LinkedList를 사용하는게 좋다.
add(), get(), set() (설명 생략)
링크드리스트 생성 후 값은 똑같이 넣는다.
LinkedList list = new LinkedList<>(); // 이하 생략
push(), addFirst() / addLast() - 앞쪽에 값 추가 / 뒤쪽에 값 추가
list.addFirst("abc");
list.push("def");
list.addLast("ghi");
element(), getFirst(), peek(), peekFirst() / getLast(), peekLast() - 첫번째 값 추출 / 마지막 값 추출
System.out.println(list.element()); System.out.println(list.getFirst());
System.out.println(list.peek()); System.out.println(list.peekfirst());
///////////////////////////////////////////////////////////////
System.out.println(list.getLast()); System.out.println(list.peekLast());
pop(), poll(), pollFirst() / pollLast() - 첫번째 값 추출 후 삭제 / 마지막 값 추출 후 삭제
System.out.println(list.pop()); System.out.println(list.poll()); System.out.println(list.pollFirst());
////////////////////////////////////////////////////////////////////////////////////////////////////////
System.out.println(list.pollLast());
removeFirst() / removeLast() - 첫번째 값 삭제 / 마지막 값 삭제
list.removeFirst();
list.removeLast();
removeFirstOccurrence() / removeLastOccurrence() - 첫번째 부터 검색해서 해당요소를 삭제 / 마지막 부터 검색해서 해당요소를 삭제
list.removeFirstOccurrence("abc");
System.out.println(list);
list.removeLastOccurrence("def");
System.out.println(list);
Set
set은 많이 사용해보지는 않았지만 List와 정반대라고 생각하면 된다.
순서가 없으며, 중복을 허용하지 않는 set은 map과 더 비슷한 느낌이다.
set은 중복 제거가 필요할 때 빛을 발한다.
HashSet
hashSet은 컬렉션 프레임워크 중 가장 빠른 속도를 가지고 있다
add(), remove(), contains(), clear(), remove()(설명 생략)
HashSet set = new HashSet(); // 이하 생략
addAll() - List 에서 설명했던 내용과 같지만 중복이 있다면 무시하고 추가하는 기능 때문에 작성해 보았다.
HashSet addset = new HashSet();
addset.add("abc");
addset.add("mno");
addset.add("pqr");
set.addAll(addset);
removeAll() - 위에서 설명했던 clear()와 같은 역할을 한다.
set.removeAll();
TreeSet
treeSet은 hashSet과 다르게 자동으로 정렬을 해준다.
add()(설명 생략)
TreeSet set = new TreeSet(); // 이하 생략
first() / last() - 가장 큰값과 가장 작은 값을 출력(
set.first();
set.last();
lower() - 제공된 값보다 작은 값 중에 가장 큰 값 / higher() - 제공된 값보다 큰 값 중에 가장 작은 값 (인자 값 미포함)
floor() - 제공된 값과 같거나 작은 값 중 가장 큰 값 / ceiling() - 제공된 값과 같거나 큰 값 중 가장 작은 값 (인자 값 포함)
set.lower("d"); // abc
set.higher("d"); // def
set.floor("def"); // def
set.ceiling("def"); // def
pollFirst() / pollLast() - 가장 작은 값을 반환 후 삭제 / 가장 큰 값을 반환 후 삭제
set.pollFirst();
set.pollLast();
Map
Key-Value 방식을 사용하는 인터페이스이다.
다른 컬렉션 클래스들과는 다른 특징을 가지고 있다.
HashMap, HashTable (HashTable은 HashMap의 구버전 격인 기능이기에 같이 정리함)
hashmap 또한 arraylist 처럼 많이 사용되고 활용된다.
해싱 기법을 사용해 데이터를 저장 및 분류한다.
*** 해싱이란, key 값에 직접 산술적인 연산을 적용해서 항목이 저장되어 있는 값에 접근하는 것이다. ***
get(), remove(), clear(설명 생략)
HashMap map = new HashMap(); // 생성
put(K, V) - K(Key, 키 값)와 V(Value, 값)을 입력해 값을 넣을 수 있다.
map.put("a", "abc");
map.put("b", "def");
map.put("c", "ghi");
keySet() / values() - 키 값과 값들을 별도 추출해서 컬렉션 형태로 반환한다.
System.out.println(map.keySet());
System.out.println(map.values());
replace() - 키 값과 바꿀 값을 제공하면 해당 키의 값을 바꿔준다.
map.replace("3", "ghi", "gh");
containsKey() / containsValue() - 해당하는 키값이나 값이 포함되어 있는지의 여부를 확인한다.
map.containsKey("1");
map.containsValue("abc");
TreeMap
트리구조로 데이터를 저장 및 분류한다.
***트리구조? - 한 노드(데이터)와 다른 노드의 이어지는 길이 하나밖에 없는 구조인데,
마치 이게 이어져서 나무 처럼 생겨서 트리 구조라고 불린다.
put(), keySet() (설명 생략)
TreeMap map = new Treemap(); // 이하 생략
*** 여기서 나오는 Entry는 키와 값을 저장하고있는 map의 내부 클래스이다. (ex 1=abc)
ceilingEntry(), ceilingKey() : 제공된 키값과 같거나 큰 값 중 가장 작은 키 값의 Entry나 키값을 반환
floorEntry(), floorKey() : 제공된 키값과 같거나 작은 값 중 가장 큰 키 값의 Entry나 키값을 반환
map.ceilingEntry("2"); // 2=def
map.ceilingKey("0"); // 1
map.floorEntry("3"); // 3=ghi
map.floorKey("3"); // 3
higherEntry(), higherKey() :제공된 키값과 큰 값 중 가장 작은 키 값의 Entry나 키값을 반환
lowerEntry(), lowerKey() : 제공된 키값과 작은 값 중 가장 큰 키 값의 Entry나 키값을 반환
map.higherEntry("2"); // 3=ghi
map.higherKey("0"); // 1
map.lowerEntry("3"); // 2=def
map.lowerKey("3"); // 2
entrySet() - Entry로 안에 내용들을 컬렉션으로 반환
System.out.println(map.entrySet());
firstEntry(), firstKey() - map 내에서 가장 큰 키값을 Entry나 Key 로 반환
lastEntry(), lastKey() - map 내에서 가장 작은 키값을 Entry나 Key로 반환
System.out.println(map.firstEntry()); System.out.println(map.firstKey());
System.out.println(map.lastEntry()); System.out.println(map.lastKey());
pollFirstEntry() / pollLastEntry() - map 내에서 가장 큰/작은 값을 Entry로 반환 후 삭제
map.pollFirstEntry();
map.pollLastEntry();
headMap() - 제공된 키보다 작은 키 값의 Entry를 SortedMap에 담아 반환
map.headMap("2");
tailMap() - 제공된 키보다 크거나 같은 값의 Entry를 SortedMap에 담아 반환
map.headMap("2");
Properties
*** Map 형식으로 된 .properties 나 .xml 파일이다.
전에 정리 했었던 Enum 또는 지금 설명하고 있는 map의 파일 버전이라고 생각하면된다. 주로 DB의 연결정보 등을 저장해두는 용도로 쓰인다.
생성해보기
File path = new File("C:\\공부\\JAVA\\test.properties"); // 파일 경로는 원하는 위치로 하기를 바란다.
try (FileWriter file = new FileWriter(path)){
Properties p = new Properties();
p.setProperty("1", "abc");
p.setProperty("2", "def");
p.setProperty("3", "ghi");
p.store(file, "test");
} catch (Exception e) {
//TODO: handle exception
}
결과 값 - test.properties
#test
#Mon May 24 20:35:44 KST 2021
1=abc
2=def
3=ghi
위에서 Entry를 출력했을 때 처럼 저장되는 것을 볼 수 있다.
다음으로는 읽어보는 방법을 알아보겠다.
읽어와보기
File path = new File("C:\\공부\\JAVA\\test.properties");
try (FileReader file = new FileReader(path)){
Properties p = new Properties();
p.load(file);
System.out.println(p.getProperty("1", "2"));
System.out.println(p.getProperty("2"));
System.out.println(p.getProperty("3"));
} catch (Exception e) {
//TODO: handle exception
}
결과 값 -
abc
def
ghi
이렇게 컬렉션 프레임워크에 있는 공통적인 메소드와 각 컬렉션 클래스들의 메소드를 살펴보면서 쓰임새 등을 살펴보았다.
어떤 상황에서 적절하게 사용해야할지 더 감이 잡힌 느낌이고, 이전에 정리한 stream이나 lambda를 이용한 코드를 짜보고 싶어졌다.
이번 정리글은 아래 페이지에서 정리한 내용을 중심으로 직접 실행해보면서 정리해 본 건데, 부족했던 지식을 채울 수 있었던 거 같다.
아직 부족한 부분이 많은 거 같지만 직접 활용해보는게 좋을 것 같아서 이제는 Spring으로 넘어가려고한다.
Spring을 공부하면서 알게된 내용들은 오늘의 공부에 정리할 것 같다.
앞으로도 꾸준히 공부해야겠다.
참고 :
'언어 > Java' 카테고리의 다른 글
[Java] 가변인자 ... 표현 (0) | 2022.03.20 |
---|---|
[Java] Static import (0) | 2022.03.20 |
[Java] - Lambda 표현식과 Stream (0) | 2022.03.20 |
[Java] 자바 프로그램의 구조 (0) | 2022.03.20 |
[Java] - 자바란? (0) | 2022.03.20 |