컬렉션 (Collection)

김찬희·2023년 2월 27일
0

KH정보교육원

목록 보기
12/27

▶ 컬렉션(Collection)

메모리상에서 자료를 구조적으로 처리하는 방법을 자료구조라 일컫는데 컬렉션(Collection)은 자바에서 제공하는 자료구조를 담당하는 프레임워크
추가, 삭제, 정렬 등의 기능처리가 간단하게 해결 되어 자료구조적 알고리즘을 구현할 필요 없음
java.util 패키지에 포함되며, 인터페이스를 통해 정형화된 방법으로 다양한 컬렉션 클래스 이용 가능

▶ 자료구조

데이터(자료)를 메모리에서 구조적으로 처리하는 방법론이다.

▶ 배열의 문제점 & 컬렉션의 장점

√ 배열의 문제점
1) 한번 크기를 지정하면 변경할 수 없다.
- 공간 크기가 부족하면 에러가 발생 → 할당 시 넉넉한 크기로 할당하게 됨 (메모리 낭비)
- 필요에 따라 공간을 늘리거나 줄일 수 없음
2) 배열에 기록된 데이터에 대한 중간 위치의 추가, 삭제가 불편하다.
- 추가, 삭제할 데이터부터 마지막 기록된 데이터까지 하나씩 뒤로 밀어내고 추가해야 함 (복잡한 알고리즘)
3) 한 타입의 데이터만 저장 가능하다.

√ 컬렉션의 장점
1) 저장하는 크기의 제약이 없다.
2) 추가, 삭제, 정렬 등의 기능 처리가 간단하게 해결된다.
- 자료를 구조적으로 처리하는 자료구조가 내장되어 있어 알고리즘 구현이 필요 없음
3) 여러 타입의 데이터가 저장 가능하다.
- 객체만 저장할 수 있기 때문에 필요에 따라 기본 자료형을 저장해야 하는 경우 Wrapper 클래스 사용

▶ 컬렉션의 주요 인터페이스

List, Set 코드 추상화
Map은 코드가 달라서 같이 추상화 X

▶ List

자료들을 순차적으로 나열한 자료구조로 인덱스로 관리되며, 중복해서 객체 저장 가능
구현 클래스로 ArrayList와 Vector, LinkedList가 있음

√ List 계열 주요 메서드

√ ArrayList
List의 후손으로 초기 저장 용량은 10으로 자동 설정되며 따로 지정도 가능
저장 용량을 초과한 객체들이 들어오면 자동으로 늘어나며 고정도 가능
동기화(Synchronized)를 제공하지 않음
예) List list = new ArrayList();

동기화 : 하나의 자원(데이터)에 대해 여러 스레드가 접근 하려 할 때 한 시점에서 하나의 스레드만 사용할 수 있도록 하는 것

√ Vector
List의 후손
ArrayList와 동등하지만 동기화(Synchronized)를 제공한다는 점이 ArrayList와 차이점
→ List 객체들 중에서 가장 성능이 좋지 않음

√ LinkedList
List의 후손으로, 인접 참조를 링크해 체인처러 관리
특정 인덱스에서 객체를 제거하거나 추가하게 되면 바로 앞/뒤 링크만 변경하면 되기 때문에 객체 삭제와 삽입이 빈번하게 일어나는 곳에서는 ArrayList보다 성능이 좋음

▶ Set

저장 순서가 유지되지 않고, 중복 객체도 저장하지 못하게 하는 자료 구조
null도 중복을 허용하지 않기 때문에 1개의 null만 저장
구현 클래스로 HashSet, LinkedHashSet, TreeSet이 있음

√ Set 계열 주요 메서드

√ HashSet
Set에 객체를 저장할 때 hash함수를 사용하여 처리 속도가 빠름
동일 객체 뿐 아니라 동등 객체도 중복하여 저장하지 않음

√ LinkedHashSet
HashSet과 거의 동일하지만 Set에 추가되는 순서를 유지한다는 점이 다름

▶ Enumeration, Iterator, ListIterator

컬렉션에 저장된 요소를 접근하는데 사용되는 인터페이스
- Enumeration : Iterator의 구버전
- ListIterator : Iterator를 상속받아 양방향 특징
[그림 1]의 상속구조 때문에 iterator() 메서드는 List와 Set 계열에서만 사용
→ Map의 경우 Set 또는 List화 시켜서 iterator()를 사용해야 함

▶ Map

키(Key)와 값(value)으로 구성되어 있으며, 키와 값은 모두 객체
키는 중복 저장을 허용하지 않고(Set방식), 값은 중복 저장 가능(List방식)
키가 중복되는 경우, 기존에 있는 키에 해당하는 값을 덮어 씌움
구현 클래스로 HashMap, HashTable, LinkedHashMap, Properties, TreeMap이 있음

√ Map 계열 주요 메서드

