본문 바로가기

JAVA/PROJECT

Project_02 : 콘솔 프로그램 Student - 배열 활용 버전

DB 연결을 하지 않고 콘솔 출력을 하는 프로젝트를 해보려고 한다.

DB 연결을 하지 않기 때문에 데이터는 배열을 활용하고자 한다.

 

이번 프로젝트는 학생의 정보를 출력하는 게시판을 구현하는 것을 목적으로 한다.

controller service vo util exception
StudentApp StudentService Student StudentUtils MyRangeException

 

- StudentApp

👉 Controller의 역할을 하는 클래스로 main 메서드를 포함하고 있다.

👉 숫자를 입력해야 할 때 다른 것을 입력하면, 숫자 타입이 아니라는 예외 처리를 하도록 하였다. (NumberFornetException)

import static student.StudentUtils.*;

public class StudentcApp {
	public static void main(String[] args) {
		
		StudentService service = new StudentService();
		
        // 콘솔에 지속적인 출력을 위하여 while(true)로 구현
		while (true) {
			try {
				System.out.println();
				int menu = nextInt("1. 조회  2. 등록  3. 수정  4. 삭제  5. 종료 > ");
				switch (menu) {
				case 1:
					service.list();
					break;
				case 2:
					service.register();
					break;
				case 3:
					service.modify();
					break;
				case 4:
					service.remove();
					break;
				case 5:
                	// 종료를 선택하면 return 문이 수행되어 while 문을 종료한다.
					return;
				default:
                	// 목록으로 제시한 범위를 벗어나는 숫자를 입력 시
                    // 사용자 정의한 예외가 발생하도록 하였다.
					throw new MyRangeException(1, 5);
				}
			}
            // 예외 발생 시에 처리
			catch (NumberFormatException e) {
				System.out.println("숫자를 입력하세요");
			}
			catch (MyRangeException | RuntimeException e) {
				System.out.println(e.getMessage());
			}
		}
	}
}

 

- StudentService

👉 콘솔 프로그램에서 사용되는 CRUD 기능을 구현하였다.

👉 예외 처리를 직접 처리하지 않고 호출부에서 처리하도록 throws 하였다.

👉 학생 객체를 저장하기 위하여 배열을 사용하고 있기 때문에 초기 지정값을 채우면 2 배 늘어날 수 있도록 구현하였다. 

import static student.StudentUtils.*;

public class StudentService {

	// 학생 배열 10칸 지정
	private Student[] students = new Student[10];
    
    // 배열에 실제 저장된 학생 수
   	private int count;
    
    // 성적순으로 정렬한 학생 배열
    private Student[] sortedStudents = new Student[10];
    
    // Test를 위한 학생 데이터
    {
//    	students[count++] = new Student(count);
//    	students[count++] = new Student(count);
//    	students[count++] = new Student(count);
//    	students[count++] = new Student(count);
//    	students[count++] = new Student(count);
    }
    
    
    // 기능 구현부
    // create
    public void register() throws MyRangeException{
    
    	// 학생 배열 상태 확인
        confirmStudentArray();
        
        // 새로운 학생 등록
        System.out.println();
		String name = nextLine("등록하실 학생의 이름을 입력해 주세요. >> ");
		int korean = confirmScore(nextInt("등록하실 학생의 국어 점수를 입력해 주세요. >> "));
		int math = confirmScore(nextInt("등록하실 학생의 수학 점수를 입력해 주세요. >> "));
		int english = confirmScore(nextInt("등록하실 학생의 영어 점수를 입력해 주세요. >> "));
        
        // 등록된 학생이 없는지 확인
        // count 가 0일 경우의 처리
        int tmp = 1;
		if (count > 0) {
			tmp = students[count-1].getNo(); 
		} 
		students[count++] = new Student(tmp, name, korean, math, english);
        
        // 성적순 학생 정렬
        sortStudents();
        
        System.out.println("학생이 등록 되었습니다. ");
    }
    
    // Read
    public void list() {
    	
        System.out.println();
        // 등록된 학생 유무 확인
		existStudent();
        
        switch (nextInt("조회하실 목록을 선택해 주세요. 1. 전체 목록 2. 석차별 조회 >> ")) {
		case 1:
			listAll();
			break;
		case 2:
			listRank();
			break;
		default:
			break;
		}
    }
    
