본문 바로가기

자바

Day09


package com.test.workshop3.doctor;
public class Doctor {
    private String name;
    private String department;
    public Doctor() {
    }
    public Doctor( String name, String department ) {
        this.name = name;
        this.department = department;
    }
    @Override
    public String toString() {
        return department + " : " + name + " 선생님";
    }
    public void treatPatient() {
        System.out.println( "환자를 진료합니다." );
    }
}
package com.test.workshop3.doctor;
public class Dentist extends Doctor {
//	String dentistName;
	public Dentist(String name) {
		super(name, "치과");
//		super. //조상 변수가 private이라 접근불가
	}
	public void pullOutTooth() {
		System.out.println("이를 뽑습니다.");
	}
}
package com.test.workshop3.doctor;
public class Surgeon extends Doctor{
	public Surgeon(String name) {
		super(name, "외과");
	}
	public void performSurgery() {
		System.out.println("수술을 집도하다.");
	}   
}

finally 블럭 : 예외의 발생여부에 상관없이 실행되어야할 코드를 포함시킬 목적으로 사용된다. try-catch-finally 순서.

 


package com.test02;
public class Sample08 {
	public static void main(String[] args) {
		try {
			startInstall();
			copyFiles();
		}catch(Exception e) {
			e.printStackTrace();
		}finally {
			deleteTempFiles();
		}
	}
	static void startInstall() {}
	static void copyFiles() {}
	static void deleteTempFiles() {	}
}

try블럭에서 return문이 실행되는 경우에도 finally블럭의 문장들이 먼저 실행된 후에, 현재 실행 중인 메서드를 종료한다. catch블럭의 문장 수행 중에 return문을 만나도 finally블럭의 문장들은 수행된다. 

 

자동 자원 반환 - try-with-resources문  : 입출력에 사용되는 클래스 중에서는 사용한 후에 꼭 닫아 줘야 하는 것들이 있다. 그래야 사용했던 자원(resources)이 반환되기 때문이다. 

package com.test02;
class CloseableResource implements AutoCloseable {
	public void exceptionWork(boolean exception) throws WorkException {
		System.out.println("exceptionWrok(" +exception+ ") 가 호출됨");	
		if(exception) 
			throw new WorkException("WorkException 발생!!");
		}
		public void close() throws CloseException {
			System.out.println("close()가 호출됨");
			throw new CloseException("CloseException발생!");
			}
	}
class WorkException extends Exception {
	WorkException(String msg){
		super(msg);
	}
}
class CloseException extends Exception {
	CloseException(String msg) {
		super(msg);
	}
}
public class Sample10 {
	public static void main(String[] args) {
		try(CloseableResource cr = new CloseableResource()) {
			cr.exceptionWork(false); //예외가 발생하지 않는다.
		}catch(WorkException e) {
			e.printStackTrace();
		}catch(CloseException e) {
			e.printStackTrace();
		}
		System.out.println();		
		try(CloseableResource cr = new CloseableResource()) {
			cr.exceptionWork(true); // 예외가 발생한다. 
		}catch(WorkException e) {
			e.printStackTrace();
		}catch(CloseException e) {
			e.printStackTrace();
		}
	}
}

try-with-resources문의 괄호()안에 객체를 생성하는 문장을 넣으면, 이 객체는 따로 close()를 호출하지 
않아도 try블럭을 벗어나는 순간 자동적으로 close()가 호출된다. 그 다음에 catch블럭 또는 finally블럭이 수행된다.
** try블럭의 괄호()안에 변수를 선언하는 것도 가능하며, 선언된 변수는 try블럭 내에서만 사용할 수 있다.
try-with-resources문에 의해 자동으로 객체의 close()가 호출될 수 있으려면, 클래스가 AutoCloseable이라는 
인터페이스를 구현한 것이여야만 한다. 
main메서드에 두 개의 try-catch문이 있는데 두번째 출력형태에서 먼저 exceptionWork()에서 발생한 에외에
대한 내용이 출력되고,close() 에서 발생한 예외는 '억제된(suppressed)'이라는 의미의 머리말과 함께 출력되었다.
두 예외가 동시에 발생할 수는 없기 때문에, 실제 발생한 예외를 WorkException으로 하고, CloseExceptio은 
억제된 예외로 다룬다. 억제된 예외에 대한 정보는 실제로 발생한 예외인 WorkException에 저장된다. 

 