√ HashMap
키 객체는 hashCode()와 equals()를 재정의해 동등 객체가 될 조건을 정해야 함
때문에 키 타입은 hashCode와 equals()메서드가 재정의되어 있는 String타입을 주로 사용
예) Map <K, V> map = new HashMap<K, V>();

▶ Hashtable

키 객체 만드는 법은 HashMap과 동일하나 Hashtable은 스레드 동기화가 된 상태이기 때문에, 복수의 스레드가 동시에 Hashtable에 접근해 객체를 추가, 삭제 하더라도 스레드에 안전(Thread safe)
예) Map<K, V> map = new HashTable<K, V>();

Properties

키와 값을 String타입으로 제한한 Map컬렉션
주로 Properties는 프로퍼티(.properties)파일을 읽어 들일 때 주로 사용
√ 프로퍼티(
.properties) 파일
- 옵션정보, 데이터베이스 연결정보, 국제화(다국어)정보를 기록하여 텍스트 파일로 활용
- 애플리케이션에서 주로 변경이 잦은 문자열을 저장하여 관리하기 때문에 유지보수를 편리하게 만들어 줌
- 키와 값이 ‘=‘기호로 연결되어 있는 텍스트 파일로 ISO 8859-1 문자셋으로 저장되고, 한글은 유니코드(Unicode)로 변환되어 저장

▶ TreeSet과 TreeMap

검색 기능을 강화시킨 컬렉션으로, 계층 구조를 활용해 이진 트리 자료구조를 구현하여 제공

  • 트리 : 각 노드 간 연결된 모양이 나무와 같다고 해서 붙여진 이름

▶ TreeSet

이진 트리를 기반으로 한 Set컬렉션으로, 왼쪽과 오른쪽 자식 노드를 참조하기 위한 두 개의 변수로 구성

▶ TreeMap

이진 트리를 기반으로 한 Map 컬렉션으로, 키와 값이 저장된 Map.Entry를 저장하고
왼쪽과 오른쪽 자식 노드를 참조하기 위한 두 개의 변수로 구성

▶ TreeSet, TreeMap 정렬

√ 오름차순(기본 정렬)
- TreeSet의 객체와 TreeMap의 key는 저장과 동시에 자동 오름차순 정렬
- 숫자(Integer, Double) 타입일 경우 값으로 정렬
- 문자열(String) 타입일 경우 유니코드로 정렬
- 정렬을 위해 java.lang.Comparable을 구현한 객체 요구
그러지 않을 경우 ClassCastException 발생
(Integer, Double, String 모두 Comparable 인터페이스를 통해 오름차순이 구현되어 있음)

√ 내림차순(따로 구현)
- TreeSet, TreeMap 객체 생성 시 매개변수 생성자를 통해 재정렬 가능
ex. TreeSet tSet = new TreeSet(Comparator<? super E> comparator);
TreeMap<K, V> tMap = new TreeMap(Comparator<? super K> comparator);
- 또 다른 방법으로 숫자(Integer, Double), 문자열(String) 타입을 제외한 Comparable을
상속 받는 객체인 경우 compareTo() 메소드의 오버라이딩 부분을 내림차순으로 변경

package edu.kh.collection.list.run;

import edu.kh.collection.list.view.StudentView;

public class StudentRun {

	public static void main(String[] args) {
		StudentView view = new StudentView();
		
		view.displayMenu();
	}
}
package edu.kh.collection.list.dto;

import java.util.Objects;

// Comparable<T> 인터페이스
// - 객체의 기본 정렬 기준을 제공하는 인터페이스
public class Student implements Comparable<Student>{

	private String name;
	private int grade;
	private int classRoom;
	private int number;
	private String address;
	private char gender;
	private int score;
	
	public Student() {}
	
	public Student(String name, int grade, int classRoom, int number, String address, char gender, int score) {
		super();
		this.name = name;
		this.grade = grade;
		this.classRoom = classRoom;
		this.number = number;
		this.address = address;
		this.gender = gender;
		this.score = score;
	}

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public int getGrade() {
		return grade;
	}

	public void setGrade(int grade) {
		this.grade = grade;
	}

	public int getClassRoom() {
		return classRoom;
	}

	public void setClassRoom(int classRoom) {
		this.classRoom = classRoom;
	}

	public int getNumber() {
		return number;
	}

	public void setNumber(int number) {
		this.number = number;
	}
	public String getAddress() {
		return address;
	}

	public void setAddress(String address) {
		this.address = address;
	}

	public char getGender() {
		return gender;
	}

	public void setGender(char gender) {
		this.gender = gender;
	}

	public int getScore() {
		return score;
	}

	public void setScore(int score) {
		this.score = score;
	}

