본문 바로가기

수업내용

[Day14][Java] Exception(예외) / 제품 주문 관리 프로그램

Ⅰ. Exception

-- Package(my.day15.a.exception), Class (ExceptionTest1(main method 포함))

 

1. ArrayIndexOutOfBoundsException
-- 배열의 크기가 오버가 되어지면 발생하는 Exception

 

 

 

public static void main(String[] args) {
		// 1. ArrayIndexOutOfBoundsException
		// 배열의 크기가 오버가 되어지면 발생하는 Exception

		String[] subjectArr = {"자바", "오라클", "JSP"};
		
		for(int i=0; i<=subjectArr.length; i++) {
			System.out.println(subjectArr[i]);
		}
		
	}

 

 

 

public static void main(String[] args) {
		// 1. ArrayIndexOutOfBoundsException
		// 배열의 크기가 오버가 되어지면 발생하는 Exception

		String[] subjectArr = { "자바", "오라클", "JSP" };

		try {
			for (int i = 0; i <= subjectArr.length; i++) {
				System.out.println(subjectArr[i]);
			}
		} catch (ArrayIndexOutOfBoundsException e) {
			System.out.println(">> 배열의 인덱스 범위가 초과되었습니다.");
			System.out.println("----------------------------");
			e.printStackTrace();
		}

	}

 

 

 

 

 

e.printStachTrace() : 에러 메시지 외에 어디가 잘못 되었는지 추적해 준다.

 

 

 

catch (ArrayIndexOutOfBoundsException e) {
			System.out.println(e.getMessage());
		}

 

 

 

 

 

▷결과

3

-- 에러 메시지만 보여 준다


 

2. ArithmeticException
-- 어떤 수를 0으로 나눌 때 발생되어지는 Exception 즉, 분모를 0으로 할 때 발생되어지는 Exception

 

 

 

for(int i=0; i<=5; i++) {	// i는 0~5까지
			int result = 50/(3-i);
			System.out.println("result => 50/"+(3-i)+"="+result);
		}

 

 

 

 

 

 

try {
			for (int i = 0; i <= 5; i++) { // i는 0~5까지
				int result = 50 / (3 - i);
				System.out.println("result => 50/" + (3 - i) + "=" + result);
			}
		} catch (ArithmeticException e) {
			System.out.println(">> 분모는 0으로 할 수 없습니다.");
		}

 

 

 

▷결과

result => 50/3=16
result => 50/2=25
result => 50/1=50
>> 분모는 0으로 할 수 없습니다.

 

 

 

for (int i = 0; i <= 5; i++) { // i는 0~5까지
			int result = 50 / (3 - i);
			System.out.println("result => 50/" + (3 - i) + "=" + result);
		}
		
		System.out.println(">> 프로그램 종료합니다. <<");

 

 

 

-- 이 때, 위에서 오류가 발생하면서 ">> 프로그램 종료합니다. <<" 문장은 출력되지 않는다.

 

 

 

try {
		for (int i = 0; i <= 5; i++) { // i는 0~5까지
			int result = 50 / (3 - i);
			System.out.println("result => 50/" + (3 - i) + "=" + result);
		}
		}finally {
		System.out.println(">> 프로그램 종료합니다. <<");	// try finally를 사용하지 않으면 윗 줄에서 오류가 발생하면서 출력되지 않는다.									
		}

 

 

 

-- 오류가 발생해든 발생하지 않든 문장을 출력하고 싶을 때 try finally를 사용한다.

-- try{ } 부분의 실행에 있어서 예외(exception)가 발생하든지 발생하지 않든지 관계없이 try{ } 부분의 실행이 끝나고 나서 무조건 실행되어지는 부분이 finally{ } 이다.

-- 오류가 발생하기 때문에 아래에 다른 코드를 추가할 경우 출력되지 않고 멈춘다.

 

 

 

try {
			for (int i = 0; i <= 5; i++) { // i는 0~5까지
				int result = 50 / (3 - i);
				System.out.println("result => 50/" + (3 - i) + "=" + result);
			}
		} catch (ArithmeticException e) {
			System.out.println(">> 분모는 0으로 할 수 없습니다.");
		} finally {
			System.out.println("-- 예외가 발생하든 발생하지 않든 관계없이 무조건 실행되어야 하는 부분입니다. --");
		}

 

 

 

