Java에서 컬렉션은 배열보다 다수의 참조형 데이터를 더 쉽게 효과적으로 처리할 수 있는 기능을 많이 가지고 있습니다.
크기 자동조정/ 추가/ 수정/ 삭제/ 반복/ 순회/ 필터/ 포함확인 등...
List, Set, Queue, Map
Collection은 기본형 변수가 아닌 참조형 변수를 저장
순서가 있는 데이터의 집합
Array는 최초의 길이를 알아야하지만 List는 처음에 길이를 몰라도 만들 수 있다.
Array vs List(ArrayList)
1. Array: 정적배열
2. List(ArrayList): 동적배열(크기가 가변적으로 늘어난다)
- 생성 시점에 작은 연속된 공간을 요청해서 참조형 변수들을 담아 놓는다.
- 값이 추가될 때 더 큰 공간이 필요하면 더 큰 공간을 받아서 저장하니깐 상관없다.
ArrayList<Integer> intList = new ArrayList<Integer>(); // 선언 + 생성
/* 추가 */
intList.add(99);
intList.add(15);
System.out.println(intList.get(1)) // 첫번쨰 list를 출력
/* 수정 */
intList.set(1,10); // 2번째 있는 15를 10으로 바꾸기
System.out.println(intList.get(1)) // 첫번쨰 list를 출력
/* 삭제 */
intList.remove(0)
System.out.println(intList.get(0)) // 0번쨰 list를 출력
// 출력값:
// 15
// 10
// 15
/* 클리어 */
intList.clear();
ArrayList intList = new ArrayList();
여기서 Integer 참조 변수를 사용해야한다!!!
메모리에 남는 공간을 요청해서 여기 저기 나누어서 실제 값을 담기
실제 값이 있는 주소값으로 목록을 구성하고 저장하는 자료구조.
기본적인 기능은 동일하지만
LinkedList 값은 나누어져 있어서 조회하는 속도가 "느리다"
But 값을 추가하거나, 삭제할 떄는 ArrayList보다 "빠르다"
스택은 수직으로 값을 쌓아놓고, 넣었다가 빼는 자료구조이다.
FILO(First In Last Out)인셈이다.
주된 기능은 push,pop,peek,isEmpty이 있다.
스택은 주로 최근 저장된 데이터를 나열하고 싶거나, 데이터의 중복 처리를 막고 싶을 떄 사용한다.
Stack<Integer> intStack = new Stack<Integer>();
intStack.push(10);
intStack.push(3);
// 다 지워질 때 까지 출력
while(!intStack.isEmpty()) {
System.out.println(intStack.pop());
}
peek()는 C++에 top()이랑 같은거다 가장 위에 있는 데이터를 보여준다
FIFO(Frist In First Out)
add,peek,poll(꺼낸다),isEmpty,size 기능이 있다
Queue는 생성자가 없는 인터페이스이라서
생성자가 없는 인터페이스는 new 연산자로 생성을 할 수 없어서 대신 LinkedList<>()를 써서 생성을 한다.
Queue<Integer> intQueue = new LinkedList<>(); // queue를 생성, 선언
intQueue.add(10);
intQueue.add(3);
// 다 지워질 때 까지 출력
while(!intQueue.isEmpty()) {
System.out.println(intQueue.poll());
}
순서가 없고, 중복 없음
Set는 그냥 쓸순 있지만, HashSet, TreeSet등으로 응용해서 같이 사용 가능
Set은 생성자가 없는 껍대기라서 바로 생성할 수 없음 그래서 생성자가 존재하는 HashSet를 이용
Set<Integer> intSet = new HashSet<>();
intSet.add(1);
intSet.add(12);
intSet.add(31);
intSet.add(10);
for(int i : intSet) {
System.out.println(i); // 1 10 12 31
}
만약에 정렬이 안되는 Set을 사용하고 싶으면
Set<Integer> intSet = new LinkedHashSet<>();
위에 있는 LinkedHashSet을 사용하면 된다!
intSet.contains(2) // true/false 반환
만약에 intSet안에 2가 있으면 true를 반환한다.
key - value (pair)
key라는 값으로 유니크하게 보장이 돼야 한다
Map -> HashMap, TreeMap으로 응용
Map<String, Integer> intMap = new HashMap<>();
intMap.put("일", 11);
intMap.put("이", 12);
intMap.put("삼", 13);
intMap.put("삼", 14); // 중복 key
intMap.put("삼", 15); // 중복 key
Map은 key값이 중요해서 중복을 허용을 안 한다.
그래서 위에 삼,삼,삼 key가 겹치는 상황이 올 수 있다
for(String key: intMap.keySet()) {
System.out.println(key); // 이 일 삼
}
그렇기 떄문에 key를 for문으로 돌리면
이, 일, 삼이 나오는 걸 알수있다.
그런데 어떤 value가 지워졌는지 알수 없으니 for으로 value도 출력해보자
for(Integer value: intMap.values()) {
System.out.println(value); // 12 11 15
}
13,14는 15 value로 인해 덮여쓰기가 된걸 알수 있다.
System.out.println(intMap.get("삼"));
삼이라는 value를 가져오고 싶으면 위에 가장 마지막으로 덮어진 15가 출력되는걸 볼수 있다.
map에서 회문 출력을 할 때 keySet을 이용해서 출력을 했었는데 entrySet()을 사용하면 더 효율적인 반복문을 작성 할 수 있다고 해서 이 두개의 차이점을 추가적으로 공부하고 싶어졌다
일단 나는 아래의 코드에서 for loop + keySet() 조합으로 회문 출력을 했었다
Map<Integer,String> stringMap = new HashMap<Integer,String>();
stringMap.put(1,"Apple");
stringMap.put(1,"PineApple");
for(Integer val : stringMap.keySet()) {
System.out.println(val + ". " + stringMap.get(val));
}
그래서 for문 + keySet()을 이용해서 key와 value 부분을 가져올 수 있습니다
우리가 keySet()을 배웠고 for문을 배웠으니 이제 iterator도 배워볼 차례이다.
iterator는 자바의 collection 프레임워크에서 collection에 저장되어 있는 요소들을 읽어오는 방법을 표준화 한것이다. Set, List, Map 인터페이스 모두 iterator로 요소들을 읽어 올 수 있다.
메소드 호출 순서는 hasNext() -> next() -> remove()remove()는 따로 여기서 다루지 않을 예정이다.
Iterator 방식으로도 물론 회문출력이 가능하다.
// key값만
Iterator<Integer> itr = stringMap.keySet().iterator();
// hasNext() 반한값이 boolean
while (itr.hasNext()){
Integer key = itr.next();
String value = stringMap.get(key);
System.out.println(key + " : " + value);
}
단 Iterator<Wrapper 자료형> 여기서 Wrapper 자료형은 무조건 Key값의 자료형을 넣어줘여한다!
Map<Integer,String> stringMap = new HashMap<Integer,String>();
여기서 key의 Wrapper 자료형이 Integer이기 떄문에
Iterator<Integer> itr = stringMap.keySet().iterator();
으로 선언을 해주었다.
for(Map.Entry<Integer,String> pair : stringMap.entrySet()){
System.out.println(pair.getKey() + " : " + pair.getValue());
}
여기서 키와 값을 같이 가져와야하는 경우 Map.Entry<K, V> 인터페이스의 entrySet() 메서드를 사용합니다. Map.Entry 인터페이스는 Map 객체의 키와 값을 접근할 수 있도록 해주는 getKey(), getValue() 함수가 존재합니다.
확실히 keySet보다는 직관적으로 key와 value를 출력해준다.
다음으로 EntrySet()을 iterator로 key와 value부분을 출력 해보도록 하겠습니다
iterator<Map.Entry<Integer,String>> iter = stringMap.entrySet().iterator();
while(iter.hasNext()){
Map.Entry<Integer,String> it = iter.next();
System.out.println(it.getKey() + " : " + it.getValue());
}
여기선 iterator<여기에 Map.Entry<K, V> 인터페이스 넣어줘야 한다.>
위에 for문으로 EntrySet()에 접근 할 때 Map.Entry<Integer,Sting> pair를 써서 pair를 통해 getKey()와 getValue()를 쓸수 있듯이 Iterator에서도 똑같이 써주면 된다.
keySet() 메서드는 맵의 모든 키를 포함하는 Set 컬렉션을 반환하는데 이 Set 컬렉션은 맵의 키를 중복 없이 담고 있습니다. 이러한 특성으로 인해 keySet()을 사용하여 맵의 키를 순회하거나 특정 키에 대한 조회 및 수정 작업을 수행할 수 있습니다.
하지만 keySet()을 통해 얻은 키를 사용하여 값을 직접 조회하는 경우, 매번 조회할 때마다 맵을 순회해야 하므로 효율적이지 않을 수 있습니다.
entrySet() 메서드는 맵의 각 키-값 쌍을 나타내는 Map.Entry 인터페이스의 객체를 담은 Set 컬렉션을 반환하는데, 각 Map.Entry 객체는 getKey(), getValue() 메서드로 키 와 값을 얻을 수 있다.
이렇게 반환된 Set 컬렉션을 사용하면 맵의 키와 값을 동시에 접근하고 조작할 수 있습니다. entrySet()을 사용하여 맵의 키와 값을 동시에 순회하는 경우, 조회 작업이 효율적이고 간편합니다.
따라서 keySet()의 장점은 키에 집중해서 작업을 수행할 수 있다.
entrySet()은 키와 값을 동시에 다룰 수 있어 효율적인 작업이 가능하다.
iterator를 사용해서도 Set 또는 List의 자료구조의 데이터를 회문출력을 할 수있다.
대표적으로 리스트 회문출력 2가지 방식 설명하겠다
1.
List<String> stringList = new ArrayList<String>();
for(int i = 0; i < stringList.size(); i++) {
System.out.println( (i+1) + ". " + stringList.get(i));
}
2.
List<String> stringList = new ArrayList<String>();
Iterator<String> it = stringList.iterator();
int cnt1 = 0;
while(it.hasNext()) {
++cnt1;
System.out.println(cnt1 + ". " + it.next());
}
Set<String> stringList = new HashSet<String>();
Iterator<String> iterSet = stringSet.iterator();
int cnt = 0;
while(iterSet.hasNext()) {
++cnt;
System.out.println(cnt + ". " + iterSet.next());
}
List 기준으로 iterator 방법을 추천을 드린다.
그 이유는 나중에라도 자료구조를 List에서 Set으로 변경시 iterator의 변경은 자료구조만 바꾸주면 끝난다. 즉 회문 부분은 변경 할 필요가 없는 것이다.
만약에 for문으로 하면 에러가 난다.
이런 에러가 날텐데...
그 이유는 Set에는 .get() 메소드가 없기 때문이다
자바의 Collection 부분은 다른 언어에 비해 뭔가 복잡하면서 한 번 제대로 이해하면 잘 쓰일거 같다는 생각이 든다! 하지만 C++를 주로 쓴 나로썬... c++이 그립다..
과연 자바 collection을 자유자재로 쓰고 싶다.