14-1. 컬렉션(Collection) :: List
1. 컬렉션이란?자바에서 제공하는 자료구조를 담당하는 프레임워크자료구조 : 메모리상에서 동일 타입 자료를 구조적으로 처리하는 방법론저장 공간의 크기를 동적 관리기능처리가 간단하게
tt2-blogging.tistory.com
List 정리는 이전 글을 참고하세요
2) Set 계열
- 집합 구조로 하나의 묶음들로 순서 없이 저장한다.
- 필터가 있어서 중복 값을 넣어도 저장되지 않음(Null 포함)
- 객체의 경우 중복 체크 메소드 오버라이딩 필요(equals, hashcode)
- 하나를 뽑으려면 뭐가 나올지 모르니까 전체를 순회해야 한다. (Iterator, forEach 이용)
→ 대신 그룹을 통째로 호출할 때 유용하다
@ Iterator
//HashSet생성
HashSet<Integer> set = new HashSet<Integer>(Arrays.asList(1,2,3));
System.out.println(set); //전체출력 [1,2,3]
// Iterator 사용
Iterator iter = set.iterator();
while(iter.hasNext()) { //값이 있으면 true 없으면 false
System.out.println(iter.next());
}
(1) 구현 클래스 종류
HashSet
- 순서 없이 랜덤 출력됨
- 원하는 값을 찾으려면 .contains()를 통해 확인을 먼저 해야한다.
//set내부에 값 1이 있는지 check : true
System.out.println(set.contains(1));
- List와 호환이 되기 때문에 중복값을 제거하기 위해 잠깐 이용되기도 함
List foodList = new ArrayList(); //list 생성
Set foods = new HashSet(foodList); //list -> set
foodList = new ArrayList(foods); //set -> list
- 혹은 정렬을 위해 List로 변환해서 정렬 진행할 수 있음
ArrayList<Integer> list = new ArrayList<>(set); Collections.sort(list, (o1,o2) -> o2 - o1); // 내림차순 정렬
System.out.println(list.toString()); // [3, 2, 1] Collections.sort(list, (o1,o2) -> o1 - o2); // 오름차순 정렬
System.out.println(list.toString()); // [1, 2, 3]
LinkedHashSet
- 저장한 순서대로 출력 가능한 Set
TreeSet
- 이진 트리를 기반으로 한 Set 컬렉션으로 왼쪽과 오른쪽 자식 데이터(노드)를 참조하기 위한 두개의 변수로 구성됨
- 이진탐색트리(TreeMap)의 문제점**을 보완한 레드-블랙 트리 형태
→ 부모 노드보다 작으면 왼쪽 자식, 크면 오른쪽 자식으로 배치하여 균형 맞춤(오름차순)- 트리가 높을 수록 시간이 오래 걸림
- 트리의 데이터가 값이 편향되게 들어오면 한쪽으로 치우쳐져 비효율적인 포퍼먼스
- Map.Entry 매칭 없이 값만 저장한다
- 빠른 탐색 속도
- 우선 순위가 있어야 출력할 수 있음
- 우선순위 파악을 위한 메소드 필요: compareTo()
(2) Set 출력 방법
- List와 달리 get()으로 뽑아올 수가 없어서 순회해야함
- forEach이용 가능
(1) Iterator
//<String>이 빠지면 Object type이 되기 때문에 String으로 형변환을 거쳐야한다.
//안하려면 제네릭 선언 필수
Iterator<String> fruitIter = keys.iterator();
while(fruitIter.hasNext()) {
Fruit f = fruits.get(fruitIter.next()); //키 하나씩 가져오기
System.out.println(f.getPrice() + f.getLocation());
}
(2) forEach
for(Object o : set) {
System.out.println(o);
}
//방법2를 좀더 간결히 하려면
set.forEach(e -> System.out.println(e));
(3) keyset()
//key들을 모두 가져옴
System.out.println("출력 1:");
Set<String> keys = fruits.keySet();
for(String k : keys) {
Fruit f = fruits.get(k);
System.out.println(f.getName() + f.getPrice());
}
(4) Map.Entry 이용
//마찬가지로 제네릭이 2개다, set의 제네릭으로 entry가 들어간 것임
Set<Map.Entry<String, Fruit>> entry = fruits.entrySet();
for(Map.Entry<String, Fruit> e : entry) {
//제네릭이 있어서 형변환 없이 바로 가능
String k = e.getKey();
Fruit f = e.getValue();
System.out.println(k + " " + f);
}
3) Map 계열
디비에서도 많이 쓰니까 알아둬야한다. (디비 정보저장)
key-Value 형식으로 키와 값이 매칭되어있는 형태 (쌍형)
- map으로 묶어져있으며 key들이 소속되어 특정 값과 매칭되어 있음
- key : 일종의 구분값(변수명)으로 중복 불가
- 중복되면 value가 새로운 값으로 덮어쓰기 됨
- 키를 먼저 가져와야 값을 가져올 수있음 → keySet()
→ keySet()을 forEach로 순회하면서 하나씩 출력할 수도 있음 - 람다식 이용시 매개변수가 두개가 된다(키, 밸류)
//출력 람다식
fruit.forEach((k,v) -> { System.out.println(k + " " + v); });
- value: 중복 가능
- 🚨 Collection인터페이스와 관계 없어서 호환 안됨
//map 사용한 DB 저장 예시 (한개 정보)
Map row = new HashMap();
row.put("memberId", "admin");
row.put("memberPwd", "1234");
row.put("age", 19);
row.put("hobby", List.of("코딩", "영화"));
ArrayList list = new ArryaList();
list.add(row);
//여러개 정보
ArrayList list = new ArrayList();
list.add(row);
row = new hashMap();
row.put("memberId", "admin");
row.put("memberPwd", "1111");
row.put("age", 20);
list.add(row);
System.out.println(list); //출력시 두개 데이터 나옴
1) 구현 클래스 종류
(1) HashMap
- Map의 대표적인 컬렉션 중 하나. 해시테이블 구조의 자료형.
- 말그대로 해싱hashing을 사용하기 때문에 많은 양의 데이터 검색시 유용하다.
- 해시 함수를 통해 키와 값이 저장되므로 사용자는 정확한 위치를 알 수 없다. → 입력 순서 보장 X
원래 해시테이블 자료구조는 입력순서에 관여하지 않는다. 또한 자바 초기의 자료형이라 지금은 쓰지 않음
- 저장공간보다 추가로 값이 들어오면 크기를 두배로 늘리며 과부하가 발생할 수 있으므로 초기에 데이터 개수를 안다면 용량을 지정해주는 것이 좋다.
//HashMap Map엘리먼트 삽입의 예
Map<String, Integer> a = new HashMap<>();
a.put("a", 1);
a.put("b", 2);
(2) TreeMap
이진 트리를 기반으로 한 Map 컬렉션으로, 키와 값이 저장된 Map.Entry를 저장하고 왼쪽과 오른쪽 자식 노드를 참조하기 위한 두 개의 변수로 구성된다.
- 일반적인 Map으로 HashMap보다 성능이 떨어지나 정렬상태로 유지하거나 정렬된 데이터 조회하는 범위 검색 사용시 효율적이다.
- 데이터 저장시 즉시 정렬이 진행되기 때문에 추가나 삭제가 HashMap보다 오래 걸린다.
- key는 저장과 동시에 자동으로 값에 따라 오름차순 정렬한다.
- 숫자 타입 → 값, 문자열 타입 → 유니코드 정렬
- Integer, Double, String은 이미 Comparable 인터페이스를 통해 오름차순이 구현되어 있음
- TreeSet, TreeMap은 내림차순은 따로 구현해야함
➕ Map 계열 내림차순 구현 방법
TreeSet, TreeMap 생성시 매개변수 생성자를 통한 재정렬 가능 - 혹은 Integer, Double, String 외 Comparable을 구현하는 객체는 compareTo()메소드 오버라이딩으로 내림차순 구현
//TreeMap Map 엘리먼트 삽입 예
Map<String, Integer> b = new TreeMap<>();
b.put("a", 1);
b.put("b", 2);
(3)LinkedHashMap
입력순서가 유지되는 맵의 일종
2) Map 제공 메소드
(1)put(key값, value)
: 데이터 넣기
List, Set은 add()를 쓴다는 점에서 차이가 있다.
- key: 기본 Object
→ 보통 숫자(Integer)나 문자열(String)로 관리, 문자열이 더 찾기 쉬움- 마찬가지로 중복 불가, 중복시 덮어쓰기 됨
- value: 기본 Object
→ Vo객체나 기본값
//Map구조
HashMap map = new HashMap();
Map m = new HashMap();
//Collection과는 호환되지 않는다
//Map저장소에 값 저장하기: put(key, value)
map.put("오순", new Animal("오순",15.3, 2, "강아지"));
//key값은 중복이 불가능하다. (덮어쓰기됨)
map.put("오순", "김명준");
System.out.println(map.get("오순")); //김명준
//출력
System.out.println(map);
//{오순=오순, 15.3, 2, 강아지, 도토리=도토리, 0.3, 3, 햄스터}
- keySet() : 모든 key 한번에 가져오기(Set 형식으로)
- set형식은 get이 없어서 원하는 값을 뽑아올 수 없음 -> 전체 순회 필요
//key 한번에 가져오기 -> set 방식으로 가져와줌
Set keys = snack.keySet();
System.out.println(keys);
//set형식은 get이 없어서 원하는 값을 뽑아올 수 없음 -> 전체 순회
- get(key): 데이터 가져오기
//data 가져오기 -> key 값을 바탕으로 값을 가져온다
//get(key)
Object o = map.get("오순"); //아래처럼 해도 됨
Animal o2 = (Animal) map.get("오순");
System.out.println(o);
System.out.println(o2.getName() + " " + o2.getAge());
- size() : 저장된 데이터 수 확인하기
remove(key값)
: 데이터 삭제하기containsKey()
: 해당하는 key 값이 있는지 확인하기System.out.println(map.containsKey("도토리")); //true
containsValue()
: 해당하는 값이 있는지 확인하기entrySet()
: key와 value값을 Map.Entry 객체로 반환해주는 메소드 -> key, value가 모두 필요할 때 사용
Map 순회하기
- entrySet()을 이용하여 내부 키-값 형태를 Entry<K, V>를 지닌 집합 자료형, 즉 Set으로 만든 다음에 순회할 수 있다.
map.keySet()
,map.get()
을 이용해 map의 key들을 모아서 순회
// for loop (keySet())
Set<Integer> keySet = map.keySet();
for (Integer key : keySet) {
System.out.println(key + " : " + map.get(key));
}
Map에 저장된 모든 키-밸류 쌍을 갖고 있는 하나의 객체로 얻을 수 있게 해줌
getKey()
, getValue()
2개의 메소드를 통해 키와 값에 접근할 수 있다.
setVaule(값)
: Map.Entry 객체의 key에 대한 value 값을 수정할 수 있다.
- key값을 얻어온 뒤에 value를 가져오지 않고 한번에 값을 수정할 수 있다.
이용해보기
- 일단 Set으로 선언을 해준다.
Set entry = snack.entrySet();
- iterator, forEach문, forEach 메소드 활용하여 가져올 수 있음
//entrySet()
//1. 이터레이터 이용
System.out.println("Map.Entry 이요해서 전체 데이터 가져오기");
Set entry = snack.entrySet();
Iterator it2 = entry.iterator();
while(it2.hasNext()) {
//형변환으로 엔트리 안에 맵 키와 밸류 정보 저장
Map.Entry e = (Map.Entry) it2.next();
System.out.println(e.getKey() + " : " + e.getValue());
}
//2. for each
for(Object o1 : snack.entrySet()) {
Map.Entry e = (Map.Entry) o1; //반복문에 돌면서 하나씩 들어감
//entry는 키와 밸류를 따로 가져올 수 있는 능력이 있음
System.out.println(e.getKey());
System.out.println(e.getValue());
}
keySet()
: 키의 값만 필요할 때 사용하지만 get(key)와 함께 value를 출력하기도 한다.- 다만, key로 value를 따로 찾는데서 시간이 소요되므로 데이터량이 많으면 entrySet()이 좋다.
4) Properites 클래스 (프로퍼티 클래스)
키와 값을 String 타입으로 제한한 Map컬렉션 형식의 클래스
프로퍼티(*.properites)파일 읽을때 주로 사용함(DB 접속 드라이버 데이터 읽기 등)
- 파일과 연동되는 메소드가 있어서 연동관리가 편리함
- 문자열 데이터를 저장관리할 때 : 프로그램에 대한 설정 내용(옵션정보), 데이터베이스 연결정보, 다국어 정보 등
- 애플리케이션에서 주로 변경이 잦은 문자열을 저장하여 관리하기 때문에 유지보수를 편리하게 만들어줌
- 키와 값이 ‘=’기호로 연결되어있는 텍스트파일로 기본적으로는 ISO 8859-1문자셋으로 저장됨
➕ property 파일
: 세미콜론, 엔터 안함(엔터 대신 띄어쓰기하고 역슬러시 사용)
(1) 사용 메소드
- 값 저장 : put()
//문자열데이터 저장관리 용도- > 파일과 연동되는 메소드가 있어서 연동관리 편리
//클래스이므로 아래와 같이 생성
Properties prop = new Properties();
//값 저장 : put()
prop.put("name", "유병승");
//혹은 setProperty(): 문자열 저장
prop.setProperty("email", "teacherDev09@gmail.com");
prop.setProperty("address", "경기도 시흥");
- 값 가져오기 : getProperty(key)
//값 가져오기
String email = prop.getProperty("email");
System.out.println(email);
- 전체 순회 : 별로 쓸일 많지 않음
for(Object key : prop.keySet()) {
String k = (String) key;
System.out.println(prop.getProperty(k));
}
System.out.println("출력");
prop.forEach((k,v) -> System.out.println(k + " " + v));
- 특정 파일에 저장(properties)
: store(FileWriter or FileOutputStream)
: stroeXML(FileWriter of FileOutputStream)- 단, 사용 후 꼭 닫아줘야함
- 없으면 파일이 자동 생성됨
//특정 file에 저장 : store(fileWriter 혹은 fileOutputStream), 함께 이용(원하는대로)
//단, 사용 후 꼭 닫아야함
//혹은 stroeXML() : 저장할 파일이 xml형식일 때 사용
//자동으로 파일 생성되었음
try(FileOutputStream fos = new FileOutputStream("test.properties")){
prop.store(new FileOutputStream("test.properties"), "test");
} catch(IOException e) {
e.printStackTrace();
}
//xml은 writer 못씀 : xml방식으로 저장하기
try(FileOutputStream wf = new FileOutputStream("test.xml");) {
prop2.storeToXML(wf, "xmlfile");
} catch(IOException e){
e.printStackTrace();
}
- 특정 파일 읽어오기
: load(FileReader or FileOutputStream)
: loadFromXML(FileOutputStream)
//properites파일 읽어오기: load(FileInputStream, FileReader)
//매개변수로 넣어주면 연동된 파일을 가져온다.
//추상화되어있기 때문에 프로그램 돌아가는 세팅할 때 유용할 수 있다
Properties prop2 = new Properties();
try(FileInputStream fis = new FileInputStream("test.properties")){
prop2.load(fis);
}catch(IOException e) {
e.printStackTrace();
}
System.out.println(prop2);
//xml데이터 가져오기 : 태그를 만들어줘야되서 reader 못씀
Properties xmlprop = new Properties();
try(FileInputStream fis = new FileInputStream("test.xml")) {
xmlprop.loadFromXML(fis);
}catch(IOException e) {
e.printStackTrace();
}
System.out.println(xmlprop.getProperty("address"));
//프로젝트 폴더 위치에 properties 파일 직접 생성한 뒤 불러오기
Properties driver = new Properties();
try(FileInputStream fis = new FileInputStream("driver.properties")){
driver.load(fis);
} catch(IOException e) {
e.printStackTrace();
}
System.out.println(driver.getProperty("driver"));
System.out.println(driver.getProperty("path"));
System.out.println(driver.getProperty("url"));
}
5) 그 외 알아두면 좋을 Collections 클래스 전용 메소드
- 특정 문자열의 중복값 갯수를 세어주는 메소드 : .frequency( , )
int count = Collections.frequency(List, String);
- 최대값: max(), 최소값 : min()
// HashMap 준비
Map<Integer, Integer> map = new HashMap<Integer, Integer>();
map.put(1, 5);
map.put(2, 70);
map.put(3, 50);
// Max Key
Integer maxKey = Collections.max(map.keySet());
// Min Key
Integer minKey = Collections.min(map.keySet());
// 결과 출력
System.out.println(maxKey); // 3
System.out.println(minKey); // 1