OOP & JAVA
[JAVA] 예외처리 및 예시(결제 시스템)
쉽코기
2021. 12. 4. 22:07
기본적인 예외처리 방법과 함께 예외처리로 구현한 결제 시스템 예시를 정리해 보았습니다.
1. try / catch / finally 문
- 에러가 발생할 경우 직접 에러를 해결하는 방법이다.
- try 에서 에러가 발생했을 경우 catch에 명시된 에러의 종류일 경우 이를 받아 처리할 수 있다.
- 예외 상속도 에 따라 상위 에러일 경우 하위 에러를 받아서 처리합니다.
- 해당 예외를 받는 catch 블럭이 없을 경우 스택 블럭을 타고 내려가면서 해당 에러를 처리할 수 있는 catch 블럭을 찾습니다.
- 메인 함수까지 올라가서 에러를 캐치하지 않으면 에러가 터져 프로그램이 종료합니다.
try{
//예외가 발생할 수 있는 코드
} catch(에러클래스1 에러변수1){
// 처리 코드
} catch(애러클래스2 에러변수2){
// 처리코드
}
2. throws 를 통한 예외 발생
: 다음 과 같이 에러를 사용자가 발생 시킬 수 도 있습니다.
if (super.getAmount() < 0) {
throw new RuntimeException("overflow 발생");
} else {
return true;
}
3. 사용자 정의 예외 만들기
- 상황에 따라서 사용자가 자신만의 에러를 만들어 사용할 수 있습니다.
- 쓰임에 따라 원하는 예외 클래스를 상속받아 커스텀 상속클래스를 생성합니다.
// OverflowException.java
public class OverflowException extends RuntimeException {
private static final long serialVersionUID = 1222179582713735628L;
public OverflowException(String message) {
super(message);
}
}
//main 함수
if (super.getAmount() < 0) {
throw new OverflowException("overflow 발생");
} else {
return true;
}
4. Checked / UnChecked 예외
- UnChecked 예외는 예외 상속도중 Runtime 예외와 그를 상속받는 모든 클래스를 말합니다.
- Checked 예외는 예외중 이를 제외한 에러들을 말합니다.
- Checked 예외를 발생 시킬 때에는 try-catch 문으로으로 throw절을 감싸거나
- throw 절이 포함된 메서드 시그내처 옆에 throws <예외클래스>를 명시해야만 합니다.
illegalArgumentException 은 예외 상속도중 runtime 을 상속받지 않으므로 checked 이고 이를 사용하기 위해 thrwos를 붙여 사용한 예시입니다.
public Wallet(final User user) throws IllegalAccessException {
if (user == null) {
throw new IllegalArgumentException("user cannot be null");
}
}
5. 예외처리 예제 - 결제시스템
결재 과정 중간에 결재에 실패 했을때 야기되는 문제를 예외처리를 통해 해결 해보았습니다.
- 상품의 금액 만큼 사용자의 계좌에서 금액을 차감한다.
- 재품의 재고 수량을 한개 줄인다.
만약 이 결재 과정중 1번을 진행 했지만 2번을 진행하던 중 재고 수량이 없을 경우 사용자의 계좌에 돈을 다시 돌려주어야합니다.
결재를 진행하기 앞서 수량을 확인한다 하더라도 다른 사용자가 먼저 결재를 해 수량이 없어지는 경우가 생길 수가 있습니다.
<제품이 있다면>
- 지갑에서 상품의 가격만큼 차감한다.
- 창고에서 해당 제품을 제거한다.
<제품없다면>
- 지갑에서 상품의 가격만큼 차감한다.
- 창고에서 해당 제품을 제거하는 과정중 removeProduct 내부에서 ProductNotFoundException(Rumtime 을 상속받음) 을 발생시킨다.
- removeProduct 내부에서 발생한 예외는 스택 블럭을 타고 메인함수의 그자리로 넘어와 터지고 catch에서 받아진다.
- 지갑에 상품의 가격만큼을 다시 더해줍니다.
// main.java
wallet.withdraw(product.getPrice());
try {
warehouse.removeProduct(product.getId());
} catch (ProductNotFoundException e) {
wallet.deposit(product.getPrice());
}
//warehouse.java
...
public void removeProduct(final UUID id) {
for (int i = 0; i < this.products.size(); ++i) {
if (this.products.get(i).getId().equals(id)) {
this.products.remove(i);
if (isProductOutOfStockMock(i)) {
throw new ProductNotFoundException("Product not found!");
}
}
}
}