-- try catch와 finally를 같이 쓸 수 있다.

-- catch로 오류를 처리해 주었으므로 아래에 다른 코드를 추가할 경우 계속 진행되어 출력된다.

 


 

-- 같은 패지키(my.day15.a.exception)에 Class(ExceptionTest2) 생성한다.

 

 

 

public class ExceptionTest2 {

	public static void main(String[] args) {
		try {
			for (int i = 0; i <= 5; i++) { // i는 0~5까지
				int result = 50 / (3 - i);
				System.out.println("result => 50/" + (3 - i) + "=" + result);
			}
		} catch (ArithmeticException e) {
			System.out.println(">> 분모는 0으로 할 수 없습니다.");
			return;	// 메소드를 끝낸다.
		} finally {
			System.out.println("-- 예외가 발생하든 발생하지 않든 관계없이 무조건 실행되어야 하는 부분입니다. --");
		}

		System.out.println(">>> 프로그램 종료합니다. Good Bye! <<<");

	}

 

 

 

-- catch에 return을 넣고 실행해 보면 ">>> 프로그램 종료합니다. Good Bye! <<<" 코드가 실행되지 않는다.

-- return : 현재 진행중인 메소드가 main() 메소드이므로, main() 메소드를 종료한다. 
-- 하지만 finally{ }가 있으면 finally{ } 부분을 실행해준 다음에 main() 메소드를 종료한다.

 

 

 

 

-- 같은 패지키(my.day15.a.exception)에 Class(ExceptionTest2)를 복사하여 Class(ExceptionTest3) 생성한다.

 

 

 

public class ExceptionTest3 {
	public static void main(String[] args) {
		try {
			for (int i = 0; i <= 5; i++) { // i는 0~5까지
				int result = 50 / (3 - i);
				System.out.println("result => 50/" + (3 - i) + "=" + result);
			}
		} catch (ArithmeticException e) {
			System.out.println(">> 분모는 0으로 할 수 없습니다.");
			System.exit(0);
		} finally {
			System.out.println("-- 예외가 발생하든 발생하지 않든 관계없이 무조건 실행되어야 하는 부분입니다. --");
		}
		System.out.println(">>> 프로그램 종료합니다. Good Bye! <<<");
	}
}

 

 

 

 

 

-- System.exit를 넣고 실행해보면 finally도 출력되지 않는다.

-- System.exit : 프로그램을 종료시키는 것이다.

-- 안에 숫자는 마음대로 쓸 수 있지만 숫자 0의 의미는 개발자가 프로그램을 정상적인 종료를 해 주겠다는 말이고, 0이 아닌 정수(ex. -234, 2568)의 의미는 개발자가 프로그램을 비정상적인 종료로 해주 겠다는 말이다.

 

 

 

public class ExceptionTest4 {

	public static void main(String[] args) {
		
		int[] noArr = {10,20,30,40};
		
			for (int i = 0; i < 5; i++) {
				try {
				int result = noArr[i]/(3-i);
				System.out.println("result = "+noArr[i]+"/"+(3-i)+"="+result);
				}catch(ArithmeticException e) {
					System.out.println(">> 분모는 0으로 할 수 없습니다.");
				}catch(ArrayIndexOutOfBoundsException e) {
					System.out.println(">> 배열의 인덱스 범위가 초과되었습니다.");
				}finally {
					System.out.println("-- 오류가 발생하든지 발생하지 않든지 무조건 실행하는 것입니다. --");
				}
			} // end of for----------------
			System.out.println(">>> 프로그램 종료합니다. Good Bye! <<<");
	} // end of main()--------------------------------------------------------------

}

 

 

 

public class ExceptionTest5 {

