▶ 컬렉션 (Collection)
- 컬렉션(Collection)은 자바에서 제공하는 자료구조를 담당하는 프레임워크
※ 자료구조: 메모리에서 자료를 구조적으로 처리하는 방법 - 추가, 삭제, 정렬 등의 기능처리가 간단하게 해결되어 자료구조적 알고리즘을 구현할 필요 없음
- java.util 패키지에 포함되며, 인터페이스를 통해 정형화된 방법으로 다양한 컬렉션 클래스 이용 가능
▶ 배열의 문제점 & 컬렉션의 장점
1) 배열의 문제점
- 한번 크기를 지정하면 변경할 수 없음
- 필요에 따라 공간을 늘리거나 줄일 수 없음 - 배열에 기록된 데이터에 대한 중간 위치의 추가, 삭제가 불편함
- 추가, 삭제할 데이터부터 마지막에 기록된 데이터까지 하나씩 뒤로 밀어내고 추가(복잡한 알고리즘) - 한 타입의 데이터만 저장 가능함
2) 컬렉션의 장점
- 저장하는 크기의 제약 없음
- 추가, 삭제, 정렬 등 기능 처리가 간단하게 해결됨
- 자료를 구조적으로 처리하는 자료구조가 내장되어 있어 알고리즘 구현 필요 없음 - 여러 타입의 데이터 저장 가능
- 객체만 저장할 수 있기 때문에 필요에 따라 기본 자료형을 저장해야 하는 경우, Wrapper 클래스 사용
▶ List
- 여러 자료를 순차적으로 나열한 자료구조 (배열과 비슷)
- 인덱스로 관리(순서 구분)되며, 중복해서 객체 저장 가능
- 구현 클래스 : ArrayList, Vector, LinkedList
1) List 계열 주요 메소드
public void ex1() {
// 다형성 적용
List list = new ArrayList(3); // 3칸 짜리 생성
// List list = new ArrayList(); // 기본형 : 10칸짜리 생성
// 1. boolean add(E e) : 마지막 요소로 추가
// E(Element) : 요소를 뜻하는 상징적인 글자 (자료형 X)
list.add("아무거나"); // String은 객체
// Auto Boxing (자동 포장)
list.add(123); // int -> Integer
list.add(3.14); // double -> Double
// ★ 컬렉션에 저장되는 객체의 타입 제한 X
// 왜 기본 자료형이 저장될까?
// -> Wrapper Class : 기본 자료형 -> 객체로 포장하는 클래스
System.out.println(list); // 참조변수 print구문으로 출력 시 toString() 결과값 출력
// list의 크기 3 초과해서 추가해도
// 자동으로 크기가 늘어나기 때문에 에러 발생 X
// 2. E get(int index) : 지정한 index 요소 얻어오기
System.out.println(list.get(1));
System.out.println(list.get(0));
System.out.println(list.get(2));
System.out.println("------------------------------");
// 예제 - 진짜 자동 포장(Auto Boxing) 되었는가 확인
System.out.println(list.get(1) instanceof Integer); // true
System.out.println(list.get(2) instanceof Double); // true
}
public void ex2() {
// 컬렉션의 장점 중 "여러 타입 저장 가능" 때문에
// instanceof로 타입 검사를 해야하는 코드가 추가되어
// 코드의 길이가 늘어나는 문제점이 발생
// -> 타입을 하나로 제한하자!
// --> Generics(제네릭)을 이용
// String으로 저장되는 타입이 제한된 List
List<String> list = new ArrayList<String>();
list.add("파닭");
list.add("마파두부");
list.add("불고기");
list.add("라멘");
list.add("서브웨이");
// 3. list.add(int index, E e) : 중간에 추가(삽입)
list.add(0,"짜장면");
list.add(3,"탕수육");
System.out.println(list);
// 결과값 : [짜장면, 파닭, 마파두부, 탕수육, 불고기, 라멘, 서브웨이]
// 4. E list.set(int index, E e) :
// 지정된 index의 요소를 바꿈(수정)
// 반환되는 값은 바뀌기 이전 요소
String before = list.set(1, "닭갈비");
System.out.println("before : " + before);
// 결과값 : before : 파닭
System.out.println(list);
// 결과값 : [짜장면, 닭갈비, 마파두부, 탕수육, 불고기, 라멘, 서브웨이]
// 5. E list.remove(int index) :
// index번째 요소를 List에서 제거
// 반환되는 값은 제거된 요소
String target = list.remove(6);
System.out.println(target + " 제거");
// 결과값 : 서브웨이 제거
// 6. boolean list.contains(E e) :
// list에 요소가 포함되어 있는지 확인
System.out.println(list.contains("닭갈비"));
// 결과값 : true
System.out.println(list.contains("파닭"));
// 결과값 : false
// 7. int list.indexOf(E e) :
// list에 요소가 존재하면 해당 index 반환
// 없으면 -1 반환
System.out.println(list.indexOf("닭갈비"));
// 결과값 : 1
System.out.println(list.indexOf("파닭"));
// 결과값 : -1
System.out.println(list);
// 결과값 : [짜장면, 닭갈비, 마파두부, 탕수육, 불고기, 라멘]
for(int i=0; i<list.size(); i++) {
// list.get(i)
// -> String으로 제한된 리스트에서 요소를 꺼내오기 때문에
// 꺼낸 요소의 자료형은 무조건 String
System.out.printf("[%d] : %s \n", i, list.get(i));
}
// 결과값 : [0] : 짜장면
[1] : 닭갈비
[2] : 마파두부
[3] : 탕수육
[4] : 불고기
[5] : 라멘
// 8. void list.clear() : 요소 모두 삭제
list.clear();
System.out.println(list);
// 결과값 : []
// 9. boolean list.isEmpty() :
// 비어있으면 true, 아니면 false
System.out.print("list는 비어 있는가? " + list.isEmpty());
// 결과값 : list는 비어 있는가? true
}
2) ArrayList
- List의 자손 클래스로 초기 저장 용량은 10으로 자동 설정되며 따로 지정도 가능
- 저장 용량을 초과한 객체가 들어오면 자동으로 늘어나며 고정도 가능
- 동기화(Synchronized)를 제공하지 않음
3) LinkedList
- List의 자손 클래스로 인접 참조를 링크해 체인처럼 관리함
- 특정 인덱스에서 객체를 제거하거나 추가하게 되면, 바로 앞/뒤 링크만 변경하면 되기 때문에
객체 삭제와 삽입이 빈번하게 일어나는 곳에서 ArrayList보다 성능이 좋음
4) Comparable / Comparator
Comparable | Comparator | |
패키지 | java.lang | java.util |
사용 메소드 | compareTo( ) | compare( ) |
정렬 | 기본 정렬기준을 구현하는데 사용 | 그 외 다른 여러 기준으로 정렬하고자 할 때 사용 |
사용법 | 정렬하고자 하는 객체에 Comparable를 상속받아 compareTo( ) 메소드를 오버라이딩해서 기본 정렬 기준 재정의 → 한 개의 정렬만 가능함 |
Model.sort 패키지 안에 필요한 정렬 기준에 맞춘 여러 클래스를 생성하고 Comparator를 상속받아 Compare( ) 메소드를 오버라이딩해서 정렬 기준 재정의 → 여러 개 정렬 가능 |
5) Collections.sort( )
- Collections.sort( List<T> list ) : T 객체에 Comparable을 상속받아
compareTo 메소드 재정의를 통해 정렬 구현(단 한 개의 정렬) - Collections( List<T> list, Comparator<T> c ) : 지정한 Comparator 클래스에 의한 정렬(여러 개의 정렬)
▶ Set
- 저장 순서가 유지되지 않고(인덱스 없음), 중복 객체도 저장하지 못하게(같은 객체를 덮어씌움) 하는 자료구조
- get( ) 메소드 없음
- null도 중복을 허용하지 않기 때문에 1개의 null만 저장
- 구현 클래스 : HashSet, LinkedHashSet, TreeSet
1) Set 계열 주요 메소드
2) HashSet
- Set에 객체를 저장할 때, Hash 함수를 사용하여 처리속도가 빠름
- 동일 객체뿐만 아니라, 동등 객체도 중복해서 저장 X
- hashCode( )를 이용해서 중복 비교 → hashCode( ) 오버라이딩 필수 → 빠른 검색 지원
3) LinkedHashSet
- 순서가 유지되는 Set
- hashCode( ) 오버라이딩 필수
4) TreeSet
- 저장되는 값을 자동으로 정렬
- Comparable 상속 필수
public void ex1() {
// 기본적인 Set 사용법
// String, Integer 등 Java 제공 객체는
// 기본적으로 hashCode(), equals(), campareTo() 등이
// 오버라이딩 되어 있음
Set<String> set = new HashSet<>();
// Cannot instantiate the type Set (인터페이스 = 미완성 설계도 -> 객체 생성 X)
// 1. boolean set.add(E e) : 추가
set.add("네이버");
set.add("카카오");
set.add("라인");
set.add("쿠팡");
set.add("배달의 민족");
set.add("당근마켓");
set.add("토스");
System.out.println(set);
// 결과값 : [배달의 민족, 당근마켓, 카카오, 네이버, 쿠팡, 라인, 토스]
// HashSet 순서 유지 X
// 중복 저장 확인 -> 중복 저장 X
set.add("토스");
set.add("토스");
set.add("토스");
set.add("토스");
set.add("토스");
set.add("토스");
System.out.println(set);
// 결과값 : [배달의 민족, 당근마켓, 카카오, 네이버, 쿠팡, 라인, 토스]
// set에 null도 저장이 되는지 확인 -> 저장 O (단, 중복 저장은 X)
set.add(null);
System.out.println(set);
// 결과값 : [null, 배달의 민족, 당근마켓, 카카오, 네이버, 쿠팡, 라인, 토스]
// 2. int set.size() : 저장된 객체의 수 반환
System.out.println(set.size() + "개");
// 결과값 : 8개
// 3. boolean remove(E e) :
// e와 똑같은 요소가 set에 있으면 지우고 true 반환
// 없으면 false 반환
if(set.remove(null)) {
System.out.println("null이 제거되었습니다.");
} else {
System.out.println("null이 없습니다.");
}
System.out.println(set);
// 결과값 : [배달의 민족, 당근마켓, 카카오, 네이버, 쿠팡, 라인, 토스]
// 4. boolean set.contains(E e) :
// set에 저장된 객체 중에서 e와 똑같은 객체가 있으면 true, 아니면 false 반환
System.out.println("네이버 "+(set.contains("네이버")? "있음" : "없음"));
// 결과값 : 네이버 있음
System.out.println("직방 "+(set.contains("직방")? "있음" : "없음"));
// 결과값 : 직방 없음
// 5. void set.clear() : set에 저장된 객체를 모두 지움
set.clear();
System.out.println("clear 후 size : " + set.size());
// 결과값 : clear 후 size : 0
// 6. boolean set.isEmpty() :
// set에 저장된 객체가 없다면(비어있다면) true, 아니면 false 반환
// "set.size() == 0" 과 같은 의미
System.out.println("set이 "+(set.isEmpty()? "비어있음" : "비어있지 않음"));
// 결과값 : set이 비어있음
}
public void ex2() {
// Set에 저장된 값을 꺼내쓰는 방법
// 1. Iterator (반복자)
// - 컬렉션 객체의 요소를 하나씩 꺼내서 반복 접근할 수 있는 객체
// (순서대로 요소 하나씩 꺼내는 객체)
Set<String> set = new HashSet<>();
set.add("쌀과자");
set.add("오예스");
set.add("초코파이");
set.add("몽쉘");
set.add("빅파이");
// Iterator set.iterator(); :
// set의 내용을 순차(반복) 접근할 수 있는 형태로 변경해서 반환
Iterator<String> it = set.iterator();
// boolean it.hasNext() :
// 다음 꺼낼 요소가 있으면 true, 없으면 false 반환
while(it.hasNext()) { // 하나씩 꺼냈을 때 다음 값이 없는 경우 == 끝
// -> 다음 값이 있으면 반복!
String temp = it.next(); // E it.next() : 다음 요소 꺼내서 반환
System.out.println(temp);
// 결과값 : 오예스
쌀과자
빅파이
초코파이
몽쉘
}
System.out.println("------------------------------------------");
// 2. 향상된 for문
for(String s : set) {
System.out.println(s);
// 결과값 : 오예스
쌀과자
빅파이
초코파이
몽쉘
}
}
public class Student {
// A.equals(B)
// A 객체와 B 객체가 가지고 있는 필드의 값이 모두 같으면 true, 아니면 false
@Override // Object.equals() 오버라이딩
public boolean equals(Object obj) {
if(this == obj) {
return true;
}
if(obj==null) {
return false;
}
if(!(obj instanceof Student)) { // 비교 대상이 Student가 아니라면
return false;
}
// obj 참조변수를 Student로 다운 캐스팅
Student other = (Student)obj;
// 현재 객체(this)와 다른 객체(other)의 필드를 비교
return this.grade == other.grade
&& this.ban == other.ban
&& this.number == other.number
&& this.name.equals(other.name)
&& this.gender == other.gender
&& this.score == other.score;
}
// (중요!!) equals() 오버라이딩 했으면
// hashCode()도 오버라이딩을 해야 한다!!
// hashCode() : 해시 테이블(객체 주소록)에서
// 객체를 빨리 찾아가게 하기 위한 번호
//****************************************
// * A.equals(B)의 결과가 true 라면
// * A.hashCode() == B.hashCode() 의 결과도 treu여야 한다.
//****************************************
@Override // Object의 hashCode() 오버라이딩
public int hashCode() {
// 필드 값이 같은 객체는 같은 정수를 반환해야 한다.
// == 필드 값을 이용해서 정수를 만들면 된다.
int result = 1; // 결과 저장 변수
final int PRIME = 31; // 31이 연산속도가 빠른 소수 중 하나
result = result * PRIME * ban;
result = result * PRIME * (name == null ? 0 : name.hashCode());
return result;
}
}
public void ex3() {
// Set이 중복을 확인하는 방법
// -> 새로 추가하려는 객체와 Set에 있는 객체가
// equals() 수행 시 true
// hashCode() 비교 시 true 이면 중복으로 판단
// ★ Set을 이용하려면 equals()와 hashCode() 필수로 오버라이딩
// A.equals(B) : A와 B가 가지고 있는 필드 값이 모두 같으면 true, 아니면 false
// hashCode() : 필드 값이 다르면 중복되지 않는 숫자를 만드는 메소드
// -> 왜 만들까? 빠른 데이터 검색을 위해서(객체가 어디에 있는지 빨리 찾기 위해서)
// Hash 함수 : 입력된 단어를 지정된 길이의 문자열로 변환하는 함수 (중복 X)
// ex) 입력 : 123 -> "asdfg" (5글자)
// ex) 입력 : 1234567 -> "qwert" (5글자)
// HashSet() : 중복 없이 데이터를 저장(Set)하고 데이터 검색이 빠름(Hash)
Set<Student> set = new HashSet<>();
Student std1= new Student(3,4,5,"홍길동",'M',100);
Student std2= new Student(3,4,5,"홍길동",'M',100);
Student std3= new Student(3,4,6,"고길동",'M',100);
set.add(std1);
set.add(std2);
set.add(std3);
System.out.println("size : " + set.size());
// 결과값 : size : 2
for(Student std : set) {
System.out.println(std);
System.out.println(std.hashCode());
}
System.out.println();
// 결과값 : [학생정보] 학년: 3, 반: 4, 번호: 5, 이름: 홍길동, 성별: M, 점수: 100
1571823060
[학생정보] 학년: 3, 반: 4, 번호: 6, 이름: 고길동, 성별: M, 점수: 100
367817478
}
▶ Map
- 특정 키워드(Key)를 입력하면, 해당되는 상세한 값(Value)을 얻을 수 있는 컬렉션 객체
- K : V 한 쌍으로 데이터를 저장 ( K : V 한 쌍을 묶어서 Entry라고 부름)
- 키(Key)와 값(Value)으로 구성되어 있으며, 키와 값은 모두 객체
- 키(Key)는 중복 저장을 허용하지 않고(Set 방식), 값(Value) 는 중복 저장 가능(List 방식)
- 키(Key) 가 중복되는 경우, 기존에 있는 키(Key) 에 해당하는 값(Value) 를 덮어씌움
- 구현 클래스 : HashMap, LinkedHashMap, TreeMap
1) Map 계열 주요 메소드
▶ HashMap
- 키(Key) 객체는 hashCode( )와 equals( )를 오버라이딩해서 동등 객체가 될 조건을 정해야 함
→ 키(Key) 타입은 hashCode( )와 equals( ) 메소드가 재정의되어 있는 String 타입을 주로 사용
▶ TreeSet과TreeMap
- 검색 기능을 강화한 컬렉션으로, 계층 구조를 활용해 이진 트리 자료구조를 구현해 제공
public void ex1() {
// Key 제한, Value 제한
Map<Integer, String> map = new HashMap<>();
// Map의 자식 클래스 중 가장 대표되는 Map
// 1. V map.put(K k, V v) : Map에 추가
// Map에 추가 시 Key가 중복되면 새로운 Value로 덮어 씌우고
// 이전 Value가 반환
// 중복이 아니면 null 반환
System.out.println(map.put(1, "아이스 바닐라 라떼")); // 결과값 : null
System.out.println(map.put(2, "아이스 녹차 라떼")); // 결과값 : null
System.out.println(map.put(3, "아이스 흑임자 라떼")); // 결과값 : null
System.out.println(map.put(3, "아이스 흑당 밀크티")); // 결과값 : 아이스 흑임자 라떼
System.out.println(map);
// 결과값 : {1=아이스 바닐라 라떼, 2=아이스 녹차 라떼, 3=아이스 흑당 밀크티}
// 2. V map.get(K k) :
// map에서 Key에 해당하는 Value를 반환
// 일치하는 Key가 없으면 null 반환
System.out.println(map.get(1)); // 결과값 : 아이스 바닐라 라떼
System.out.println(map.get(2)); // 결과값 : 아이스 녹차 라떼
System.out.println(map.get(3)); // 결과값 : 아이스 흑임자 라떼
System.out.println(map.get(4)); // 결과값 : null
// Value가 String이기 때문에 String 변수에 저장 가능
String s = map.get(1);
// 3. int map.size() : 저장된 K:V쌍의 수를 반환
System.out.println("K:V 몇 쌍? : "+map.size()+"쌍");
// 결과값 : K:V 몇 쌍? : 3쌍
// 4. V map.remove(K k) :
// map에서 Key가 일치하는 요소(K:V)를 제거
// 제거되는 Value를 반환, 없으면 null 반환
System.out.println(map.remove(1)+" 제거"); // 결과값 : 아이스 바닐라 라떼 제거
System.out.println(map.remove(10)+" 제거"); // 결과값 : null 제거
// 5. void map.clear() : map 다 지움
map.clear();
// 6. boolean map.isEmpty() : 비었으면 true, 아니면 false
System.out.println("map은 비었는가? : "+map.isEmpty());
// 결과값 : map은 비었는가? : true
}
public void ex2() {
// Map에 저장된 값 순차 접근(반복해서 순서대로 하나씩 꺼내기)
// 1. Set map.keySet() :
// key만을 모아놓은 집합(Set)을 반환
Map<String, String> map = new HashMap<>();
map.put("학원", "서울시 강남구");
map.put("롯데월드", "서울시 송파구");
map.put("스타필드 하남", "경기도 하남시");
Set<String> set = map.keySet();
System.out.println(set);
// 결과값 : // 결과값 : [롯데월드, 스타필드 하남, 학원]
System.out.println("------------------------------");
// 2. keySet을 이용해서 Map에 있는 모든 요소 순차 접근
for(String key : set) {
System.out.printf("[%s] %s \n", key, map.get(key));
}
// 결과값 : [롯데월드] 서울시 송파구
[스타필드 하남] 경기도 하남시
[학원] 서울시 강남구
}
public void ex3() {
// Map은 언제 사용하면 좋을까?
// 1) 한 번에 많은 양의 데이터를
// 명확하게 구분할 수 있는 형태로 전달해야되는 경우
// 2) VO(Value Object) : 값 전달용 객체
// Vo가 없거나, 있어도 사용 빈도가 낮은 경우
// Map으로 대체해서 사용
Map<String, Object> s1 = new HashMap<>();
// Value의 타입이 Object로 제한되어있다.
// == 어떤 객체든 Value에 들어올 수 있다!
s1.put("grade", 3); // 3(int) -> Integer로 Auto Boxing
s1.put("ban", 5);
s1.put("number", 17);
s1.put("name", "카리나");
s1.put("gender", 'F');
s1.put("score", 40);
Set<String> set = s1.keySet(); // key들의 집합
for(String key : set) {
System.out.printf("[%s]: %s \n", key, s1.get(key));
}
// 결과값 : [number]: 17
[score]: 40
[gender]: F
[grade]: 3
[name]: 카리나
[ban]: 5
System.out.println("--------------------------------------");
// Map과 VO 비교
Student s2 = new Student();
s2.setGrade(2);
s2.setBan(5);
s2.setNumber(11);
s2.setName("장원영");
s2.setGender('F');
s2.setScore(70);
System.out.printf("s1: %d학년 %d반 %d번 %s \n",
s1.get("grade"),s1.get("ban"),s1.get("number"),s1.get("name"));
// 결과값 : s1: 3학년 5반 17번 카리나
System.out.printf("s2: %d학년 %d반 %d번 %s \n",
s2.getGrade(),s2.getBan(),s2.getNumber(),s2.getName());
// 결과값 : s2: 2학년 5반 11번 장원영
}
public void ex4() {
List<Map<String, Object>> list = new ArrayList<>();
for(int i=0; i<10; i++) {
// Map 생성
Map<String, Object> map = new HashMap<>();
// map에 데이터 추가
map.put("id", "user0"+i);
map.put("pw", "pass0"+i);
// map을 List에 추가
list.add(map);
}
// for문 종료 시 List에는 10개의 Map 객체가 추가 되어있음
// ★ List에 저장된 Map에서 key가 "id"인 경우의 value 모두 출력
for(Map<String, Object> temp :list) {
System.out.println(temp.get("id"));
}
// 결과값 : user00
user01
user02
user03
user04
user05
user06
user07
user08
user09
}
'Java > 기본 개념' 카테고리의 다른 글
변수(Variable) (0) | 2024.12.16 |
---|---|
프로그래밍 기초 (0) | 2024.12.16 |
스레드(Thread) (0) | 2024.11.17 |
네트워크(Network) (0) | 2024.11.17 |
입출력 (IO_Input / Output) (3) | 2024.11.17 |