	@Override
	public String toString() {
		return "Student [name=" + name + ", grade=" + grade + ", classRoom=" + classRoom + ", number= " + number + ", address=" + address
				+ ", gender=" + gender + ", score=" + score + "]";
	}

	@Override
	public int hashCode() {
		return Objects.hash(address, classRoom, gender, grade, name, number, score);
	}

	@Override
	public boolean equals(Object obj) {
		if (this == obj)
			return true;
		if (obj == null)
			return false;
		if (getClass() != obj.getClass())
			return false;
		Student other = (Student) obj;
		return Objects.equals(address, other.address) && classRoom == other.classRoom && gender == other.gender
				&& grade == other.grade && Objects.equals(name, other.name) && score == other.score && number == other.number;
	}

	@Override
	public int compareTo(Student other) {  // o = other
		
		// Student 객체로 이루어진 컬렉션을 정렬하라고 할 때
		// 별도의 다른 기준이 없다면 score 순서로 정렬
		
		// compareTo() 메서드에서 반환되는 값이 
		// 0 이하이면 : 순서를 그대로 유지
		// 0 초과(양수) : 큰 값이 오른쪽(끝쪽)
		// -> 정확히는 리턴값이 양수이면 값이 큰 객체를 오른쪽으로 이동
		// return this.score - other.score;
		
		return other.score - this.score;
	}
}
package edu.kh.collection.list.view;

import java.util.InputMismatchException;
import java.util.List;
import java.util.Scanner;

import edu.kh.collection.list.dto.Student;
import edu.kh.collection.list.service.StudentService;

public class StudentView {

	private Scanner sc = new Scanner(System.in);
	private StudentService service = new StudentService();
	
	public void displayMenu() {
		int input = 0;
		
		do {
			try {
				System.out.println("\n--- 학생 관리 프로그램 ---\n");
				System.out.println("1. 학생 정보 추가");
				System.out.println("2. 학생 전체 조회");
				System.out.println("3. 학생 정보 수정");
				System.out.println("4. 학생 정보 제거");
				System.out.println("5. 학생 이름 검색");
				System.out.println("6. 학생 주소 검색");
				System.out.println("7. 학년별 조회");
				System.out.println("8. 성별 조회");
				System.out.println("9. 성적 순서 조회");
				System.out.println("0. 프로그램 종료");
				System.out.println();
				
				System.out.print("메뉴 선택 >> ");
				
				input = sc.nextInt();
				sc.nextLine();  // 입력 버퍼에 남은 개행문자 제거
				
				System.out.println();
				
				switch(input) {
				case 1: addStudent(); break;
				case 2: selectAll(); break;
				case 3: updateStudent(); break;
				case 4: removeStudent(); break;
				case 5: selectName(); break;
				case 6: selectAddress(); break;
				case 7: selectGrade(); break;
				case 8: selectGender(); break;
				case 9: sortScore(); break;
				case 0: System.out.println("[프로그램 종료]"); break;
				default : System.out.println("[잘못 입력하셨습니다.]");
				}
				
				
			} catch(InputMismatchException e) {
				System.out.println("[잘못된 형식의 입력입니다.]");
				sc.nextLine();  // 입력 버퍼에 잘못 입력된 내용 제거
				input = -1; // 반복문이 종료되는 것을 방지
			}
			
			System.out.println();
		}while(input != 0);
	}

	/**
	 * 학생 추가하기 
	 */
	private void addStudent() {
		System.out.println("\n--- 학생 정보 추가 ---\n");

		// 학생 정보 입력 메서드 호출 후 결과 반환 받기
		Student std = inputStudent();
		
		if(service.addStudent(std)) {
			System.out.println("[학생 정보가 추가되었습니다.]");
		}
	}
	
	/**
	 *  전체 학생 조회
	 */
	private void selectAll() {
		System.out.println("\n--- 전체 학생 조회 ---\n");
		
		List<Student> list = service.selectAll();
		
		// 향상된 for문
		for(Student s : list) {
//			System.out.println(s.toString());
			System.out.println(s);
			
			// print 관련 메서드에서
			// 참조변수를 출력하고자 매개변수로 전달하면
			// 자동으로 .toString()을 붙여서 호출 (컴파일러)
		}
	}
	
	/**
	 * 학생 정보 수정
	 */
	private void updateStudent() {
		System.out.println("\n--- 학생 정보 수정 ---\n");
		
		System.out.println("<수정할 학생 정보 입력>");
		
		// 학생 정보 입력 메서드 호출 후 결과 반환 받기
		Student std = inputStudent();
		
		System.out.println("-----------------------");
		System.out.print("수정할 학생의 index : ");
		int index = sc.nextInt();
		
		Student s = service.updateStudent(index, std);
		// s = 수정되기 전 학생 정보가 반환됨
		
		System.out.println(s.getName() + "의 정보가 수정 되었습니다.");
	}
	