사용자정의 예외 만들기 :

package com.test1;
class MyException2 extends Exception {
	MyException2(String msg) {
		super(msg);
	}
}
public class Sample05 {
	public static void main(String[] args) {
	int i = 2;
		try {
			if( i == 2) { //조건을 통해 사용자정의로 예외문을 만들 수 있다.
		throw new MyException2("안녕하세요"); //예외 발생 시킴
				}
			}catch(MyException2 e) {
			System.out.println(e.getMessage());	
				}
		}
}

 

예외 되던지기(exception re-throwing) : 한 메서드에서 발생할 수 있는 예외가 여럿인 경우, 몇 개는 try-catch문을 통해서 메서드 내에서 자체적으로 처리하고, 그 나머지는 선언부에 지정하여 호출한 메서드에서 처리하도록 함으로써, 양쪽에서 나눠서 처리되도록 할 수 있다. 그리고 단 하나의 예외에 대해서도 예외가 발생한 메서드와 호출한 메서드,양쪽에서 처리하도록 할 수 있다. 예외를 처리한 후에 인위적으로 다시 발생시키는 방법을 통해서 가능한데, 이것을 '예외 되던지기(exception re-throwing)'라고 한다. 

먼저 예외가 발생할 가능성이 있는 메서드에서 try-catch문을 사용해서 예외를 처리해주고 catch문에서 필요한 작업을 행한 후에 throw문을 사용해서 예외를 다시 발생시킨다. 다시 발생한 예외는 이 메서드를 호출한 메서드에게 전달되고 호출한 메서드의  try-catch문에서 예외를 또다시 처리한다. 이때 주의 할 점은 예외가 발생할 메서드에서는 try-catch문을 사용해서 예외처리를 해줌과 동시에 메서드의 선언부에 발생할 예외를 throws에 지정해줘야 한다.

package com.test1;
public class Sample03 {
	public static void main(String[] args) {
		try {
			method1();
		}catch(Exception e) {
			System.out.println("main메서드에서 예외가 처리되었습니다.");
		}
	}
static void method1() throws Exception {
		try {
			throw new Exception();
		}catch (Exception e) {
			System.out.println("method1메서드에서의 예외가 처리됨");
			throw e; // 다시 예외를 발생시킨다.
		}
	}
}
method1()과 main메서드 양쪽의 catch블럭이 모두 수행되었음을 알 수 있다.
method1()의 catch블럭에서 에외를 처리하고도 throw문을 통해 다시 예외를 발생 시켰다.
그리고 이 예외를  main메서드에서 한 번 더 처리하였다.
반환값이 있는 return문의 경우,catch블럭에도 return문이 있어야 한다. 예외가 발생했을 경우에도 값을 반환해야 하기 때문이다. 

예외,상속을 이용한 은행 계좌 만들기 프로그램 

선언클래스와 구동 클래스를 만들고 사용자 정의 예외 클래스를 2개 생성하여 은행계좌 시스템을 구현했다.