    private listAll() {
    	
        System.out.println(" 학생 번호 "  + " | " +  " 이름 " + " | " + " 국어 점수 " + " | " + " 수학 점수 " + " | " + " 영어 점수 " + " | " + " 총점 " + " | " + " 평균 ");
        
        // 배열의 길이만큼 돌리면 채워지지 않은 부분은 null로 출력된다.
        // 학생이 저장된 만큼만 돌리면 저장된 학생만 출력하게 된다.
        for (int i = 0; i < count; i++) {
			System.out.printf("%s%n", students[i]);
		}
    }
    
    private listRank() {
    	System.out.println(" 석차 번호 "  + " | " + " 학생 번호 "  + " | " +  " 이름 " + " | " + " 국어 점수 " + " | " + " 수학 점수 " + " | " + " 영어 점수 " + " | " + " 총점 " + " | " + " 평균 ");
        
        for (int i = 0; i < count; i++) {
			System.out.printf("%5d %6c %s%n", (i + 1), ' ', sortedStudents[i]);
		}
    }
    
    // Update
    public void modify() {
    
    	// 등록된 학생 유무 확인
    	existStudent();
        // 전체 목록 출력
		listAll();
		System.out.println();
        
        // 학생 번호은 여기서 primary key 역할을 한다.
		int no = nextInt("수정할 학생의 번호를 입력하세요. >> ");
		System.out.println();
		System.out.println(" 학생 번호 "  + " | " +  " 이름 " + " | " + " 국어 점수 " + " | " + " 수학 점수 " + " | " + " 영어 점수 " + " | " + " 총점 " + " | " + " 평균 ");
        
        // 수정할 학생을 번호로 데이터를 찾아온다.
        Student target = findBy(no);
		
		System.out.println();
		switch (nextInt("수정할 영역을 선택해주세요. 1. 이름 | 2. 국어 점수 | 3. 수학 점수 | 4. 영어 점수 >> ")) {
		case 1:
        	// 수정 내용을 set 메서드로 반영
			target.setName(nextLine("변경된 이름을 입력하세요. >> "));
			System.out.println("변경이 완료되었습니다. ");
			break;
		case 2:
			target.setKorean(nextInt("변경된 국어 점수를 입력하세요. >> "));
			System.out.println("변경이 완료되었습니다. ");
			break;
		case 3:
			target.setMath(nextInt("변경된 수학 점수를 입력하세요. >> "));
			System.out.println("변경이 완료되었습니다. ");
			break;
		case 4:
			target.setEnglish(nextInt("변경된 영어 점수를 입력하세요. >> "));
			System.out.println("변경이 완료되었습니다. ");
			break;
		default:
			break;
		}
		sortStudents();
        listAll();
    }
    
    public void remove() {
    	
        // 등록된 학생 유무 확인
    	existStudent();
		listAll();
		int no = nextInt("삭제할 학생의 번호를 입력하세요. >>");
        
        // 삭제 대상 학생 데이터가 존재할 경우
        if(findBy(no) != null) {
        	// 배열을 복제하여 빠진만큼 줄인다.
			System.arraycopy(students, no, students, no - 1, students.length - no);
			count--;
			System.out.println("삭제가 완료되었습니다.");
		}
        
        sortStudents();
        listAll();
    }
    
    // 배열의 길이만큼 학생이 저장되어 있으면
    // 배열의 길이를 두 배 늘린다.
   	private confirmStudentArray() {
		if(count == students.length) {
			Student[] tmp = new Student[students.length * 2];
 			System.arraycopy(students, 0, tmp, 0, students.length);
			students = tmp;
		}
	}
    
    // 학생 번호로 학생 정보 가져오기
	private Student findBy(int no) {
    	// 목표하는 학생 정보를 담을 객체를 만든다.
		Student target = new Student();
		
        // 매개변수로 넘어온 번호와 일치하는 학생을 찾아서
		for (int i = 0; i < count; i++) {
			if(students[i].getNo() == no) {
				System.out.printf("%s%n", students[i]);
                // 생성한 객체에 저장한다.
				target = students[i];			
			}
		}
        return target;
     }
     
     // 정렬된 학생 목록 만들기
     private void sortStudents() {
     	// 원본 학생 배열을 복사
  		System.arraycopy(students, 0, sortedStudents, 0, students.length);

		for (int j = 0; j < count - 1; j++) {
			for (int i = 0; i < count - 1 - j; i++) {
            	// 평균 점수를 비교하여 정렬한다.
				if(sortedStudents[i].avgScore() < sortedStudents[i+1].avgScore()) {
					Student tmp = sortedStudents[i];
					sortedStudents[i] = sortedStudents[i+1];
					sortedStudents[i+1] = tmp;
				}
			}
		}
     }
     