	/** 학생 전체 정보를 입력 받아 Student 객체로 반환하는 메서드
	 * @return std : Student
	 */
	private Student inputStudent() {
		System.out.print("이름 : ");
		String name = sc.nextLine();
		
		System.out.print("학년 : ");
		int grade = sc.nextInt();
		
		System.out.print("반 : ");
		int classRoom = sc.nextInt();
		
		System.out.print("번호 : ");
		int number = sc.nextInt();
		sc.nextLine();  // 입력 버퍼 개행문자 제거
		
		System.out.print("주소 : ");
		String address = sc.nextLine();
		
		System.out.print("성별(F/M) : ");
		char gender = sc.next().toUpperCase().charAt(0);
		// String.toUpperCase() : 모두 대문자로 변경
		// String.toLowerCase() : 모두 소문자로 변경
		
		System.out.print("성적 : ");
		int score = sc.nextInt();
		
		Student std = new Student(name, grade, classRoom, number, address, gender, score);
		
		return std;
	}
	
	/**
	 * 학생 정보 제거
	 */
	private void removeStudent() {
		System.out.println("\n--- 학생 정보 제거 ---\n");
		System.out.print("삭제할 학생의 인덱스 입력 : ");
		int index = sc.nextInt();
		
		// 제거되기 전 학생 정보가 반환됨
		Student s = service.removeStudent(index);
		
		System.out.println(s.getName() + "학생 정보가 제거되었습니다.");
	}
	
	private void selectName() {
		System.out.println("\n--- 학생 이름 검색 ---\n");
		System.out.print("검색할 학생의 이름 : ");
		String name = sc.nextLine();
		
		List<Student> list = service.selectName(name);
		
		// 만약 검색 결과가 없을 경우
		// list.size() : 리스트에 저장된 객체의 수
		// list.isEmpty() : 리스트에 저장된 객체가 없다면 true
		
//		if(list.size() == 0) {  // 저장된 객체의 수가 0개인 경우
		if(list.isEmpty()) {  // 리스트에 저장된 객체가 없을 경우
			System.out.println("[검색 결과가 없습니다.]");
		} else {
			for(Student s : list) System.out.println(s);
		}
	}
	
	private void selectAddress() {
		System.out.println("\n--- 학생 주소 검색 ---\n");
		System.out.print("검색할 주소 : ");
		String input = sc.nextLine();
		
		List<Student> list = service.selectAddress(input);
		
		// 만약 검색 결과가 없을 경우
		// list.size() : 리스트에 저장된 객체의 수
		// list.isEmpty() : 리스트에 저장된 객체가 없다면 true
		
//		if(list.size() == 0) {  // 저장된 객체의 수가 0개인 경우
		if(list.isEmpty()) {  // 리스트에 저장된 객체가 없을 경우
			System.out.println("[검색 결과가 없습니다.]");
		} else {
			for(Student s : list) System.out.printf("%d학년 %d반 %2d번 %s / 주소 : %s \n",s.getGrade(),s.getClassRoom(),s.getNumber(),s.getName(),s.getAddress());
		}
	}
	
	private void selectGrade() {
		System.out.println("\n--- 학년별 조회 ---\n");
		
		/* 조회할 학년을 입력하세요 : 3
		 * 
		 * ***** 조회한 학년이 있을 경우 ***** 
		 * [3학년 조회 결과]
		 * 3학년 5반 2번 홍길동
		 * 3학년 2반 1번 이미영
		 * 
		 * ***** 조회한 학년이 없을 경우 *****
		 * [3학년 학생이 존재하지 않습니다]
		 * */
		
		System.out.print("조회할 학년을 입력하세요 : ");
		int input = sc.nextInt();
		sc.nextLine();
		
		List<Student> list = service.selectGrade(input); 
		
		if(list.isEmpty()) System.out.printf("[%d학년 학생이 존재하지 않습니다]", input);
		else {
			System.out.printf("[%d학년 조회 결과]\n", input);
			for(Student s : list) System.out.printf("%d학년 %d반 %2d번 %s", s.getGrade(),s.getClassRoom(),s.getNumber(),s.getName() );
		}
	}
	