	public static void main(String[] args) {
		
		int[] noArr = {10,20,30,40};
		
			for (int i = 0; i < 5; i++) {
				try {
				int result = noArr[i]/(3-i);
				System.out.println("result = "+noArr[i]+"/"+(3-i)+"="+result);
				}catch(ArithmeticException | ArrayIndexOutOfBoundsException e) {
					System.out.println(">> 분모는 0으로 할 수 없거나 배열의 인덱스 범위가 초과되었습니다.");	// JDK 1.7부터 가능
				} finally {
					System.out.println("-- 오류가 발생하든지 발생하지 않든지 무조건 실행하는 것입니다. --");
				}
			} // end of for----------------
			System.out.println(">>> 프로그램 종료합니다. Good Bye! <<<");
	} // end of main()--------------------------------------------------------------

}

 

 

 

-- 위의 코드를 아래 코드처럼 OR로 붙여서 사용할 수 있다. (JDK 1.7부터 가능)

 

 

 

public class ExceptionTest6 {

	public static void main(String[] args) {
		
		int[] noArr = {10,20,30,40};
		String str = "똘똘이";
		
			for (int i = 0; i < 5; i++) {
				try {
				int result = noArr[i]/(3-i);
				int strNum = Integer.parseInt(str);	// NumberFormatExceptionberformat
				System.out.println("result = "+noArr[i]+"/"+(3-i)+"="+result);
				System.out.println("strNum => "+strNum);
				} catch(ArithmeticException | ArrayIndexOutOfBoundsException e) {
					System.out.println(">> 분모는 0으로 할 수 없거나 배열의 인덱스 범위가 초과되었습니다.");
				} catch(Exception e){ // Exception : 모든 Exception을 다 받아준다
					System.out.println(e.getMessage());
				} finally {
					System.out.println("-- 오류가 발생하든지 발생하지 않든지 무조건 실행하는 것입니다. --");
				}
			} // end of for----------------
			System.out.println(">>> 프로그램 종료합니다. Good Bye! <<<");
	} // end of main()--------------------------------------------------------------

}

 

 

 

-- Exception : 모든 Exception을 다 받아준다.

 

 

 


 

 

 

 

-- 순서를 바꿀 경우 오류가 발생한다.

-- 이미 위에 Exception catch 블록 부분에서 다 처리가 되었기 때문에 아래로 코드가 진행되지 않는다.

-- 그러므로 catch의 코딩 순서는 특정한 일부의 Exception부터 기술하고 아래로 내려가면서 더 많은 Exception을 받을 수 있는 것으로 코딩을 해야 한다.

 


 

-- Package(my.day15.b.exception), Class(Sungjuk, MainApp)를 생성

-- get set을 한 뒤 국영수 set을 없애고 하나의 setPoint에서 하도록 한다.

-- Generate Constructor useing Fields

-- 기본 생성자 생성

 

-- throws : setPoint 메소드는 실행시 NumberFormatException을 유발시킬 수 있으니 setPoint 메소드를 실행하는 쪽에서 NumberFormatException 처리를 하라는 말이다. (try catch)

 

 

 

package my.day15.b.exception;

public class Sungjuk {

	private String name;
	private int kor;
	private int eng;
	private int math;
	
	public Sungjuk(){ }
	
	public Sungjuk(String name, int kor, int eng, int math) {
		this.name = name;
		this.kor = kor;
		this.eng = eng;
		this.math = math;
	}
	
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	
	public int getKor() {
		return kor;
	}
	
	
	public int getEng() {
		return eng;
	}
	
	public int getMath() {
		return math;
	}
	
	public void setPoint(String kor, String eng, String math) throws NumberFormatException {
		this.kor = Integer.parseInt(kor);
		this.eng = Integer.parseInt(eng);
		this.math = Integer.parseInt(math);
	}
	
	
}

 

 

 

-- Scanner를 받아온다.

 

 

 

public class MainApp {

	public static void main(String[] args) {

		Scanner sc = new Scanner(System.in);
		
		Sungjuk[] sjArr = new Sungjuk[3];
		
		System.out.print(">> 학생명 => ");
		String name = sc.nextLine();
		
		System.out.print(">> 국어 => ");
		String kor = sc.nextLine();
		
		System.out.print(">> 영어 => ");
		String eng = sc.nextLine();
		
		System.out.print(">> 수학 => ");
		String math = sc.nextLine();
		
		Sungjuk sj = new Sungjuk();	// 기본 생성자
		
		sj.setName(name);
		
		try {	
		sj.setPoint(kor, eng, math);
		}catch(NumberFormatException e) {
			System.out.println(">> 과목의 모든 점수는 숫자로만 입력하세요!!");
			sj = null; 
		}
		sc.close();
	}
}

 

 

 

 

-- Sungjuk[] sjArr 속에 sj를 저장한다.

 

 

 

if(sj != null) {
		for(int i=0; i<sjArr.length; i++) {
			if(sjArr[i] == null) {
				sjArr[i] = sj;
				break;
			}
		}
	}

 

 

 

 

-- 입력된 성적을 조회한다.

 

 

 

boolean flag = false; 
		