package com.test.workshop3.account;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import javax.naming.InvalidNameException;
import com.test.workshop3.exception.*;
public class AccountTest {
	public static void main(String[] args) throws InvalidValueException, AccountNotFoundException {
		int menu = 0;
		Account acc = null;
		while (menu != 9) {
			printMenu();
			try {
				String account;
				String name;
				int balance;
				menu = Integer.parseInt(getUserInput());
				int a3;
				int a4;
				// TODO 각 메뉴 선택 시 해야 할 일 구현
				switch (menu) {
				case 1: // 계좌 생성
					System.out.print("\n계좌번호 : ");
					account = AccountTest.getUserInput();
					System.out.print("예금주 : ");
					name = AccountTest.getUserInput();
					System.out.print("최초 입금 : ");
					balance = Integer.parseInt(getUserInput());
					acc = new Account(account, name, balance);
					break;
				case 2: // 계좌 정보 출력
					if (acc == null) {
						throw new AccountNotFoundException("[에러] 계좌가 없습니다.");
					}
					System.out.println("현재 고객님의 보유 계좌 목록입니다.");
					System.out.println(acc);
					break;
				case 3: // 입금
					System.out.print("입금할 금액 : ");
					a3 = Integer.parseInt(getUserInput());
					acc.deposit(a3);
					break;
				case 4: // 출금
					System.out.print("출금할 금액 : ");
					a4 = Integer.parseInt(getUserInput());
					acc.withdraw(a4);
					break;
				case 9: // 종료
					System.out.println("종료합니다.");
					break;
				default:
					System.out.println("[에러] 메뉴를 잘못 입력하였습니다.");
					break;
				}
			} catch (AccountNotFoundException e) {
				System.out.println(e.getMessage());
			} catch (InvalidValueException e) {
				System.out.println(e.getMessage()); // TODO catch 세분화 (각각의 예외 상황 별로)
			} catch (NumberFormatException e) {
				System.out.println("[에러] 메뉴는 숫자로 입력해야 합니다.");
			} catch (Exception e) {
				System.out.println(e.getMessage());
			}
		}
	}
	private static void printMenu() {
		System.out.println("\n===== < 메뉴 > =====");
		System.out.println(" 1. 계좌 생성");
		System.out.println(" 2. 계좌 정보 출력");
		System.out.println(" 3. 입금");
		System.out.println(" 4. 출금");
		System.out.println(" 9. 종료");
		System.out.println("===================");
		System.out.print(">> 메뉴 : ");
	}
	public static String getUserInput() {
		BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
		String inputString = null;
		try {
			inputString = br.readLine();
		} catch (IOException e) {
			e.printStackTrace();
		}
		return inputString;
	}
}

 

package com.test.workshop3.account;
import com.test.workshop3.exception.AccountNotFoundException;
import com.test.workshop3.exception.InvalidValueException;
public class Account {  
	private String account;
	private String name;
	private int balance;
	public String getAccount() {
		return account;
	}
	public void setAccount(String account) {
		this.account = account;
	}
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public int getBalance() {
		return balance;
	}
	public void setBalance(int balance) {
		this.balance = balance;
	}
	public Account(String account, String name, int balance) throws InvalidValueException {
		// TODO 최초 입금 금액이 0원 이하인 경우, 예외 발생
		if (balance <= 0) {
			throw new InvalidValueException("[에러] 최초금액은 0원 이상입니다.");
		}
		this.balance = balance;
		this.account = account;
		this.name = name;
		System.out.println("계좌가 정상적으로 생성되었습니다.");
	}
	public void deposit(int money) throws InvalidValueException {
		// TODO 입금할 금액이 잘못 입력된 경우, 예외 발생
		if (money <= 0) {
			throw new InvalidValueException("최소 금액은 0원 이상입니다.");
		}
		this.balance += money;
		System.out.println(money + " 원 정상입금되었습니다.");
	}
	public void withdraw(int money) throws InvalidValueException {
		// TODO 출금할 금액이 잘못 입력되었거나, 잔액이 부족한 경우 예외 발생
		if (balance < money) {
			throw new InvalidValueException("잔고 부족 " + (money - balance) + " 원모자람");
		}
		if (money < 0) {
			throw new InvalidValueException("출금할 금액은 0원 초과로 입력해");
		}
		balance -= money;
	}
	@Override
	public String toString() {
		return "[계좌] " + this.account + "\t[예금주] " + this.name + "\t[잔액] " + this.balance;
	}
}
package com.test.workshop3.exception;
public class InvalidValueException extends Exception {
    public InvalidValueException(String msg) {
        super(msg);
    }
}
package com.test.workshop3.exception;
//부모 클래스인 Exception을 상속받아 사용자가 정의(customException)한 클래스를 사용할 수 있다.
public class AccountNotFoundException extends Exception {
	public AccountNotFoundException(String msg) {
        super(msg);
    }
}​

 

NumberFormatException 예외처리 :

NumberFormatException 은 프로그램 코딩시 종종 일어나는 오류
영어 그대로 해석하면  숫자형 포맷 오류 발생한다
문자를 숫자로 변경시도하다가 에러가 발생하는 경우이다.
(Double.parseDouble(), Float.parseFlost() 등등 다른 자료형변환 함수도 포함)

 

 

 

 

'자바' 카테고리의 다른 글

Day10-1  (0) 2021.05.17
2주차 은행 계좌 예제 수정  (0) 2021.05.16
Day08  (0) 2021.05.13
Day07  (0) 2021.05.13
Day06  (0) 2021.05.11