	/**
	 * 성별 조회
	 */
	private void selectGender() {
		System.out.println("\n--- 성별 조회 ---\n");
		
		/* 조회할 성별을 입력하세요(M/F) : m / M / f / F  (대소문자 구분 X)
		 * 
		 * ***** 잘못 입력하는 경우 *****
		 * 조회할 성별을 입력하세요(M/F) : a
		 * 
		 * [M 또는 F만 입력 해주세요.]
		 * 
		 * 조회할 성별을 입력하세요(M/F) : (정상 입력이 될 때까지 무한 반복)
		 * 
		 * ***** 정상 입력인 경우 *****
		 * 조회할 성별을 입력하세요(M/F) : F
		 * [여학생 목록]
		 * 2학년 7반 12번 김갑순(F)
		 * 2학년 3반  8번 이미영(F)
		 * 
		 * (무한 반복 종료)
		 * */
		while(true) {
			System.out.print("조회할 성별을 입력하세요(M/F) : ");
			String input = sc.nextLine().toUpperCase();
		
			if(!input.equals("M") && !input.equals("F")) {
				System.out.println("[M 또는 F만 입력 해주세요.]");
			} else {
				List<Student> list = service.selectGender(input);
				
				char gender = input.equals("M") ? '남' : '여';
				System.out.printf("[%s학생 목록]\n", gender);
				
				for(Student s : list) System.out.printf("%d학년 %d반 %2d번 %s(%s)\n",s.getGrade(),s.getClassRoom(),s.getNumber(),s.getName(),s.getGender());
				break;
			}
		}
	}
	/**
	 * 성저 순서 조회
	 */
	private void sortScore() {
		System.out.println("\n--- 성적 순서 조회 ---\n");
		
		// 성적 순서로 정렬
		List<Student> studentList = service.sortScore();
		
		for(Student s : studentList) {
			System.out.println(s);
		}
	}
}
package edu.kh.collection.list.service;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

import edu.kh.collection.list.dto.Student;

public class StudentService {

	private List<Student> studentList = new ArrayList<Student>();
	
	public StudentService() {
		studentList.add(new Student("홍길동", 3, 5, 17, "서울시 중구 남대문로", 'M', 75));
		studentList.add(new Student("손오공", 1, 1, 1, "제주시 서귀포구 해안로 ", 'M', 100));
		studentList.add(new Student("루피", 4, 7, 21, "서울시 노원구 하계로", 'M', 89));
		studentList.add(new Student("원펀맨", 2, 4, 2, "대구시 몰라 이상한로", 'F', 45));
		studentList.add(new Student("김나미", 8, 6, 7, "서시 구 문로", 'F', 75));
	}
	/** studentList에 학생 추가
	 * @param std
	 * @return true
	 */
	public boolean addStudent(Student std) {
		return studentList.add(std);
	}
	
	/** 학생 전체 조회 서비스
	 * @return studentList
	 */
	public List<Student> selectAll() {
		return studentList;
	}
	
	/** 학생 정보 수정 서비스
	 * @param index
	 * @param std
	 * @return s:Student (수정되기 전 학생 정보)
	 */
	public Student updateStudent(int index, Student std) {
		
		// set(int index, E e) : 1) index에 위치하는 요소를 e로 변경
		//						 2) 기존에 있던 요소 e2를 반환
		
		return studentList.set(index, std);
	}
	
	/** 학생 정보 제거 서비스
	 * @param index
	 * @return s:Student (제거된 학생 정보)
	 */
	public Student removeStudent(int index) {

		// E remove(int index) : index번째 요소를 List에서 제거하여 반환
		
		// boolean remove(E e) : List에서 E와 일치하는 요소를 찾아서
		//						 있으면 제거하고 true
		//						 없으면 false 반환
		
		
		return studentList.remove(index);
	}
	public List<Student> selectName(String name) {
		
		// 1) 검색 결과를 저장할 List<Student> 생성
		List<Student> list = new ArrayList<Student>();
		
		// 2) studentList의 모든 요소를 순차 접근하면서 이름이 일치하는 학생을
		//    list에 추가
		
		for(Student s : studentList) {
			if(s.getName().equals(name)) list.add(s);
		}
		
		// 3) 검색 결과를 반환
		return list;
	}
	
	/** 학생 주소 검색 서비스
	 * @param input
	 * @return list:List<Student> 검색어가 주소에 포함된 학생 리스트
	 */
	public List<Student> selectAddress(String input) {
		
		List<Student> list = new ArrayList<Student>();
		
		for(Student s : studentList) {
			// String.contains("문자열") : String에 "문자열"이 포함되어 있으면 true 반환
			if(s.getAddress().contains(input)) list.add(s);
		}
		
		return list;
	}
	
	/** 학년별 검색
	 * @param input
	 * @return list:List<Student> input과 학년이 같은 학생 리스트
	 */
	public List<Student> selectGrade(int input) {
		
		List<Student> list = new ArrayList<Student>();
		// 제네릭의 타입 추론
		// - 생성되는 컬렉션 객체의 제네릭을 별도 작성하지 안하도
		//   참조 변수의 제네릭을 통해 제한되는 타입을 유추(추론)
		
		for(Student s : studentList) if(s.getGrade() == input) list.add(s);
		
		return list;
	}
	public List<Student> selectGender(String input) {
		
		List<Student> list = new ArrayList<>();
		
		for(Student s : studentList) {
			if(input.charAt(0) == s.getGender()) list.add(s);
		}
		return list;
	}
	