		for(int i=0; i<sjArr.length; i++) {
			if(sjArr[i] != null) {
				flag = true;
				System.out.println(sjArr[i]);
			}	
		}
		if(!flag)
			System.out.println(">> 입력된 성적이 하나도 없습니다.");

 

 

 

▷결과

 

 

 

 

문제 ▷▷ toString을 사용하여 성적을 바르게 출력될 수 있도록 하시오. (메소드의 Override)

 

 

▶▶Sungjuk Class에 toString 메소드를 Override 한다.

▷첫 번째 방법(StringBuffer 사용)

 

 

 

@Override
	public String toString() {
		StringBuffer sb = new StringBuffer();
		
		sb.append("1. 국어 : "+kor+"\n");
		sb.append("2. 영어 : "+eng+"\n");
		sb.append("3. 수학 : "+math+"\n");
		
		return sb.toString();
	}

 

 

 

▷두 번째 방법

 

 

 

public String toString() {
		String result = "1.학생명 : "+name+"\n"+
						"2. 국어 : "+kor+"\n"+
						"3. 영어 : "+eng+"\n"+
						"4. 수학 : "+math+"\n";
		return result;
	}

 

 

 

 

 

▷ Aaaa 클래스에 Sungjuk 클래스를 상속 받으면 Object도 상속이 될까?

-- Sungjuk 클래스에서 이미 Object를 상속받고 있기 때문에 Aaaa 클래스에도 Object가 상속이 된다.

 


 

-- Package(my.day15.c.exception)와 Class(Member, Product, MainApp) 생성

-- MainApp은 main method 포함

 

 

 

 

MainApp에 위와 같이 메뉴를 만들어 보자.

 

-- 메뉴와 번호를 나타내는 것은 메소드로 만들어 불러와야 한다.

-- 9를 입력하면 프로그램을 종료하고 다른 번호를 누를 경우 "메뉴에 없는 번호입니다"를 출력한다.

 

 

 

public class MainApp {

	public static void viewMenu() {
		System.out.println("=== 메뉴 ===");
		System.out.println("1.로그인 2.로그아웃 3.제품조회 4.주문    9.프로그램 종료");
	}
    
	public static void main(String[] args) {

		Scanner sc = new Scanner(System.in);
		String menu ="";
		viewMenu();
		
		do {
			System.out.println(">> 메뉴번호 선택 :");
			menu = sc.nextLine();
		
			switch (menu) {
			case "1":
				
				break;
			case "2":
				
				break;
			case "3":
	
				break;
            case "4":
	
				break;
			case "9":
	
				break;

			default:
				System.out.println("메뉴 번호에 없는 번호입니다.");
				break;
			}
		} while (!"9".equals(menu));
		
		System.out.println("=== 프로그램 종료 ===");
		sc.close();
	}
}

 

 


 

 

 

 

3. 제품조회를 선택하면 위 결과가 나오도록 viewProdDisplay() 메소드를 만들어 보자.

 

 

 

▶▶ MainApp

 

 

 

static void viewProdDisplay(Product[] prodArr) {
		System.out.println("============================");
		System.out.println("제품코드      제품명      단가      잔고량");
		System.out.println("============================");
		for(Product prd : prodArr) {
			if(prd!=null) {
			System.out.println(prd);
			}
		}
		System.out.println("============================");
	}

 

 

 

case "3":	// 제품조회
				viewProdDisplay(prodArr);
				break;

 

 

 

▶▶ Product

 

 

 

@Override
	public String toString() {
		String result = prodCode+"\t"+prodName+"\t"+price+"\t"+jangoCnt;
		return result;
	}

 

-- Member Class에서 passwd, name 변수 추가 / getter setter

 

1. 로그인과 2. 로그아웃 함수 만들기

 

▷ 4. 주문 만들기

-- 로그인 했을 때 주문 함수를 호출할 수 있다.

-- 제품코드를 입력했을 때 배열에 존재하는 제품코드와 비교하고 같지 않다면 주문하시려는 "제품코드는 존재하지 않습니다."라는 메시지 출력

-- 주문량 입력할 때 숫자로 입력하지 않으면 "주문량은 숫자로만 입력하세요."라는 메시지 출력

-- 잔고보다 주문량이 더 많으면 "주문량이 잔고량을 초과하였기에 주문이 불가합니다."라는 메시지 출력

 

day15.zip
0.00MB

 


-- ExceptionJangoOver 클래스 생성

-- === 사용자 정의 예외(오류)절 만들기 ===
1. Exception 클래스를 상속받도록 한다.
2. 생성자를 구성해서 예외메시지(오류메시지)를 등록해 주면 끝난다.

 

 

 

public class ExceptionJangoOver extends Exception {

