재밌고 어려운 IT를 이해해보자~!
함수를 활용한 학생부 프로그램 리팩토링(Refactoring) 본문
리팩토링 하기에 앞서..
함수를 만들기전에 메인에 코드를 작성해보고 함수화 하는것이 좋다.
함수화 할때 알아야 할것 3가지
1. 빨간밑줄이 생기면 인자로 데려와야하는 변수이다.
2. 함수를 거쳐서 왔을때 메인에도 적용되는지 확인.
3. return으로 값을 받을지 main에서 직접 변경할지 고민.
★ 모듈화(컴포넌트화,캡슐화,리팩토링,패키징,함수화,메서드화,...)
모듈이란?
단독 수행할 수 있는 코드 묶음
독자적인 기능이 존재하는 코드
많은 조각들로 다양하게 이루어진 레고가 더 좋은 레고이다.
1. 조합 경우의 수 가 훨씬 많고,
2. 더 세부적인 표현이 가능함!
기존 작성했던 프로그램은 전체 코드중에 단 한줄이라도 문제가 생기면 동작이 불가능
== 결합도가 높은 코드
== 응집도가 낮은 코드
오늘만들 프로그램은, 각 기능들을 각각의 함수로 묶어서 별도로 관리할 예정
함수 1개가 코드수정중이더라도 전체 프로그램은 사용가능
== 결합도가 낮은 코드
== 응집도가 높은 코드
원래 존재하던 기능을 "함수화"시키는 것 == ★모듈화★
설게부터 다시해보자!
학생부 프로그램 제작
설계 : LP ERD UF
LP? → 사용자가 어떤 기능을 사용할지 == CRUD
비즈니스 메서드
핵심로직
핵심관심
ERD(Entity Relationship Diagram) → 프로그램에서 활용하는 데이터에 대한 모든 정의
엔터티간의 상관관계를 뜻하는 것 같다.
UF(User Flow) → 사용자가 어떤 순서로 프로그램을 이용하는지 화면에 대한 모든 구성과 구성요소.
저가 목표를 달성하기 위해 서비스 내에서 행하는 일련의 행위를 말한다.
C Create 학생추가
R Read 학생목록출력,학생1명검색
U Update 학생정보변경
D Delete 학생삭제
프로그램 종료.
int[] 학생 점수 데이터
최대 3명까지 저장 가능
1. 추가
2. 목록출력
3. 검색
4. 변경
5. 삭제
0. 종료
유효성 검사
사용자가 "입력"이라는 행위를 한다면, 무조건 잘못된 사용법으로 입력할수도있기때문에 검사해주어야만한다!!!!!
기능 추가(or 변경)
ex1) "1등 출력"이라는 기능 추가
ex2) "목록출력" >> "50점이상 학생만 출력"으로 기능 변경.
이를 토대로 다시한번 학생부 프로그램을 메인에 작성해보고 함수화를 시켜 리팩토링을 진행해보았다.
강사님이 해주신거와 비교해서 어디거 어떻게 부족한지 알ㅇr보도록하자.
함수를 사용하기 전 메인에 작성한 학생부 프로그램
package class02;
import java.util.Random;
import java.util.Scanner;
public class Test01 {
public static void sample(int[] stuArr, int index) { // 샘플 데이터 추가
// stuArr[index++]=80;
Random rand = new Random();
stuArr[index] = rand.nextInt(101); // 0~100
System.out.println();
System.out.println((index + 1) + "번학생의 점수는 " + stuArr[index] + "점입니다.");
System.out.println((index + 1) + "번학생 추가완료!");
System.out.println();
// ① 빨간밑줄 ▷ 인자로 데려와야하는 변수
// ② main()에서도 적용이 되었는지 확인
// : main()측의 index는 변경되지 못함!
// ③ return으로 변경? VS main()에서 직접 변경?
// : index값의 변화가 ++로 고정이어서(단순해서) 직접 변경 O
}
public static void printstuarr(int[] stuArr, int index) {
System.out.println();
System.out.println(" === 목록출력 ===");
for (int i = 0; i < index; i++) {
System.out.println((i + 1) + "번학생 : " + stuArr[i] + "점");
}
System.out.println();
}
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int[] stuArr = new int[3];
int index = 0; // 현재 저장된 학생 데이터 개수
/*
* // 샘플 데이터 추가 stuArr[index++]=80; stuArr[index++]=72;
*/
// sample(stuArr,index++); //선 함수 수행 후 연산 -> index0인채로 함수수행하고 index+1
// sample(stuArr,index++); //선 함수 수행 후 연산 -> index1인채로 함수수행하고 index+2
while (true) {
System.out.println();
System.out.println(" === 학생부 프로그램 ===");
System.out.println("1. 추가"); //
System.out.println("2. 목록출력"); //
System.out.println("3. 검색"); //
System.out.println("4. 변경"); //
System.out.println("5. 삭제"); //
System.out.println("0. 종료");
System.out.print("입력 >> ");
int action = sc.nextInt();
System.out.println();
if (action == 0) { // 종료
System.out.println();
System.out.println("종료 하시겠 습니까? y / n");
String exit = sc.next();
if (exit.equals("y")) {
System.out.println();
System.out.println("프로그램을 종료합니다...");
break;
} else {
continue;
}
}
else if (action == 1) {
// 학생 추가 유효성검사
if (index > 2) {
System.err.println("이미 3명의 학생 정보가 꽉찾습니다. 학생을 삭제하고 입력하세요.");
continue;
}
while (true) {
System.out.println("추가하실 " + (index + 1) + "번 학생 점수를 입력해주세요");
int score = sc.nextInt();
if (score < 0 || score > 100) {
System.out.println("학생 점수가 0~100 범위를 벗어났습니다. 다시 입력하세요");
continue;
} else {
stuArr[index++] = score;
System.out.println((index) + "번 학생 점수가 추가되었습니다.");
break;
}
}
}
else if (action == 2) { // 목록출력
printstuarr(stuArr, index);
}
else if (action == 3) {
if (index == 0) {
System.err.println("입력된 학생 정보가 없습니다. \n학생 정보를 입력하고 다시 찾아주세요");
} else {
System.out.println("검색할 학생 번호를 입력하세요.");
int stunum = sc.nextInt();
if (0 < stunum && stunum <= index) {
System.out.println("학생 번호 : " + (stunum) + "번\n" + "학생 점수 : " + stuArr[stunum - 1] + " 점");
} else {
System.out.println("입력하신 학생번호는 존재하지 않습니다.\n 다시 입력하세요.");
}
}
} else if (action == 4) {
if (index == 0) {
System.err.println("입력된 학생 정보가 없습니다. \n학생 정보를 입력하고 다시 찾아주세요");
} else {
A:
while (true) {
System.out.println("점수를 변경할 학생 번호를 입력하세요.");
int stunum = sc.nextInt();
if (stunum > index || stunum <= 0) {
System.out.println("입력하신 학생 번호는 입력되지 않았습니다. 다시 입력하세요");
System.out.println("현재까지 입력된 번호: " + "1~" + (index));
continue;
}
for (int i = 0; i < index; i++) {
if (stunum == (i + 1)) {
System.out.println(stunum + "번 학생을 선택하셨습니다.");
System.out.println("현재" + stunum + "번 학생 점수 :" + stuArr[stunum - 1] + "점");
while (true) {
System.out.println("변경할 점수를 입력하세요.");
int newscore = sc.nextInt();
if (newscore != stuArr[stunum - 1] && newscore >= 0 && newscore <= 100) {
stuArr[stunum - 1] = newscore;
System.out.println(stunum + "번 학생 점수가 " + stuArr[stunum-1] + "점 으로 변경되었습니다.");
break A;
}
else if (newscore == stuArr[stunum - 1]) {
System.out.println("기존값과 동일한 점수를 입력하셨습니다." );
System.out.println("점수를 그대로 유지할까요?? 맞으면 y 아니면 n 입력");
String ans = sc.next();
if (ans.equals("y")) {
System.out.println("y를 선택했습니다. 기존 점수 유지");
break A;
} else if (ans.equals("n")) {
System.out.println("n을 입력했습니다. 점수를 다시 입력하세요");
} else {
System.out.println("잘못입력");
}
} else {
System.err.println("점수가 이상하다 재입력!!!!!!");
}
}
}
}
}
}
}
// 배열내부는 삭제되지 않고 인덱스를 없애는 방향으로 학생이 삭제되는 것 처럼 보이게 한다. 따라서 마지막 학생만 삭제가능
else if (action == 5) {
if (index == 0) {
System.err.println("삭제할 학생 정보가 없습니다.");
} else {
System.out.println((index--) + "번 학생이 삭제되었습니다.");
}
}
}
}
}
함수를 활용해서 리팩토링한 학생부 프로그램!
package class02;
import java.util.Random;
import java.util.Scanner;
public class Test01 {
public static void programmenu() {
System.out.println();
System.out.println(" === 학생부 프로그램 ===");
System.out.println("1. 추가"); //
System.out.println("2. 목록출력"); //
System.out.println("3. 1등출력");
System.out.println("4. 검색"); //
System.out.println("5. 변경"); //
System.out.println("6. 삭제"); //
System.out.println("7. 50점이상 학생출력"); //
System.out.println("0. 종료");
System.out.print("입력 >> ");
}
public static int exit() {
Scanner sc = new Scanner(System.in);
System.out.println("종료 하시겠 습니까? y / n");
String exit = sc.next();
if (exit.equals("y")) {
System.out.println();
System.out.println("프로그램을 종료합니다...");
return 0;
}
return -1;
}
public static int addstu(int[] stuArr, int index) { // 샘플 데이터 추가
Scanner sc = new Scanner(System.in);
// 학생 추가 유효성검사
if (index > 2) {
System.err.println("이미 3명의 학생 정보가 꽉찾습니다. 학생을 삭제하고 입력하세요.");
return -1;
}
while (true) {
System.out.println("추가하실 " + (index + 1) + "번 학생 점수를 입력해주세요");
int score = sc.nextInt();
if (score < 0 || score > 100) {
System.out.println("학생 점수가 0~100 범위를 벗어났습니다. 다시 입력하세요");
} else {
stuArr[index++] = score;
System.out.println((index) + "번 학생 점수가 추가되었습니다.");
return index;
}
}
}
public static void printstuarr(int[] stuArr, int index) {
System.out.println();
System.out.println(" === 목록출력 ===");
if (index == 0) {
System.err.println("입력된 학생 정보가 없습니다. \n학생 정보를 입력하고 다시 찾아주세요");
}
for (int i = 0; i < index; i++) {
System.out.println((i + 1) + "번학생 : " + stuArr[i] + "점");
}
System.out.println();
}
//1등출력
public static void printrank1(int[] stuArr, int index) {
int max = stuArr[0];
int maxIndex = 0;
for (int i=1; i<index; i++) {
if (max <stuArr[i]) {
max = stuArr[i];
maxIndex = i;
}
}
System.out.println("1등학생은 "+(maxIndex+1)+"번 학생이며 "+"점수는 "+stuArr[maxIndex]+"입니다.");
}
public static int stusearch(int[] stuArr, int index) {
Scanner sc = new Scanner(System.in);
if (index == 0) {
System.err.println("입력된 학생 정보가 없습니다. \n학생 정보를 입력하고 다시 찾아주세요");
return -1;
} else {
while (true) {
System.out.println("검색할 학생 번호를 입력하세요.");
int stunum = sc.nextInt();
if (0 < stunum && stunum <= index) {
System.out.println("학생 번호 : " + (stunum) + "번\n" + "학생 점수 : " + stuArr[stunum - 1] + " 점");
return 0;
} else {
System.out.println("입력하신 학생 번호는 입력되지 않았습니다. 다시 입력하세요");
System.out.println("현재까지 입력된 번호: " + "1~" + (index));
}
}
}
}
public static int[] scorechange(int[] stuArr, int index) {
Scanner sc = new Scanner(System.in);
if (index == 0) {
System.err.println("입력된 학생 정보가 없습니다. \n학생 정보를 입력하고 다시 찾아주세요");
return new int[0];
} else {
while (true) {
System.out.println("점수를 변경할 학생 번호를 입력하세요.");
int stunum = sc.nextInt();
if (stunum > index || stunum <= 0) {
System.out.println("입력하신 학생 번호는 입력되지 않았습니다. 다시 입력하세요");
System.out.println("현재까지 입력된 번호: " + "1~" + (index));
}
for (int i = 0; i < index; i++) {
if (stunum == (i + 1)) {
System.out.println(stunum + "번 학생을 선택하셨습니다.");
System.out.println("현재" + stunum + "번 학생 점수 :" + stuArr[stunum - 1] + "점");
while (true) {
System.out.println("변경할 점수를 입력하세요.");
int newscore = sc.nextInt();
if (newscore != stuArr[stunum - 1] && newscore >= 0 && newscore <= 100) {
stuArr[stunum - 1] = newscore;
System.out.println(stunum + "번 학생 점수가 " + stuArr[stunum - 1] + "점 으로 변경되었습니다.");
return stuArr;
} else if (newscore == stuArr[stunum - 1]) {
System.out.println("기존값과 동일한 점수를 입력하셨습니다.");
System.out.println("점수를 그대로 유지할-1까요? 맞으면 y 아니면 n 입력");
String ans = sc.next();
if (ans.equals("y")) {
System.out.println("y를 선택했습니다. 기존 점수 유지");
return stuArr;
} else if (ans.equals("n")) {
System.out.println("n을 입력했습니다. 점수를 다시 입력하세요");
} else {
System.out.println("잘못입력");
}
} else {
System.err.println("점수가 이상합니다...? 재입력");
}
}
}
}
}
}
}
public static int deletestu(int[] stuArr, int index) {
if (index == 0) {
System.err.println("삭제할 학생 정보가 없습니다.");
return -1;
} else {
System.out.println((index--) + "번 학생이 삭제되었습니다.");
return index;
}
}
public static void stuabove50(int[] stuArr, int index) {
if (index == 0) {
System.err.println("입력된 학생 정보가 없습니다. \n학생 정보를 입력하고 다시 찾아주세요");
}
for (int i=0; i<index; i++) {
if (stuArr[i] >50) {
System.out.println("50점이상 :" + (i+1)+" 번 학생");
}
}
}
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int[] stuArr = new int[3];
int index = 0; // 현재 저장된 학생 데이터 개수
while (true) {
// 학생부 프로그램 출력~
programmenu();
int action = sc.nextInt();
if (action == 0) { // 종료
int out = exit();
if (out==0) {
break;
}
}
else if (action == 1) {
index = addstu(stuArr, index);
}
else if (action == 2) { // 목록출력
printstuarr(stuArr, index);
}
else if (action == 3) { // 1등출력
printrank1(stuArr, index);
}
else if (action == 4) {
stusearch(stuArr, index);
}
else if (action == 5) {
stuArr = scorechange(stuArr, index);
}
// 배열내부는 삭제되지 않고 인덱스를 없애는 방향으로 학생이 삭제되는 것 처럼 보이게 한다. 따라서 마지막 학생만 삭제가능
else if (action == 6) {
index = deletestu(stuArr, index);
}
else if (action == 7) {
stuabove50(stuArr, index);
} else {
System.out.println("번호잘못입력");
}
}
}
}
강사님 학생부 프로그램 코드
package class03;
import java.util.Random;
import java.util.Scanner;
public class Test03 {
// 샘플 데이터 추가
// 기능을 함수화
// 모듈화
public static void sample(int[] stuArr,int index) {
Random rand=new Random();
stuArr[index]=rand.nextInt(101); // 0~100
System.out.println();
System.out.println((index+1)+"번학생의 점수는 "+stuArr[index]+"점입니다.");
System.out.println((index+1)+"번학생 추가완료!");
System.out.println();
}
public static void insertStu(int[] stuArr,int index,Scanner sc) {
System.out.println();
while(true) {
System.out.print((index+1)+"번학생의 점수 입력 >> ");
int score=sc.nextInt();
if(checkScore(score)) {
stuArr[index++]=score;
break;
}
}
System.out.println(index+"번학생 추가완료!");
System.out.println();
}
public static void printStuArr(int[] stuArr,int index) {
System.out.println();
System.out.println(" === 목록출력 ===");
for(int i=0;i<index;i++){
System.out.println((i+1)+"번학생 : "+stuArr[i]);
}
System.out.println();
}
public static void printStu(int[] stuArr,int index,Scanner sc) {
System.out.println();
while(true) {
System.out.print("검색할 학생 번호 입력 >> ");
int stuNum=sc.nextInt();
if(checkStuNum(stuNum,index)) {
System.out.println(stuNum+"번 학생의 점수: "+stuArr[stuNum-1]+"점");
break;
}
}
System.out.println();
}
public static void updateStu(int[] stuArr,int index,Scanner sc) {
System.out.println();
while(true) {
System.out.print("변경할 학생의 번호 입력 >> ");
int stuNum=sc.nextInt();
if(checkStuNum(stuNum,index)) {
while(true) {
System.out.print("변경할 점수 입력 >> ");
int score=sc.nextInt();
if(checkScore(score)) {
stuArr[stuNum-1]=score;
System.out.println(stuNum+"번 학생의 점수 "+score+"점으로 변경완료!");
break;
}
}
break;
}
}
System.out.println();
}
public static void deleteStu(int index) {
System.out.println();
System.out.println(index+"번학생 삭제완료!");
System.out.println();
}
public static void printInfo() {
System.out.println();
System.out.println("없는 번호입니다...확인후 다시 시도해주세요!");
System.out.println();
}
// 대부분의 유효성 검사 로직은
// 모듈화하여 사용됩니다!
// input: 확인대상
// output: 가능여부(boolean)
// 함수명: hasXxx(), isXxx(), checkXxx(), flagXxx(), ...
public static boolean hasStu(int index) {
if(index<=0) {
System.out.println("학생데이터가 전혀 없습니다...");
return false;
}
return true;
}
public static boolean checkInsert(int[] stuArr,int index) {
if(index>=stuArr.length) {
System.out.println("학생부가 가득찼습니다...");
return false;
}
return true;
}
public static boolean checkScore(int score) {
if(0<=score && score<=100) {
return true;
}
System.out.println("점수는 0~100점까지만 가능합니다...");
return false;
}
public static boolean checkStuNum(int stuNum,int index) {
if(1<=stuNum && stuNum<=index) {
return true;
}
System.out.println("해당 번호의 학생은 없습니다...");
return false;
}
public static void main(String[] args) {
Scanner sc=new Scanner(System.in);
int[] stuArr=new int[3];
int index=0; // 현재 저장된 학생 데이터 개수
/*
// 샘플 데이터 추가
stuArr[index++]=80;
stuArr[index++]=72;
*/
///sample(stuArr,index++); // 선 함수실행
///sample(stuArr,index++); // 후 연산자수행
while(true) {
System.out.println();
System.out.println(" === 학생부 프로그램 ===");
System.out.println("1. 추가");
System.out.println("2. 목록출력");
System.out.println("3. 검색");
System.out.println("4. 변경");
System.out.println("5. 삭제");
System.out.println("0. 종료");
System.out.print("입력 >> ");
int action=sc.nextInt();
System.out.println();
if(action==0) { // 종료
System.out.println();
System.out.println("프로그램을 종료합니다...");
System.out.println();
break;
}
else if(action==1) { // 추가
if(!checkInsert(stuArr,index)) {
continue;
}
insertStu(stuArr,index++,sc);
}
else if(action==2) { // 목록출력
// hasStu(index)함수의 output이 boolean이면 유리하겠다!
if(!hasStu(index)) {
// flase여야 if통과 => !(NOT) 추가하기
continue;
}
printStuArr(stuArr,index);
// 1) 우선 기능을 main()에서 완성시켜야함!
// 2) 모듈화 시작 : main()에서 작성완료한 코드를 뜯기
}
else if(action==3) { // 검색
if(!hasStu(index)) {
continue;
}
printStu(stuArr,index,sc);
}
else if(action==4) { // 변경
if(!hasStu(index)) {
continue;
}
updateStu(stuArr,index,sc);
}
else if(action==5) { // 삭제
if(!hasStu(index)) {
continue;
} // 함수화(모듈화)의 큰 장점! 코드의 재사용성이 증가!!!
deleteStu(index--);
}
else {
printInfo();
}
}
}
}
괜찮은 듯 싶었는데, 강사님께서 알려주신 코드를 보니 매우 난잡하고 모듈화가 되었다기보단 메인문 자체가 함수가 된 느낌이 들었다.
어떤 부분들을 수정해야하고 모듈화를 진행할때 중요한 점이 무엇인지 알아보자.
1. 함수 명 개선
나의 함수명을 보면
programmmenu() : 메뉴출력
exit() : 프로그램 종료
printstuarr() : 입력된 학생정보 전체출력
printrank1() : 1등학생 출력
stusearch() : 학생검색
scorechange() : 점수변경
deletestu() : 학생삭제
stuabove50() : 50점초과인 학생출력 이다.
CRUD를 생각해서 함수명을 작성할 필요가 있고, 두가지단어가 합성되어있을때 두번째단어는 대분자로 시작해야한다.
ex) hasStu, checkScore, deleteStu
출력 -> print
입력 ->insert
변경 ->update
삭제 ->delete
정보 ->info
가지고 있는지? -> has (hasStu)
입력가능? checkInsert
점수확인 checkScore
학생번호확인 checkStunum
2. 함수에 불필요한 인자값, 필요한 인자값 구분해서 작성하기
함수를 작성 할때마다 Scanner메서드를 통해 객체를 생성하면, heap메모리를 엄청나게 낭비하는 것이다.
Scanner 객체 또한 함수의 인자로 받을 수 있다.
ex) 메인에서 생성된 객체 sc를 함수의 인자로 받아서 사용할 수 있다.
funcA(Scanner sc) {
int num = sc.nextInt();
}
main(){
Scanner sc = new Scanner(System.in)
}
또한 사용되지 않는 인자는 받지 않아야한다. 함수가 호출될 때 불필요한 메모리가 낭비 될 수 있다.
3. 반복되는 주요기능 함수화
학생데이터가 배열에 있는가?
학생데이터가 배열에 꽉찾있는가?
학생 점수는 몇점?
학생 번호는 몇번?
등의 반복적으로 사용될만한 질문들을 함수로 작성하고 리턴받아서 사용하자.
public static boolean hasStu(int index) {
if(index<=0) {
System.out.println("학생데이터가 전혀 없습니다...");
return false;
}
return true;
}
public static boolean checkInsert(int[] stuArr,int index) {
if(index>=stuArr.length) {
System.out.println("학생부가 가득찼습니다...");
return false;
}
return true;
}
public static boolean checkScore(int score) {
if(0<=score && score<=100) {
return true;
}
System.out.println("점수는 0~100점까지만 가능합니다...");
return false;
}
public static boolean checkStuNum(int stuNum,int index) {
if(1<=stuNum && stuNum<=index) {
return true;
}
System.out.println("해당 번호의 학생은 없습니다...");
return false;
}
boolean 타입 output을 return 받아 사용할 수 있다.
if(checkStuNum(stuNum,index)) {
}
학생 번호체크는 자주 확인해야하는 질문이기 때문에 이처럼 모듈화를 해주면 효율이 매우 좋아진다.
*참고로 2중 while문을 한번에 break하는 방법을 몰랐었는데 다음처럼 작성하면,
내부 while문에서 break를 만났을 때 외부 while문도 break를 만나서 한번에 종료된다.
while(true) {
System.out.print("변경할 학생의 번호 입력 >> ");
int stuNum=sc.nextInt();
if(checkStuNum(stuNum,index)) {
while(true) {
System.out.print("변경할 점수 입력 >> ");
int score=sc.nextInt();
if(checkScore(score)) {
stuArr[stuNum-1]=score;
System.out.println(stuNum+"번 학생의 점수 "+score+"점으로 변경완료!");
break;
}
}
break;
}
}
4. 꼭 return이 필요한 경우에만 output이 있는 함수로 작성.
학생 번호를 입력받아서 입력된 정보가 한개도 없으면 "입력된 정보가 없습니다." 를 출력하고
있으면 학생 정보를 출력해주는 함수를 생각해보자.
이 함수는 input은 필요하지만 output 필요 없는 함수이다. -> void 함수로 선언.
다음 학생 검색하는 함수를 보자.
public static int stusearch(int[] stuArr, int index) {
Scanner sc = new Scanner(System.in);
if (index == 0) {
System.err.println("입력된 학생 정보가 없습니다. \n학생 정보를 입력하고 다시 찾아주세요");
return -1;
} else {
while (true) {
System.out.println("검색할 학생 번호를 입력하세요.");
int stunum = sc.nextInt();
if (0 < stunum && stunum <= index) {
System.out.println("학생 번호 : " + (stunum) + "번\n" + "학생 점수 : " + stuArr[stunum - 1] + " 점");
return 0;
} else {
System.out.println("입력하신 학생 번호는 입력되지 않았습니다. 다시 입력하세요");
System.out.println("현재까지 입력된 번호: " + "1~" + (index));
}
}
}
}
if 문에 return -1은 void() 문으로 생성했으면 전혀 필요없는 값이다. 하지만 int형으로 선언했기때문에 뭐라도 int형을 return해야해서 넣은 의미없는 값이다.
또한 while 문에서도 return 0 대신에 break; 를 사용하면 된다.
void 함수로 바꿔보자
public static void stusearch(int[] stuArr, int index, Scanner sc) {
if (index == 0) {
System.err.println("입력된 학생 정보가 없습니다. \n학생 정보를 입력하고 다시 찾아주세요");
} else {
while (true) {
System.out.println("검색할 학생 번호를 입력하세요.");
int stunum = sc.nextInt();
if (0 < stunum && stunum <= index) {
System.out.println("학생 번호 : " + (stunum) + "번\n" + "학생 점수 : " + stuArr[stunum - 1] + " 점");
break;
} else {
System.out.println("입력하신 학생 번호는 입력되지 않았습니다. 다시 입력하세요");
System.out.println("현재까지 입력된 번호: " + "1~" + (index));
}
}
}
}
훨씬 알아보기 쉽고 불필요한 return도 없다!
5. 값에의한호출일때, 함수에서 인자를 받은값을 함수내에서 기능을 통해 변경후 return 받을지 아니면,
메인문에서 따로 다룰지 원하는 기능구현에 따라 잘 선택해야한다.
ex)
학생추가함수 -1
public static int addstu(int[] stuArr, int index) { // 샘플 데이터 추가
Scanner sc = new Scanner(System.in);
// 학생 추가 유효성검사
if (index > 2) {
System.err.println("이미 3명의 학생 정보가 꽉찾습니다. 학생을 삭제하고 입력하세요.");
return -1;
}
while (true) {
System.out.println("추가하실 " + (index + 1) + "번 학생 점수를 입력해주세요");
int score = sc.nextInt();
if (score < 0 || score > 100) {
System.out.println("학생 점수가 0~100 범위를 벗어났습니다. 다시 입력하세요");
} else {
stuArr[index++] = score;
System.out.println((index) + "번 학생 점수가 추가되었습니다.");
return index;
}
}
}
상위 코드는 addstu라는 함수를 통해서 학생이 추가되었을때 학생배열 인덱스를 +1 해서 학생 수를 늘리는 함수이다. 학생이 아무도 없고 첫번째 학생을 추가한다고 가정했을때, 인덱스+1한 값을 main으로 retrun 받기 때문에 addstu함수를 메인에서 호출만 하면 main에 선언되어있는 index==0 은 index ==1이 된다. *학생 배열에 입력한 점수는 참조에 의한 호출 및 대입 이기 때문에 알아서 변경된다.
학생추가함수 -2
public static void insertStu(int[] stuArr,int index,Scanner sc) {
System.out.println();
while(true) {
System.out.print((index+1)+"번학생의 점수 입력 >> ");
int score=sc.nextInt();
if(checkScore(score)) {
stuArr[index++]=score;
break;
}
}
public static void main(String[] args) {
if(action==1) { // 추가
if(!checkInsert(stuArr,index)) {
continue;
}
insertStu(stuArr,index++,sc);
}
상위 함수는 index값을 함수에서 직접 변경해서 return하는 것이 아니라 배열에 점수만 입력하고 종료하는 함수이다.
그 이후 index값은 main문에서 ++ 를 해준다.
사실 아직은 어떤 방법이 더좋은지 모르곘다. 고객이 원하는 뉘앙스를 잘 파악해야한다.
자주 사용하는 로직 팁!
package class01;
import java.util.Scanner;
public class Test02 {
// 확인용 로직
// 1) 입력된 정수값이 범위에 해당하나요?
// 사용자가 정수를 입력함
// 이 입력값이 a~b 사이의 범위값이 맞는지 확인
public static boolean funcA(int a,int b) {
Scanner sc=new Scanner(System.in);
System.out.print("정수입력 >> ");
int input=sc.nextInt();
if(a<=input && input<=b) {
return true;
//intput<a && b<input 밖에 어떤일이 일어나던지 아무상관이 없는것 처럼 된다.
//조건 안에 들어왔을때 true를 주는것이 바람직하다.
}
return false;
}
// 사용자가 정수를 입력함
// 이 입력값이 a~b 사이의 범위값이 맞는지 확인
// a~b 사이의 범위값으로 제대로 입력할때까지 계속하고,
// 제대로 입력되었다면 main()으로 입력값 반환
public static int funcB(int a,int b) {
Scanner sc=new Scanner(System.in);
int input;
while(true) {
System.out.print("정수입력 >> ");
input=sc.nextInt();
if(a<=input && input<=b) {
break;
//return input 써도 알아서 함수 빠져나가지만 읽기 어렵다.
//break를 사용해서 이렇게 해주는것이 좋다/
//break쪽에 return input을 써도 되는데 그러면 나중에 찾기힘들다.
}
}
return input;
}
// 2) 특정 배열에 특정 값이 존재하나요?
// 배열에 어떤 값이 있는지 확인
// 있으면 T 없으면 F
public static boolean funcC(int[] datas,int key) {
boolean flag=false; // 플래그 변수
for(int data:datas) {
if(data==key) {
flag=true;
break;
// 그냥 break안쓰고 flag로만 판단하는거보다 break를 걸고
//true가나오는지 확인해주는 것이 더 예외상황이 발생할 황률이 적다.
}
}
return flag;
}
public static int funcD(int[] datas,int key) {
int keyIndex=-1;
// 아~ -1이 반환되었네? key 값이 배열에 없구나~~
for(int i=0;i<datas.length;i++) {
if(datas[i]==key) {
keyIndex=i;
}
}
return keyIndex;
}
// 3) 이 배열이 정렬되었나요?
// 배열이 있을때
// 정렬되었다면 T 아니면 F
public static boolean funcE(int[] datas) {
boolean flag=false;
int i;
for(i=0;i<datas.length-1;i++) {
if(datas[i] > datas[i+1]) {
break;
}
}
if(i>=datas.length-1) {
flag=true;
}
return flag;
}
public static void main(String[] args) {
int a=1,b=5,c=10;
int[] datas=new int[5];
// [ 10 20 30 40 50 ]
for(int i=0;i<datas.length;i++) {
datas[i]=(i+1)*10;
}
/*
if(funcA(a,b)) {
System.out.println("맞음");
}
else {
System.out.println("아님");
}
System.out.println("제대로 입력한 값은 "+funcB(a,b)+"입니다.");
*/
if(funcC(datas,c)) { // 조건식에 함수가있다? output타입이 boolean이다!
System.out.println("있음");
}
else {
System.out.println("없음");
}
int output=funcD(datas,c);
if(output!=-1) {
System.out.println(c+"는 ["+output+"]에 있습니다.");
}
else {
System.out.println(c+"는 없습니다...");
}
datas[0]=1000;
if(funcE(datas)) {
System.out.println("정렬됨");
}
else {
System.out.println("정렬안됨");
}
}
}
코드를 작성할때 고민하던 좋은 로직들이 많다 !!
※ print.out, print.err
학생부 프로그램을 실행시켰을때,
print.err("A");
print.out("B");
라는 코드가 있었는데 첫번째 루프를 돌때 B가먼저 출력되고 A가 그다음을 출력된 적이 있었다. 그 다음부터는
정상적으로 출력되었지만..뭔가 이상하다.
인터넷에서는 out 객체는 자체적으로 자신의 버퍼를 가지고있고, 여러개의 print request를 버퍼에 넣고 기다렸다가
적절한 타이밍에 한번에 출력한다고 한다. 그 이유는 print 구문이 있을때마다 콘솔에 메세지를 flush하면
jvm(java virtual machine)성능상에 영향을 주고 느려진다.
err객체 또한 자신의 버퍼를 가지지만 에러 상황처럼 일반적이지 않을때 출력을 의미하기 때문에 대부분 바로 flush 하게되어서 출력은 out보다 빨리나올 가능성이 크고 jvm은 느려지는 현상이 발생 할 수 있다!
라고 하지만!!! 내 경우는 처음 err문이 out 나온 케이스이다. 강사님께 들은 이유로는 err 객체를 처음 호출해서 그렇다고 한다!
그리고 두개의 객체 모두 버퍼에 쌓아서 콘솔에 출력하는 각각의 스레드로 동작 하기 때문에, 정확한 순서의 출력을 원한다면 err를 사용하는것은 지양하는 것이 좋겠다.
'코리아IT핀테크과정' 카테고리의 다른 글
클래스(Class), 메서드(Method), 생성자(Constructor) (0) | 2023.11.30 |
---|---|
선택정렬 코드 실행 (0) | 2023.11.29 |
삽입정렬 코드 실행 (0) | 2023.11.28 |
함수(Function) (0) | 2023.11.27 |
버블정렬 코드 개선 (0) | 2023.11.27 |