	/**
	 * 성적 순서 조회 서비스
	 * @return 
	 */
	public List<Student> sortScore() {
		
		// studentList 정렬 (score 내림 차순)
		// - Collections 클래스 : 컬렉션에 도움되는 유용한 기능을 모은 클래스
		// - Comparable<T> 인터페이스
		//   -> 객체의 기본 정렬 기준을 제공하는 인터페이스
		
		// <?> : 어떤게 작성될지 모름 == 아무거나 작성 가능
		// <?> void java.util.Collections.sort(List<?> list)
		
		Collections.sort(studentList);
		// studentList에 저장된 객체 Student의
		// 오버라이딩된 compareTo() 메서드를 이용해서 정렬
		// -> 현재 큰 숫자가 오른쪽으로 이동하도록 오버라이딩 됨
		// -> 오름차순 정렬
		
		// void Collections.reverse(List<?> list)
		// - list 순서를 반대로 뒤집음
		// -> 오름차순 --> 내림차순
//		Collections.reverse(studentList);
		
		return studentList;
	}
}
package edu.kh.collection.list.run;

import edu.kh.collection.list.service.ListService;

public class ListRun {

	public static void main(String[] args) {
		ListService service = new ListService();
//		service.ex1();
		service.ex2();
	}
}
package edu.kh.collection.list.service;

import java.util.ArrayList;
import java.util.List;

public class ListService {

	/* List : 자료들을 순차적으로 나열한 자료구조 (배열과 비슷함)
	 * 
	 * - 인덱스를 이용해서 순서를 유지
	 * - 순서 구분이 가능하기 때문에 중복되는 데이터를 저장할 수 있다.
	 * 
	 * List 인터페이스를 구현한 대표적인 클래스
	 * -> ArrayList(신), Vector(구), LinkedList
	 * */
	
	public void ex1() {
		/* 컬렉션 특징
		 * 1) 크기 제약이 없다.
		 * 2) 추가, 삭제, 수정 등의 기능이 구현되어 있다.
		 * 3) 여러 타입의 객체를 저장할 수 있다.
		 *    -> Object 타입의 참조변수 묶음이기 때문에.
		 * */
		
		// ** 컬렉션은 모두 java.util 패키지에 존재 **
		// utility : 유용
		
		// ArrayList list = new ArrayList();  // 기본 생성자 -> 10칸짜리 생성
		
		ArrayList list = new ArrayList(3);  // 매개변수 생성자 -> 3칸짜리 생성
		
		// -> 예상되는 데이터 수에 따라 생성자를 골라서 사용
		// -> 생성자에 따라 속도, 메모리 효율이 달라짐
		
		// boolean add(E e) : 리스트 마지마에 요소 추가
		// * E(Element) : 요소(객체)를 의미하는 제네릭 표기법
		//                == Object 타입으로 생각하면 됨.
		
		list.add("아무거나");
		list.add(123);  // Integer로 저장
		list.add(3.14);  // Double로 저장
						 // -> Auto Boxing
		
		list.add("초과");  // List 범위 3 초과
						   // -> 자동으로 크기 증가
		
		// void add(int index, E e) : 원하는 index 위치에 요소 추가
		list.add(1, "중간삽입");
		
//		list.add(10, "삽입");  // 오류 발생
		
		// E get(int index): 주어진 index의 요소를 반환
		// int size() : 리스트 크기 X, 리스트에 저장된 요소의 개수
		
//		System.out.println(list.get(3));
		
		for(int i=0;i<list.size();i++) {
			System.out.println(list.get(i));
			// * 컬렉션에서 여러 데이터 타입을 저장할 경우의 단점 *
			// - 각 요소마다 타입이 다르기 때문에 
			//   원하는 코드가 있을 경우 타입검사 + 다운 캐스팅이 강제됨
			if(list.get(i) instanceof String) {  // 요소가 String인 경우
				char ch = ((String)list.get(i)).charAt(0);
				System.out.println("ch : " + ch);
			} else if(list.get(i) instanceof Integer) {  // 요소가 Integer인 경우
				int max = ((Integer)list.get(i)).MAX_VALUE;
				System.out.println("max : " + max);
			}  else if(list.get(i) instanceof Double) {
				double min = ((Double)list.get(i)).MIN_VALUE;
				System.out.println("min : " + min);
			}
		}
		System.out.println("---------------");
	}
	
