-
컬렉션 프레임워크(List, Set, Map)JAVA 2022. 9. 24. 20:04
collection framework는 collection interface를 최상위로 하는 자료구조 interface이다.
전체 구조 컬렉션 프레임워크의 장점
다양한 자료구조를 가지고 있고 가변적인 크기를 통해 유연한 사용을 할 수 있다.
컬렉션 프레임워크 특징
컬렉션 프레임워크에서 데이터 추가, 삭제, 검색 방법이 비슷하다
왜냐하면 최상위의 컬렉션 프레임워크가 하위의 List, Set interface를 구현하기 때문이다.
이 때 인터페이스 구현 시 장점은? 필수 method를 강제할 수 있다.
ArrayList
index를 사용한다는 점에서 Array와 비슷하다.
가변적인 크기를 가지고 있어 크기가 무제한으로 늘어난다.
값을 추가/삭제 하면 index가 1씩 당겨지거나 미뤄지게 된다.
따라서 빈번한 값의 추가/삭제는 무리가 간다.
배열은 같은 인덱스에 중복해서 값을 넣을 경우 값이 덮어쓰게 된다.
반면에 ArrayList는 같은 인덱스에 중복해서 값을 넣을 경우 계속 밀리게 되어 덮어쓰지 않는다.
list.size() : 크기를 반환한다.
list.get(index) : 인덱스의 값을 반환한다.
list.remove(index) : 인덱스의 값을 삭제하고 그 값을 반환한다.
list.indexOf(값) : 특정한 값이 있는 인덱스를 반환한다.
list.contains(값) : 값의 포함 여부를 참/거짓으로 반환한다.
list.set(인덱스,값) : 특정 인덱스의 값을 입력 값으로 변경한다.
list.clear() : 리스트를 비운다.
list.isEmpty() : 리스트가 비워져 있는지 참/거짓으로 반환한다.
package chap09.ex01.arList; import java.util.ArrayList; import java.util.List; public class ArrayList01 { public static void main(String[] args) { //ArrayList<String> list = new ArrayList<String>(); List<String> list = new ArrayList<String>(3); // 크기 지정 가능, 안 해도 상관 없음 String[] arr = new String[3]; // 데이터 추가 arr[0] = "test"; list.add("collection"); //0 list.add("thread"); //1 list.add("java IO"); //2 list.add("NETWORK"); //3 <- 배열 같았으면 Exception 발생 list.add(3, "lamda"); //배열같은 경우에는 덮어쓰게 된다. 그런데 리스트에서는 ([3]lamda [4]NETWORK) //리스트 개수 : list.size() //특정 인덱스 값 꺼내오기 : list.get(index) //이것들을 활용해서 리스트 안에 값을 하나씩 가져오기 for(int i=0 ; i<list.size() ; i++) { System.out.print(list.get(i) + "\t"); } System.out.println(); System.out.println("삭제한 값 : " + list.remove(2)); // 인덱스로 삭제하면 삭제한 값을 반환한다. System.out.println("삭제 성공 여부 : " + list.remove("collection")); // 값으로 삭제하면 성공 여부를 반환한다. for (String item : list) { System.out.print(item + "\t"); } } }
Array에서 ArrayList로 변환하는 방법
Array에 담겨져 있는 모든 값을 한 번에 저장하기 위해서 Array -> List -> ArrayList 형태로 변환한다.
우선 List로 변환하기 위해서 Arrays.asList(배열)로 변환한다.
이 때 List는 인터페이스이기 때문에 값을 확인하는 것은 가능하지만 추가/삭제가 불가능하다.
추가/삭제를 하기 위해서 ArrayList로 변환해야 하는데 이 때 addAll(리스트)를 사용하면 모든 값을 한 번에 추가할 수 있다.
package chap09.ex01.arList; import java.util.ArrayList; import java.util.Arrays; import java.util.List; public class ArrayList02 { // array -> ArrayList 변환 public static void main(String[] args) { // 가끔 배열을 ArrayList로 변환할 경우도 있다. String[] arr = {"List","Set","Map"}; // Array -> List -> ArrayList //1. Array -> List (interface) List<String> list = Arrays.asList(arr); System.out.println(list.size()); System.out.println(list.get(1)); //list.add("collection"); // List는 인터페이스이기 때문에 보는 것만 가능하고, 쓰지는 못한다. //2. List -> ArrayList // List에 있는 값을 뽑아서 ArrayList에 넣어줘야 한다. ArrayList<String> arrList = new ArrayList<>(); arrList.addAll(list); // addAll로 List를 전부 한 번에 넣을 수 있다. arrList.add("collection"); for (String item : arrList) { System.out.print(item+"\t"); } } }
ArrayList와 Vector의 차이점
모든 기능은 똑같지만 ArrayList는 다중 유저의 사용을 허용하고 Vector는 다중 유저의 사용을 허용하지 않는다.
package chap09.ex01.arList; import java.util.Vector; public class ArrayList03 { public static void main(String[] args) { Vector<Integer> score = new Vector<Integer>(); score.add(70); //0 score.add(50); //1 score.add(80); //2 score.add(90); //3 score.add(100); //4 score.add(90); //5 // 검색 // indexOf() : 특정한 값을 찾아 인덱스를 반환 System.out.println(score.indexOf(90)); // contains() : 포함 여부를 참/거짓으로 반환 System.out.println(score.contains(30)); // 수정 score.set(3, 95); // 특정 인덱스를 특정 값으로 변경 //리스트 비우기 //[10][20][30][4][5] score.clear(); // 리스트를 깔끔하게 비운다. // 비워졌는지 확인 System.out.println(score.isEmpty()); // 리스트가 비워졌는지 참/거짓으로 반환 } }
ArrayList와 LinkedList의 차이점
ArrayList는 배열 형식으로 저장이 되고 LinkedList는 각 노드에 데이터가 저장되고 다음 노드를 가리키는 포인터있어서 연결되어 있는 형식이다.
저장된 데이터가 많아질수록 LinkedList가 더 빠르다. -> 데이터가 추가/삭제될 경우 포인터가 가리키는 값만 바꾸면 되기 때문에
package chap09.ex02.link; import java.util.ArrayList; import java.util.LinkedList; import java.util.List; public class BenchMark { public static void main(String[] args) { // A와 B 달리기 측정 // 선수 준비 ArrayList<String> arr = new ArrayList<String>(); LinkedList<String> lnk = new LinkedList<String>(); // 장소 준비 (데이터 100개 채우기) for (int i = 0; i < 100; i++) { arr.add("data"); lnk.add("data"); } // 시계 준비 (걸린 시간 = 도착 시간 - 출발 시간) long startTime = 0; long endTime = 0; // ArrayList 의 출발 시간 기록 startTime = System.currentTimeMillis(); // 현재 시간을 1000/1 초로 환산 // 달리기 for (int i = 1; i <= 100000; i++) { arr.add(55, "add data"); } // ArrayList 도착 시간 기록 endTime = System.currentTimeMillis(); System.out.println("ArrayList 걸린 시간 : " + (endTime - startTime) + " ms"); // LinkedList 의 출발 시간 기록 startTime = System.currentTimeMillis(); // 현재 시간을 1000/1 초로 환산 // 달리기 for (int i = 1; i <= 100000; i++) { lnk.add(55, "add data"); } // LinkedList 도착 시간 기록 endTime = System.currentTimeMillis(); System.out.println("LinkedList 걸린 시간 : " + (endTime - startTime) + " ms"); } }
HashSet
Set은 중복된 값을 허용하지않고 값의 순서가 없다.
따라서 검색 기능을 사용할 수 없기 때문에 iterator를 사용해야 한다.
ArrayList와 마찬가지로 collection interface를 구현받기 때문에 사용하는 메소드가 거의 같다.
iterator 시키면 next()를 통해 값을 꺼내올 수 있다.
hasNext()를 통해 더 이상 꺼내올 값이 없는지 확인할 수 있다.
향상된 for문을 사용하면 더 편하게 꺼내올 수 있다.
package chap09.ex03.set; import java.util.Iterator; import java.util.Set; class Member{ } public class HashSet { public static void main(String[] args) { // 현재 클래스와 사용할 클래스 이름이 동일하면 자동으로 패키지명을 포함한 클래스명이 나타난다. // 가급적이면 겹치지 않는 클래스 이름을 사용해야 한다. Set<String> set = new java.util.HashSet<>(); /*데이터 추가 - java, jsp, oracle, mvc, java*/ set.add("java"); set.add("jsp"); set.add("oracle"); set.add("mvc"); set.add("java"); // 중복 System.out.println(set.size()); Set<Member> members = new java.util.HashSet<>(); members.add(new Member()); members.add(new Member()); members.add(new Member()); System.out.println(members.size()); // Set에서 하나씩 꺼내보기 - 순서가 없기 때문에 Set에서는 검색이 없다. // 방법 1. set -> iterator화 시킨다. -> next()를 이용해서 꺼낸다. Iterator<String> iter = set.iterator(); while (iter.hasNext()) { String item = iter.next(); System.out.print(item+" | "); } System.out.println(); // 방법 2. for -> 향상된 for문을 사용하면 iterator와 관련된 작업을 생략할 수 있다. for (String item : set) { System.out.print(item+" | "); } } }
HashMap
collection interface를 구현받지 않고 Map interface을 구현받기 때문에 조금 다른 메소드를 사용한다.
package chap09.ex04.map; import java.util.HashMap; import java.util.Iterator; import java.util.Map; import java.util.Map.Entry; import java.util.Set; public class HashMapMain { public static void main(String[] args) { // HashMap은 Map 인터페이스를 구현받고 있다. Map<String, Integer> map = new HashMap<String, Integer>(); // 데이터 추가시 add가 아닌 put을 사용 -> collection interface를 구현받지 않기 때문에 map.put("kim", 63); map.put("lee", 26); map.put("park", 26); // 값의 중복은 허용 map.put("kim", 30); // 키의 중복은 허용하지 않는다. (중복 발생시 나중 것으로 덮어쓴다.) // 크기 System.out.println("map : " + map.size()); // 특정 값 가져오기 : 키를 통해서 값을 찾는다.(Dictionary) System.out.println("kim의 나이 : " + map.get("kim")); // 특정 값 삭제하기 : 키를 통해서 값을 지운다. -> 어떤 값을 지웠는지 알려준다. System.out.println(map.remove("kim")); // 모든 값을 출력 1 : key를 Set으로 가져온다. -> iterator로 분리 -> key를 하나씩 가져와서 해당하는 value를 // 찾는다. Set<String> keySet = map.keySet(); Iterator<String> keyIter = keySet.iterator(); while (keyIter.hasNext()) { String key = keyIter.next(); System.out.print(key + " : " + map.get(key) + "\t"); } System.out.println(); // 모든 값을 출력 2 : map을 entrySet으로 만든다. -> iterator로 분리(K,V) -> 키와 값을 각각 추출 Set<Entry<String, Integer>> entrySet = map.entrySet(); Iterator<Entry<String, Integer>> entry = entrySet.iterator(); while (entry.hasNext()) { Entry<String, Integer> item = entry.next(); String key = item.getKey(); int val = item.getValue(); System.out.print(key + " : " + val + "\t"); } System.out.println(); // 모든 값을 출력 3 : key를 Set으로 가져온다. -> key를 하나씩 가져와서 해당하는 value를 찾는다. for (String key : map.keySet()) { System.out.print(key + " : " + map.get(key) + "\t"); } if (!map.isEmpty()) { map.clear(); } } }
Entry
Map 형태에서 키와 값 쌍으로 가져오는 형태를 엔트리라고 한다.
entrySet()을 통해 엔트리 형태로 가져올 경우 Set타입이기 때문에 iterator를 해야 값을 가져올 수 있다.
map.put(key,value) : 값을 추가한다.
map.get(key) : 키를 통해 값을 찾는다.
map.remove(key) : 키를 통해 값을 제거하고 값을 반환한다.
map.entrySet() : 엔트리 형식으로 값을 가져온다.
package chap09.ex04.map; import java.util.HashSet; import java.util.Hashtable; import java.util.Iterator; import java.util.Map.Entry; import java.util.Set; public class HashTableMain { public static void main(String[] args) { Hashtable<String, Integer> map = new Hashtable<>(); //이름, 점수 map.put("홍길동1", 99); map.put("홍길동2", 80); map.put("홍길동3", 85); map.put("홍길동4", 100); map.put("홍길동5", 70); map.put("홍길동6", 60); map.put("홍길동7", 99); map.put("홍길동8", 75); map.put("홍길동9", 95); map.put("홍길동10", 45); //홍길동4의 점수 System.out.println(map.get("홍길동4")); //홍길동4가 있는지 확인 System.out.println(map.containsKey("홍길동4")); //99점의 학생이 존재하는가? System.out.println(map.containsValue(99)); //특정 키를 가지고 해당 값을 찾는 법은 get()을 통해 가능 //특정 값을 가지고 해당 키를 찾는 방법은? //99점의 학생 이름을 찾으세요. //1. 키의 값을 하나씩 뽑아서 값을 찾아 대조하는 방식 for (String item : map.keySet()) { if(map.get(item)==99) { System.out.print(item + "\t"); } } System.out.println(); //2. 엔트리<키,값>를 뽑아서 값을 찾아 일치하는 값의 키를 가져오는 방식 Set<Entry<String, Integer>> entrySet = map.entrySet(); Iterator<Entry<String, Integer>> entry = entrySet.iterator(); while(entry.hasNext()) { Entry<String, Integer> item = entry.next(); if(item.getValue()==99) { System.out.print(item.getKey() + "\t"); } } } }
스택(stack)
- LIFO(Last In First Out) 형태의 자료구조다.
push()를 통해 값을 넣고 pop()을 통해 값을 뺀다.
peek()을 통해 값만 확인하고 다시 넣을 수 있다.
package chap09.ex05.stack; public class Towel { private String color; public Towel(String color) { this.color = color; } public String getColor() { return color; } }
package chap09.ex05.stack; import java.util.Stack; public class TowelBox { public static void main(String[] args) { Stack<Towel> box = new Stack<Towel>(); // 수건넣기(push) box.push(new Towel("red")); box.push(new Towel("orange")); box.push(new Towel("yellow")); box.push(new Towel("green")); box.push(new Towel("blue")); box.push(new Towel("navy")); box.push(new Towel("purple")); System.out.println(box.size()); while(!box.isEmpty()) { //Towel towel = box.pop(); //System.out.println(towel.getColor()+"색 수건을 꺼낸다. " + box.size()+"장 남음"); //메소드 체이닝 System.out.println(box.pop().getColor()+"색 수건을 꺼낸다. " + box.size()+"장 남음"); //peek() : 뽑아서 확인하고 다시 넣는다. //System.out.println(box.peek().getColor()+"색 수건을 꺼낸다. " + box.size()+"장 남음"); } } }
큐(queue)
FIFO(First In First Out) 형태의 자료구조이다.
자바에선 LinkedList로 구현되어 있다.
offer()를 통해 값을 넣고 poll()을 통해 값을 뺀다.
package chap09.ex06.queue; public class Job { private String command; private String to; public Job(String command, String to) { this.command = command; this.to = to; } public String getCommand() { return command; } public String getTo() { return to; } }
package chap09.ex06.queue; import java.util.LinkedList; import java.util.Queue; public class JobQueue { public static void main(String[] args) { Queue<Job> queue = new LinkedList<Job>(); // 해야할 일을 큐에 넣어보자 queue.offer(new Job("send SMS", "Alice")); queue.offer(new Job("send Mail", "Bryan")); queue.offer(new Job("send SMS", "Criss")); queue.offer(new Job("send Talk", "Denis")); queue.offer(new Job("send SMS", "Erick")); try { while(!queue.isEmpty()) { //peek() : stack과 마찬가지로 빼서 확인 후 다시 넣는다. Job job = queue.poll(); String command = job.getCommand(); String to = job.getTo(); System.out.println(command + " to " +to); System.out.println("잔여 작업 : " + queue.size()); } } catch (Exception e) { System.out.println("객체 추출 구문을 확인해주세요."); e.printStackTrace(); } finally { System.out.println("끝"); } } }
'JAVA' 카테고리의 다른 글
thread 2 (스레드 제어~스레드 풀) (1) 2022.09.24 thread - 1 (스레드 생성~join) (1) 2022.09.24 제너릭 (Generic) (1) 2022.09.24 문자열 (String) (1) 2022.09.24 예외 (Exception) (0) 2022.09.24