	// 기본 생성자
	public ExceptionJangoOver() {
		super(">>> 주문량이 잔고량을 초과하였기에 주문이 불가합니다. <<<"+"\n");
	}
	// 파라미터가 있는 생성자
	public ExceptionJangoOver(String errorMsg) {
		super(errorMsg+"\n");
	}
}

 

 

 

▶▶ MainApp

 

 

 

 public static void orderProduct(Scanner sc, Product[] prodArr) 
	 		throws ExceptionJangoOver {
		
		 System.out.print("제품코드 입력 : ");
		 String oderProdCode = sc.nextLine();
		
		 int odrCnt = 0;
		do {
			System.out.print("주문량 : ");
			String strOdrCnt = sc.nextLine();

			try {
				odrCnt = Integer.parseInt(strOdrCnt);
				break;
			} catch (NumberFormatException e) {
				System.out.println("주문량은 숫자로만 입력하세요.");
			}
		} while (true);
		
		boolean flag = false;
		for (int i = 0; i < prodArr.length; i++) {
			if (prodArr[i] != null && prodArr[i].getProdCode().equals(oderProdCode)) {
				flag = true;
				if (odrCnt > prodArr[i].getJangoCnt()) {
					throw new ExceptionJangoOver();	
                    }
			}
		}
		
		if(!flag) {
			System.out.println("주문하시려는 제품코드는 존재하지 않습니다.");
		}
	 }

 

 

 

throw new ExceptionJangoOver();	

 

 

 

-- 주문량이 잔고량보다 더 크면 사용자가 정의한 예외절(Exception)을 던지겠다.(throw)

-- 기본 생성자 호출

 

 

 

 

public static void orderProduct(Scanner sc, Product[] prodArr) throws ExceptionJangoOver

 

 

 

-- orderProduct 메소드는 실행시 사용자가 정의한 ExceptionJangoOver 예외절을 발생시킬 수 있다는 것을 꼭 표시해 주어야 한다.

 

 

 

case "4":
	if(loginUser != null) {
		try {
			orderProduct(sc, prodArr);
		} catch (ExceptionJangoOver e) {
			e.printStackTrace();
			}
		}
		else {
			System.out.println("로그인 후에 주문하실 수 있습니다.");
		}
		break;

 

 

 

 

 

 

System.out.println("오류 메시지 : "+e.getMessage());

 

 

 

 

 

 

throw new ExceptionJangoOver("주문량  "+odrCnt+" 개가 잔고량  "+
prodArr[i].getJangoCnt()+" 개보다 크므로 주문이 불가합니다.");

 

 

 

-- 기본 생성자 호출 외에 사용자가 지정한 문장을 출력할 수 있다.

 

 

 

day15.zip
0.00MB

 


 

 

문제1. 
-- 이순신이 4.주문에서 새우깡을 3개 주문했다고 하자. 3개를 주문한 다음에 제품 조회를 하면 잔고량이 7개로 변해야 한다.

문제2. 
-- 나의 정보 조회 메뉴 만들기
-- 이순신 코인 50000원 중에 새우깡을 3개 주문했으므로 나의 정보 조회 했을 때 47000원이 나와야 한다.

문제3. ▷
-- 제품을 구매할 때마다 구매한 금액의 1%를 포인트로 적립해 준다.

-- 나의 정보 조회를 하면 포인트도 출력되어야 한다.