사용자 정의 예외처리
요즘 유행하는 비트코인을 가져와서 간단한 사용자 정의 예외처리 예시를 만들었다.
입금된 비트코인 잔고보다 인출되는 비트코인 잔고가 더 많으면 throws로 지정된 오류 클래스로 보내기로 했고
오류 클래스에서 지정된 연산 수행 후에 toString 클래스로 오류전용 지정 문구를 출력하도록 만들었다.
class CoinAccount extends BalanceInsufficientException{
private double BTCaccount;
private double ETHaccount;
public CoinAccount(double bTCaccount, double eTHaccount) {
super();
BTCaccount = bTCaccount;
ETHaccount = eTHaccount;
}
public CoinAccount() {
}
public void BTCdeposit(double BTC) {
BTCaccount+=BTC;
}
public void BTCwithdraw(double BTC, Bank b) throws BalanceInsufficientException{
if(BTCaccount<BTC) {
throw new BalanceInsufficientException(BTC - BTCaccount);
}
else {
BTCaccount -= BTC;
b.setBTCBank(BTC);
System.out.println("정상적으로 인출되었습니다. 현재잔고 : " + BTCaccount);
}
}
public void ETHdeposit(double ETH) {
ETHaccount+=ETH;
}
public double getBTCaccount() {
return BTCaccount;
}
public double getETHaccount() {
return ETHaccount;
}
public String toString() {
return "코인잔고 BTC: " + BTCaccount + " ETH: " + ETHaccount;
}
}
class BalanceInsufficientException extends RuntimeException{
double differ;
public BalanceInsufficientException() {
super(); // RuntimException객체의 생성자를 호출한다
}
public BalanceInsufficientException(double differ) {
super(); // RuntimException객체의 생성자를 호출한다
this.differ = differ;
}
@Override
public String toString() {
return "현재 잔고가 " + differ + "만큼 부족하여 인출할 수 없습니다";
}
}
아래의 main클래스를 예외활용하면 아래와 같은 문구가 출력된다.
출력문:
현재 잔고가 0.001만큼 부족하여 인출할 수 없습니다
public static void main(String[] args) {
CoinAccount ca = new CoinAccount();
try {
ca.BTCdeposit(0.004);
ca.BTCwithdraw(0.005);
// 코인 withdraw을 할 때 잔고가 부족하면 오류를 발생시켜 프로그램 종료
}
catch (BalanceInsufficientException e) {
System.out.println(e);
}
}
}
예외 되던지기
예외를 처리한 후에 다시 예외를 발생시키는 행동
호출한 메서드와 호출받은 메서드에서 예외를 두번 처리한다.
예시로 아래의 코드를 참조하자.
- 아빠가 딸에게 심부름을 시켰지만 딸이 돈이 없는 경우 try에서 새로운 에러를 생성하고 catch에서 생성된 오류를 다시 집어던진다.
- 아빠가 받은 에러를 다시 재처리하여 출력한다.
- 아래는 아래코드의 최종 출력문
출력문:
아빠가 딸에게 심부름을 시킴
아빠의 심부름, 하지만 돈이 없음
결국 아빠가 딸 심부름 대신 처리
public class ReThrow {
public static void main(String[] args) throws Exception{
System.out.println("아빠가 딸에게 심부름을 시킴");
father();
}
static void father() throws Exception{
try {
daughter(); //딸 메서드를 호출
}
catch (Exception e) {
System.out.println("결국 아빠가 딸 심부름 대신 처리");
// 다시 되돌려 받은 에러를 아빠메서드에서 대신 처리
}
}
static void daughter() throws Exception{
try {
System.out.println("아빠의 심부름, 하지만 돈이 없음");
throw new Exception(); //호출받았지만 돈이 없는 관계로 새로운 exception오류 생성
}
catch (Exception e) {
throw e; //만들어진 오류를 다시 호출한 메서드(father)로 집어던짐
}
}
}
연결된 예외(Chained Exception)
한 예외가(A) 다른 예외(B)를 발생시킬 수 있다
A예외가 B예외를 발생시키면 A는 B의 원인예외 (Cause Exception)이라고 부른다.
이 두개의 예외를 연결시키는 것이 연결된 예외이다.
사용목적의 이유는 아래와 같다
1. 여러 예외를 하나도 묶어 다루기 위해서
- 여러의 catch블럭으로 일일이 써주면 코드의 가독성이 떨어져서 하나의 예외로 묶은 후에 예외를 한번에 처리한다
2. Checked Exception(필수처리)을 Unchecked Exception(선택처리)으로 변경하기 위해서
- 어떤 필수처리(Exception의 자손 클래스)를 선택처리로 변경할 때 RuntimeException으로 변경하면 되지만, 만약 오류 클래스들이 다른 클래스에 많이 사용되고 있다면 일일이 변경하기가 매우 번거로울 수 있다.
- 따라서 RuntimeException(선택처리) 오류클래스를 만들고 'initCause()' 함수를 사용하여 필수처리의 예외를 선택처리 오류 클래스에 집어넣으면 일일이 변경하지 않고 필수처리 오류들을 선택처리로 한번에 위장변경 시킬 수 있다.
아래의 예시는 만약 편의점에 심부름을 간다고 할 경우, 편의점이 존재하는가 혹은 차가 있는가를 예외처리하여 연결된 예외로 묶어준 경우이다.
- 기본 멤버변수를 차, 편의점을 boolean 타입으로 준 후 false면 AllErrorException으로 한번에 묶어 출력하도록 하였다.
- 오류를 묶을 때 initCause를 사용해 오류가 발생할 시에 AllErrorException으로 통합시켜 다시 throw로 재돌려주는 형식
출력문:
차타고 출발
Lecture.AllErrorException: 편의점의 존재여부
at Lecture.daughter.errand(CauseException.java:53)
at Lecture.CauseException.main(CauseException.java:19)
Caused by: Lecture.ExistException: 주변에 편의점이 없습니다
at Lecture.daughter.gotoConvStore(CauseException.java:68)
at Lecture.daughter.errand(CauseException.java:43)
... 1 more
public class CauseException {
public static void main(String[] args){
daughter d = new daughter();
Mart m = new Mart();
try {
d.errand();
}
catch (AllErrorException e) {
e.printStackTrace();
}
}
}
class daughter{
Boolean Car = true;
Boolean ConvStore = false;
public daughter() {
}
public daughter(int fathermoney) {
this.money = fathermoney;
}
void errand() throws AllErrorException{
try {
gobyCar();
gotoConvStore();
}
catch (CarErrorException e) {
// allerrorexception 클래스에 통합시켜주기위해 isitcause를 사용하여 오류 묶어 실행
// 각각의 다른 오류들을 카테고리화 시켜 통합했다.
AllErrorException ea = new AllErrorException("이동수단 없음");
ea.initCause(e);
throw ea;
}
catch (ExistException e) {
AllErrorException ea = new AllErrorException("편의점의 존재여부");
ea.initCause(e);
throw ea;
}
}
void gobyCar() throws CarErrorException{
if(!Car) {
throw new CarErrorException("차가 없어서 못갑니다");
}
else
System.out.println("차타고 출발");
}
void gotoConvStore() throws ExistException{
if(!ConvStore) {
throw new ExistException("주변에 편의점이 없습니다");
}
else
System.out.println("편의점 출발");
}
class AllErrorException extends Exception{
public AllErrorException(String msg) {
super(msg);
}
}
class CarErrorException extends Exception{
public CarErrorException(String msg) {
super(msg);
}
}
class ExistException extends Exception{
public ExistException (String msg) {
super(msg);
}
}
'Java > 자바의정석 기초편' 카테고리의 다른 글
자바의 정석 9장 (24일차) - Object 클래스(equals, toString, hashCode) (0) | 2022.02.15 |
---|---|
자바의 정석 8장 (23일차) - 연습문제 (try-catch로 숫자게임 반복하기) (0) | 2022.02.14 |
자바의 정석 8장 (21일차) - 메서드에 예외 선언 & finally (0) | 2022.02.10 |
자바의 정석 8장 (20일차) - 프로그램 오류 (0) | 2022.02.09 |
자바의 정석 7장 (19일차) - 7장 연습문제 (객체지향 2) (0) | 2022.02.08 |