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문이 있어야 한다. 예외가 발생했을 경우에도 값을 반환해야 하기 때문이다.
예외,상속을 이용한 은행 계좌 만들기 프로그램
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() 등등 다른 자료형변환 함수도 포함)