	public void ex2() {
		// 제네릭을 이용한 컬렉션 타입 체크
		// - <타입> 형식으로 작성
		
		List<String> list = new ArrayList<String>();
		// String으로 타입이 제한된 ArrayList 객체를 생성하여
		// 부모 타입인 List로 참조
		
		// 컴파일 단계에서 타입 체크 
		// -> 컬렉션에 사용되는 객체의 타입이
		//    컬렉션 생성 시 지정된 타입과 같은지 확인
		//    + 자동으로 다운캐스팅 진행
		// boolean list.add(String e)
		
		list.add("그만좀");
		list.add("졸아라");
		list.add("누군지 아시죠??");
		
		for(int i=0;i<list.size();i++) {
			String str = list.get(i);  // 다운캐스팅 필요 X
			System.out.println(str.charAt(0));
		}
		System.out.println("---------------");
		
		// 향상된 for문
		// - 배열/컬렉션의 모든 요소를 순차적으로 접근하는 반복문
		for(String s : list) {
			System.out.println(s);
		}
	}
}
package edu.kh.collection.map.run;

import edu.kh.collection.map.service.MapService;

public class MapRun {

	public static void main(String[] args) {
		
		MapService service = new MapService();
//		service.ex1();
		service.ex2();
	}
}
package edu.kh.collection.map.service;

import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Scanner;
import java.util.Set;

public class MapService {

	public void ex1() {
		/* Map : 특정 키워드(key)를 입력하면 상세한 값(value)이 나온다
		 * 
		 * - Key: Value 형태의 데이터를 모아둔 컬렉션 객체
		 * 
		 * - Key만 모아서 봤을 때 Set의 특징을 지님
		 *   -> 중복 X, 순서 유지 X
		 *   
		 * - Value만 모아서 봤을 때 
		 *  --> Key로 인해서 값이 구분되기 때문에
		 *      중복 허용 (List의 특징을 지님)
		 * 
		 * */
		
		Map<Integer, String> map = new HashMap<>();
		// Key는 Integer로 제한
		// Value는 String으로 제한
		
		// V put(K k, V v) : Map 추가
		
		map.put(1, "김밥");
		map.put(2, "라면");
		map.put(3, "떡볶이");
		map.put(4, "돈까스");
		System.out.println(map);
		
		// key가 중복되는 경우 -> 덮어 씌움
		map.put(4, "치즈돈까스");
		System.out.println(map);
		
		// V get(K k) : Key에 해당하는 Value 반환
		System.out.println(map.get(3));
		
		// Map에서 Key만 묶어보면 Set의 특징을 갖는다
		// + 향상된 for문
		// -> Map에 저장된 모든 객체의 Value만 출력하기
		Set<Integer> keys = map.keySet();
		// Set<T> keySet() : key만 모아서 Set 형태로 반환
		
		System.out.println("-------------------------------------------------");
		for(Integer k : keys) {
			System.out.println(k + " : " + map.get(k));
		}
	}

	public void ex2() {
		// Map은 언제 사용하면 좋을까?
		// 1) 한 번에 다량의 데이터를 전달해야 하는 경우
		//    + 데이터의 명확한 구분이 필요한 경우
		
		// 2) DTO(Data Transfer Object) : 값 전달용 객체
		//    - 재사용성이 적은 DTO를 대체하는 경우
		
		// 3) 별도의 DTO가 없을 경우
		
//		Map<String, Object> member = new HashMap<>();
		Map<String, Object> member = new LinkedHashMap<>();
		
		// value가 Object 타입
		// -> Object는 모든 클래스 최상위 부모
		//   == 모든 객체의 부모 타입의 참조변수로 사용 가능(다형성)
		//   == value에 어떤 객체든 작성 가능
		
		// member에 값 추가
		member.put("memberId", "mem01");
		member.put("memberPw", "pass01");
		member.put("memberName", "테스트1");
		member.put("memberAge", 23);  // Auto Boxing 적용
		member.put("memberGender", 'M');
		
		Scanner sc = new Scanner(System.in);
		
		System.out.print("ID : ");
		String id = sc.next();
		
		System.out.print("PW : ");
		String pw = sc.next();
		
		// id, pw가 member와 모두 일치하면 member 정보 출력
		
		if(member.get("memberId").equals(id)) {
			// value가 Object 타입이기 때문에
			// equals()는 Object의 equals() 코드와 연결됨 == 정적 바인딩
			
			// 하지만 프로그램 수행 시
			// 실제 참조하는 객체의 타입 String의 equals()로 연결됨 == 동적 바인딩
			
			if(member.get("memberPw").equals(pw)) {
				
				// member의 모든 정보 출력
				for(String key : member.keySet()) {
					System.out.println(key + " : " + member.get(key));
				}
			} else {
				System.out.println("비밀번호가 일치하지 않습니다.");
			}
			
		} else {
			System.out.println("아이디가 일치하지 않습니다.");
		}
	}
}
package edu.kh.collection.set.run;

import edu.kh.collection.set.service.SetService;

public class SetRun {

	public static void main(String[] args) {
		
		SetService service = new SetService();
//		service.ex1();
//		service.ex2();
		service.creatLotto();
	}
}
package edu.kh.collection.set.service;

import java.util.ArrayList;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Random;
import java.util.Set;
import java.util.TreeSet;

