자바에서 제공하는 자료구조를 담당하는 프레임워크
- 추가, 삭제, 정렬 등의 기능처리가 간단하게 해결 되어 자료구조적 알고리즘을 구현할 필요 없음
- java.util 패키지에 포함되며, 인터페이스를 통해 정형화된 방법으로 다양한 컬렉션 클래스 이용 가능
한 번 크기를 지정하면 변경할 수 없다.
배열에 기록된 데이터에 대한 중간 위치의 추가, 삭제가 불편하다.
한 타입의 데이터만 저장 가능하다.
자료들을 순차적으로 나열한 자료구조
- 인덱스로 관리되며, 중복해서 객체 저장 가능
- 구현 클래스 : ArrayList, Vector, LinkedList
- List의 후손으로 초기 저장 용량은 10으로 자동 설정되며 따로 지정도 가능
- 저장 용량을 초과한 객체들이 들어오면 자동으로 늘어나며 고정도 가능
- 동기화(Synchronized)를 제공하지 않음
- List의 후손으로, 인접 참조를 링크해 체인처럼 관리
- 특정 인덱스에서 객체를 제거하거나 추가하게 되면 바로 앞/뒤 링크만 변경하면 되기 때문에
객체 삭제와 삽입이 빈번하게 일어나는 곳에서는 ArrayList보다 성능이 좋음
ArrayList() 기본 생성자
: 기본 크기 10짜리 리스트 생성
-> 하지만 리스트는 크기가 늘었다 줄었다 하기 때문에 큰 의미 없음
ArrayList(용량)
: 용량 만큼의 리스트 생성
-> 너무 큰 값을 작성하면 메모리를 많이 소모함
List.add(Object e)
: 리스트에 객체를 추가
Object List.get(index i)
: 리스트에서 i번째 인덱스에 있는 객체(Object)를 반환
int List.size()
: List에 저장된 데이터의 개수를 얻어오는 방법
-> 배열명.length 대신 사용
boolean java.util.List.isEmpty()
: List가 비어 있는지 확인하는 방법
-> 비어 있으면 true를 반환
Object List.set(int index, Object e)
: List의 i번째 요소를 전달받은 e로 변경
-> 반환값 Object == 변경 전 Object 객체가 담겨 있음
Object List.remove(int index)
: List에서 index번째 요소를 제거
-> 이때, 제거된 요소가 반환됨
-> List는 중간에 비어 있는 인덱스가 없게 하기 위해서 remove() 동작 시 뒤쪽 요소를 한 칸씩 당겨옴
제네릭스(Generics) - < >
: 컬렉션에 저장되는 객체 타입을 한 가지로 제한
List<Student> studentList = new ArrayList<Student>();
// Student로 저장되는 타입이 제한된 리스트 생성
// == Student만 저장 가능 == 모든 게 Student
// == Student임을 검사할 필요가 없다.
package edu.kh.collection.model.vo;
public class Student {
private String name; // 이름
private int age; // 나이
private String region; // 사는 곳
private char gender; // 성별
private int score; // 점수
public Student() {} // 기본 생성자
// 매개변수 생성자
public Student(String name, int age, String region, char gender, int score) {
super();
this.name = name;
this.age = age;
this.region = region;
this.gender = gender;
this.score = score;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getRegion() {
return region;
}
public void setRegion(String region) {
this.region = region;
}
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;
}
// toString() 오버라이딩 자동 완성
// alt + shift + s -> s (Generate toString) .. -> enter
@Override
public String toString() {
return "Student [name=" + name + ", age=" + age + ", region=" + region + ", gender=" + gender + ", score="
+ score + "]";
}
}
package edu.kh.collection.model.service;
import java.util.ArrayList;
import java.util.InputMismatchException;
import java.util.List;
import java.util.Scanner;
import edu.kh.collection.model.vo.Student;
public class StudentService {
// 필드
private Scanner sc = new Scanner(System.in);
// 학생 정보를 저장할 List(객체 배열 Upgrade 버전)
// java.util.List 인터페이스 : List에 반드시 필요한 필수 기능을 모아둔 인터페이스
// * 인터페이스는 객체 생성 X, 부모 참조 변수 O
// ArrayList() 기본 생성자 : 기본 크기 10짜리 리스트 생성
// -> 하지만 리스트는 크기가 늘었다 줄었다 하기 때문에 큰 의미 없음
// ArrayList(용량) : 용량 만큼의 리스트 생성
// -> 너무 큰 값을 작성하면 메모리를 많이 소모함
// private List<Student> studentList = new ArrayList<Student>(); // 검색(조회)에 효율적
private List<Student> studentList = new LinkedList<Student>(); // 추가, 수정, 삭제에 효율적
// Student로 저장되는 타입이 제한된 리스트 생성
// == Student만 저장 가능 == 모든 게 Student
// == Student임을 검사할 필요가 없다.
public StudentService() {
studentList.add(new Student("박서준", 25, "서울시 중구", 'M', 50));
studentList.add(new Student("아이유", 22, "경기도 용인시", 'f', 40));
studentList.add(new Student("정해인", 26, "서울시 광진구", 'f', 20));
studentList.add(new Student("박보영", 25, "충북 청주시", 'M', 80));
studentList.add(new Student("장원영", 25, "서울시 강남구", 'f', 70));
}
public void ex() {
// List 테스트
// List.add(Object e) : 리스트에 객체를 추가
// * 매개변수 타입이 Object == 모든 객체 매개변수로 전달할 수 있음
// (매개변수 Object == 최상위 부모 참조 변수 == 다형성 적용 가능)
studentList.add(new Student()); // 0번 인덱스
// studentList.add(sc); // 1번 인덱스
// studentList.add("문자열"); // 2번 인덱스
// studentList.add(new Object()); // 3번 인덱스
// -> 컬렉션 특징 : 여러 타입의 데이터를 저장할 수 있다.
// (반환형)
// Object List.get(index i) : 리스트에서 i번째 인덱스에 있는 객체(Object)를 반환
// 반환형이 Object == 모든 객체를 반환할 수 있다.
System.out.println(studentList.get(0).toString());
// 실행 전 : String java.lang.Object.toString() == 정적 바인딩
// 실행 후 : 알고 보니 0번째는 Student 객체이고, toString()이 오버라이딩 되어 있음
// -> Student의 toString()이 수행됨 == 동적 바인딩
// Student의 이름만 얻어 오기
// Student 객체가 맞는지 확인하고 다운 캐스팅을 해야
// Student 기능을 사용할 수 있다.
if(studentList.get(0) instanceof Student) {
System.out.println( ((Student)studentList.get(0)).getName() );
}
// -> 길고 복잡함
// -> 컬렉션의 장점인 여러 객체 저장이 코딩에 방해됨
// ******************** 그래서 등장했다 -> 제네릭스(Generics) ********************
// (보통 제네릭이라고 함) <>
// [제일 중요한 역할]
// -> 컬렉션에 저장되는 객체 타입을 한 가지로 제한
System.out.println(studentList.get(0).getName());
}
// 메소드 설명용 주석 (alt + shift + j)
/**
* 메뉴 출력용 메소드
* @author 만든이
*/
public void displayMenu() {
int menuNum = 0;
do {
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("0. 프로그램 종료");
System.out.print("\n 메뉴 번호 선택 >> ");
try {
menuNum = sc.nextInt();
System.out.println(); // 줄바꿈
switch(menuNum) {
case 1: System.out.println(addStudent()); break;
case 2: selectAll(); break;
case 3: System.out.println(updateStudent()); break;
case 4: System.out.println(removeStudent()); break;
case 5: searchName1(); break;
case 6: searchName2(); break;
case 0: System.out.println("<프로그램 종료>"); break;
default : System.out.println("메뉴에 작성된 번호만 입력해 주세요.");
}
} catch(InputMismatchException e) {
System.out.println("\nerror : 입력 형식이 유효하지 않습니다. 다시 시도해 주세요.");
sc.nextLine(); // 입력 버퍼에 남아 있는 잘못 입력된 문자열 제거
menuNum = -1; // 첫 반복 시 잘못 입력하는 경우 menuNum이 0을 가지고 있어 종료되는데
// 이를 방지하기 위해 임의값 -1 대입
}
} while(menuNum != 0);
}
/**
* 1. 학생 정보 추가 메소드
* - 추가 성공 시 "성공", 실패 시 "실패" 문자열 반환
*/
public String addStudent() throws InputMismatchException {
System.out.println("======= 학생 정보 추가 ======");
System.out.print("이름 : ");
String name = sc.next();
System.out.print("나이 : ");
int age = sc.nextInt();
sc.nextLine(); // 입력 버퍼 개행 문자 제거
System.out.print("사는 곳 : ");
String region = sc.nextLine();
System.out.print("성별(M/F) : ");
char gender = sc.next().toUpperCase().charAt(0);
// String -> char
System.out.print("점수 : ");
int score = sc.nextInt(); // InputMismatchException
// Student 객체 생성 후 List에 추가
if(studentList.add( new Student(name, age, region, gender, score) )) {
// boolean java.util.List.add(Student e)
// (반환형) -> 제네릭 <Student> 때문에 List 타입이 Student로 제한됨
// add()는 무조건 true 반환하기 때문에
// 솔직히 실패하는 경우는 없음
// 대신 예외가 발생해서 add() 수행 전 메소드가 종료될 수는 있음
return "성공";
} else {
return "실패";
}
}
/**
* 2. 학생 전체 조회 메소드
*/
public void selectAll() {
// - List는 인덱스가 있다. (0번부터 시작)
// - List에 저장된 데이터의 개수를 얻어오는 방법 : int List.size()
// -> 배열명.length 대신 사용
// - List가 비어 있는지 확인하는 방법 :
// boolean java.util.List.isEmpty() : 비어 있으면 true를 반환
System.out.println("====== 학생 전체 조회 ======");
// studentList가 비어 있는 경우 "학생 정보가 없습니다." 출력
//if(studentList.size() == 0) {
if(studentList.isEmpty()) {
System.out.println("학생 정보가 없습니다.");
return; // 현재 메소드를 종료하고 호출한 곳으로 돌아감
// 단, 반환값은 없음(void)
}
/* 일반 for문
for(int i=0; i<studentList.size(); i++) {
System.out.println( studentList.get(i) );
// StudentList에서 i번째 인덱스 요소를 얻어와 출력
}
*/
// 향상된 for문 (for each문)
// - 컬렉션, 배열의 모든 요소를 순차적으로 반복 접근할 수 있는 for문
// (순차적 : 0번 인덱스부터 마지막 요소까지 인덱스를 1씩 증가)
// [작성법]
// for(컬렉션 또는 배열에서 꺼낸 한 개의 요소를 저장할 변수 : 컬렉션명 또는 배열명){ }
int index = 0;
for( Student std : studentList ) {
// std에는 for문 반복 시마다 0, 1, 2, ... 인덱스 요소들 한 번씩 저장됨
System.out.print( (index++) + "번 : ");
System.out.println( std );
}
}
/**
* 학생 정보 수정 메소드
*/
public String updateStudent() throws InputMismatchException {
// - Student List.set(int index, Student e)
// -> List의 i번째 요소를 전달받은 e로 변경
// -> 반환값 Student == 변경 전 Student 객체가 담겨 있음
System.out.println("========== 학생 정보 수정 ==========");
System.out.print("인덱스 번호 입력 : ");
int index = sc.nextInt();
sc.nextLine();
// 1) 학생 정보가 studentList에 있는가?
if( studentList.isEmpty() ) {
return "입력된 학생 정보가 없습니다.";
// 2) 입력된 숫자가 0보다 작은가? (음수 검사)
} else if( index < 0) {
return "음수는 입력할 수 없습니다.";
// 3) 만약 문자열을 입력한 경우 -> throws로 예외 처리
// 4) 입력 받은 숫자가 studentList 범위 내 인덱스 번호인가?
} else if(index >= studentList.size()) {
return "범위를 넘어선 값을 입력할 수 없습니다.";
} else {
// 수정 코드 작성
System.out.println(index + "번째 인덱스에 저장된 학생 정보");
System.out.println(studentList.get(index));
System.out.print("이름 : ");
String name = sc.next();
System.out.print("나이 : ");
int age = sc.nextInt();
sc.nextLine(); // 입력 버퍼 개행 문자 제거
System.out.print("사는곳 : ");
String region = sc.nextLine();
System.out.print("성별(M/F) : ");
char gender = sc.next().charAt(0);
// String -> char
System.out.print("점수 : ");
int score = sc.nextInt(); // InputMismatchException
// 입력받은 index번째에 새로운 학생 정보를 세팅 == 수정
// 이때, index번째에 있던 기존 학생 정보가 반환된다.
Student temp = studentList.set(index, new Student(name, age, region, gender, score));
return temp.getName() + "의 정보가 변경되었습니다.";
}
}
/**
* 학생 정보 제거 메소드
*/
public String removeStudent() throws InputMismatchException {
// - Student List.remove(int index)
// 리스에서 index번째 요소를 제거
// 이때, 제거된 요소가 반환된다.
// * List는 중간에 비어 있는 인덱스가 없게 하기 위해서
// remove() 동작 시 뒤쪽 요소를 한 칸씩 당겨온다.
System.out.println("======= 학생 정보 제거 =======");
System.out.print("인덱스 번호 입력 : ");
int index = sc.nextInt();
sc.nextLine();
// 1) 학생 정보가 studentList에 있는가?
if( studentList.isEmpty() ) {
return "입력된 학생 정보가 없습니다.";
// 2) 입력된 숫자가 0보다 작은가? (음수 검사)
} else if( index < 0) {
return "음수는 입력할 수 없습니다.";
// 3) 만약 문자열을 입력한 경우 -> throws로 예외 처리
// 4) 입력 받은 숫자가 studentList 범위 내 인덱스 번호인가?
} else if(index >= studentList.size()) {
return "범위를 넘어선 값을 입력할 수 없습니다.";
} else {
// 학생 정보 제거
System.out.print("정말 삭제하시겠습니까?(Y/N) : ");
char ch = sc.next().toUpperCase().charAt(0);
// String -> 대문자 String -> 대문자 0번째 인덱스 문자
// String.toUpperCase() : 문자열을 대문자로 변경
if(ch == 'Y') {
Student temp = studentList.remove(index);
return temp.getName() + "의 정보가 제거되었습니다.";
} else {
return "취소";
}
}
}
/**
* 이름이 일치하는 학생을 찾아서 조회하는 메소드
*/
public void searchName1() {
System.out.println("===== 학생 검색(이름 일치) =====");
System.out.print("검색할 이름 입력: ");
String input = sc.next();
boolean flag = true;
// 향상된 for문
for( Student std : studentList) {
if( input.equals( std.getName() ) ) { // 이름이 일치하는 경우
// 일치한 학생의 정보 출력
System.out.println(std);
flag = false;
}
}
if(flag) { // flag가 true인 경우 == for문 내에 있는 if가 수행된 적 없다
// == 검색 결과가 없다
System.out.println("검색 결과가 없습니다.");
}
}
/**
* 이름에 특정 문자열이 포함되는 학생을 찾아서 조회하는 메소드
*/
public void searchName2() {
// contains : 포함
// boolean String.contains(문자열) : String에 문자열이 포함되어 있으면 true
System.out.println("===== 학생 검색(문자열 포함) =====");
System.out.print("이름에 포함되는 문자열 입력 : ");
String input = sc.next();
boolean flag = true;
// 향상된 for문
for( Student std : studentList ) {
if( std.getName().contains( input ) ) {
System.out.println(std);
flag = false;
}
}
if(flag) { // flag가 true인 경우 == for문 내에 있는 if가 수행된 적 없다
// == 검색 결과가 없다
System.out.println("검색 결과가 없습니다.");
}
}
}