     // 입력한 학생 점수의 범위가 유효한지 확인
     private int confirmScore(int score) throws MyRangeException {
     	// 점수 범위가 유효하지 않으면 예외를 발생시킨다.
		if(score < 0 || score > 100) {
			throw new MyRangeException();
		}
		return score;
	}
    
    // 배열에 저장된 학생 유무
    private void existStudent() {
        // count 가 0 인 경우
		ifcount == 0) {
        	// 예외를 발생시킨다.
			throw new RuntimeException("현재 등록된 학생이 없습니다.");
		}
	}
}

 

- Student

👉 멤버 변수에 직접적인 접근을 할 수 없는 대신 get과 set 메서드를 통하여 접근하도록 구현하였다.

public class Student {
	
    // 학번
	private int no;
	// 이름
	private String name;
	// 국어
	private int korean;
	// 수학
	private int math;
	// 영어
	private int english;
	
    // 기본 생성자
    public Student() {}
    
    // Test 를 위한 생성자
    public Student(int no) {
		this(no, randomName(), randomScore(), randomScore(), randomScore());
	}
    
    // 매개변수를 통한 생성자
    public Student(int no, String name, int korean, int math, int english) {
    	// set 메서드를 통해 입력
		setNo(no);
		setName(name);
		setKorean(korean);
		setMath(math);
		setEnglish(english);
	}
    
    public int getNo() {
		return no;
	}

	public void setNo(int no) {
		this.no = no;
	}

	public String getName() {
		return name;
	}

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

	public int getKorean() {
		return korean;
	}
	
    // 점수가 입력되는 메서드에는
	public void setKorean(int korean) {
    	// 별도로 값의 유효성을 확인할 수 있도록 하였다.
		if (korean < 0 || korean > 100) {
//			System.out.println("잘못된 범위");
			korean = 0;
			return;
		}
		this.korean = korean;
	}

	public int getMath() {
		return math;
	}

	public void setMath(int math) {
		if (math < 0 || math > 100) {
//			System.out.println("잘못된 범위");
			math = 0;
			return;
		}
		this.math = math;
	}

	public int getEnglish() {
		return english;
	}

	public void setEnglish(int english) {
		if (english < 0 || english > 100) {
//			System.out.println("잘못된 범위");
			english = 0;
			return;
		}
		this.english = english;
	}
    
    // 점수 총합
	public int sumScore() {
		return getKorean() + getMath() + getEnglish();
	}

	// 점수 평균
	public double avgScore() {
		return (int) (sumScore() * 100d / 3) / 100d;
	}
    
    @Override
	public String toString() {
		return String.format("%5d %11s %8d %14d %12d %11d %9.2f", no, name, korean, math, english, sumScore(), avgScore());
	}
    
    // test score
	static int randomScore() {
		return (int)(Math.random() * 41 + 60);
	}
	
	// test name
	static String randomName() {
		String[] arr = {"피카츄", "라이츄", "파이리", "꼬부기", "버터플", "야도란", "피존투", "또가스"};
		return arr[(int)(Math.random() * 8)];
	}
}

 

- StudentUtils

👉 콘솔 프로그램 특성상 반복되는 코드를 줄이기 위하여 해당 클래스를 만들었다.

👉 클래스 메서드로 만들어 해당 클래스의 인스턴스 생성 없이 접근 가능하도록 하였다.

import java.util.Scanner;

public class StudentUtils {
	private static Scanner scanner = new Scanner(System.in);
	
	public static String nextLine(String msg) {
		System.out.print(msg);
		return scanner.nextLine();
	}
	
	public static int nextInt(String msg) {
		return Integer.parseInt(nextLine(msg));
	}
}

 

- MyRangeException

👉 범위에 대한 예외 처리를 사용자화 하기 위해 만들었다.

👉 해당 예외로 처리할 수 있는 범위는 '점수'와 '목록'이 있다. 

public class MyRangeException extends Exception{

	// 생성 시에 별도로 지정하지 않으면 각각 0, 100으로 초기화
    int begin;
	int end = 100;

	public MyRangeException() {}
    
	public MyRangeException(int begin, int end) {
		this.begin = begin;
		this.end = end;
	}
    
    // getMessage() 메서드를 오버라이드함
	@Override
	public String getMessage() {
		return String.format("입력 가능한 값의 범위는 %d 부터 %d 사이입니다.", begin, end);
	}
}

해당 프로그램은 배열을 사용하고 있기 때문에 배열을 지속적으로 늘려가야 한다는 단점이 존재한다.

다음은 이 프로그램을 리스트로 사용하여 늘려주지 않아도 알아서 처리해주는 장점을 활용해 보고자 한다.