import edu.kh.collection.list.dto.Student;

public class SetService {

	public void ex1() {
		// Set(집합)
		// - 순서를 유지하지 않음 (인덱스 X)
		// - 중복 데이터 저장 불가(같은 객체를 덮어 씌움)
		//   -> null도 1개만 저장 가능
		
		// 대표적인 자식 클래스
		// HashSet, LinkedHashSet, TreeSet
		
		Set<String> set = new HashSet<>();  // <> 타입 추론
		set.add("네이버");
		set.add("카카오");
		set.add("라인");
		set.add("쿠팡");
		set.add("배달의민족");
		set.add("당근마켓");
		set.add("토스");
		set.add("직방");
		set.add("야놀자");
		// 순서 유지 X
		
		set.add("야놀자");
		set.add("야놀자");
		set.add("야놀자");
		set.add("야놀자");
		// 중복 저장 X
		
		set.add(null);
		set.add(null);
		set.add(null);
		// null도 추가할 수 있지만 1개만 가능(중복 제거)
		
//		System.out.println(set.toString());
		System.out.println(set);
		
		// boolean remove(Object o)
		// - Set에 저장된 객체 중 같은 객체를 찾아 제거
		//   같은 객체가 있어서 제거되면 true / 아니면 false
		
		// - 같은 객체의 기준 == equals() -> true, hashCode() 같음
		
		if(set.remove("직방"))	 System.out.println("직방이 제거되었습니다.");
		else					 System.out.println("직방이 존재하지 않습니다.");
		System.out.println(set);
		
		if(set.remove("직방"))	 System.out.println("직방이 제거되었습니다.");
		else					 System.out.println("직방이 존재하지 않습니다.");
		System.out.println(set);
		
		System.out.println("------------------------------------------------------------------------------");
		
		// Set에 저장된 요소 하나씩 얻어오기
		
		// 1. Iterator (반복자)  속도가 조금 더 빠름
		
		// * 코드 설명에 iterator, iterable 단어가 포함되어 있다면 
		//   반복 접근(순차 접근)이 가능하다라고 판단
		
		// - 컬렉션에서 제공하는 컬렉션 객체의 요소를 반복 접근하는 객체
		
		Iterator<String> it = set.iterator();
		// Set 객체에는 반복자 Iterator 객체가 붙어있다고 생각!
		
		while(it.hasNext()) {
			// it.hasNext() : 다음 꺼내올 객체가 존재하면 true
			
			String temp = it.next();
			// it.next() : 다음 객체를 꺼내옴
			
			System.out.println(temp);
		}
		
		System.out.println("------------------------------------------------------------------------------");
		
		// 2. 향상된 for문 이용
		for(String s : set) {
			System.out.println(s);
		}
	}
	
	public void ex2() {
		
		// Set이 저장된 객체가 중복임을 확인하는 방법
		// -> equals()를 통해 필드 값이 같으면 중복
		//  --> equals() 오버라이딩 필수
		
		// Hash가 붙은 Set/Map
		// - Hash가 붙은 이유 : 속도 향상
		//  --> hashCode() 오버라이딩 필수
		//   ---> equals()가 true일 때 hashCode()도 같아야 한다(규칙)
		//   === Hash가 붙은 Set/Map은 hashCode()를 이용해서 중복 판단
		
		// 최종 결론 : Hash가 붙은 Set/Map을 사용하려면
		// equals(), hashCode() 오버라이딩이 필수이다!
		
		Set<Student> set = new HashSet<>(); 
		
		set.add(new Student("홍길동", 1, 2, 3, "서울시 어딘가", 'M', 50));
		set.add(new Student("홍길동", 1, 2, 3, "서울시 어딘가", 'M', 50));
		set.add(new Student("홍길동", 1, 2, 3, "서울시 어딘가", 'M', 50));

		for(Student s : set) {
			System.out.println(s);
		}
	}
	
	public void creatLotto() {
		
		// 로또 번호 5세트 만들어서 출력하기
		
		List<Set<Integer>> lottoList = new ArrayList<>();
		
		Random random = new Random();
		
		for(int i=0;i<5;i++) {
			
//			Set<Integer> set = new HashSet<>();  // 검색 속도가 좋은 Set
			Set<Integer> set = new TreeSet<>();  // 이진트리 구조를 이용해 정렬을 지원하는 Set 
			
			while(set.size() < 6) {
				// set에 저장된 객체의 수가 6개 미만이면 반복
				// == 6개면 멈추겠다
				set.add(random.nextInt(45)+1); // 1 ~ 45
			}
			
			// 완성된 한세트의 로또번호를 List에 추가
			lottoList.add(set);
			
		}
		
		// 로또 번호 확인
		for(Set<Integer> set : lottoList) {
			System.out.println(set);
		}
	}
}
profile
김찬희입니다.

0개의 댓글