본문 바로가기
Category/JAVA

[JAVA] 예외 처리

by developer__Y 2023. 10. 24.
예외(Exception)

자바에서의 예외는 잘못된 사용 또는 코딩으로 인한 오류를 말한다.

예외가 발생되면 프로그램은 곧바로 종료되지만,자바에서는 예외 처리를 통해 계속 실행 상태를 유지할수있다.

 

 

사진 출처 : https://www.tcpschool.com/java/java_exception_class

  • 일반 예외 (Exception)
    컴파일러가 예외 처리 코드 여부를 검사하는 예외로, ClassNotFoundException, InterruptedException등이 있다.
  • 실행 예외(RuntimeException)
    컴파일 단계에서 예외 처리 코드 여부를 검사하지 않는 예외로, RuntimeException과 그 자식 클래스에 해당한다.

자바는 예외가 발생하면 예외 클래스로 부터 객체를 생성한다. 이 모든 예외 클래스는 Throwable을 상속받고,

추가적으로 Exception을 상속받는다.

예외가 발생하면, 프로그램 종료를 막고 정상 실행을 유지하기위한 코드처리를 예외 코드 처리라고 한다.

예외를 처리하는 방법은 크게 두가지가있다.

try-catch

try-catch-finally 블록으로 구성된 예외 처리 구문으로, 생성자 내부와 메소드 내부에서 작성된다.

예외가 발생할 것으로 예상되는 메소드에 미리 '예외가 발생하면 이렇게 처리하세요.'라고 가이드를 제시하는 것과 같다.

이를 코드로 표현하면,

 

public class ExceptionEx {
	
	public static void dataLength(String data) {
		
			try{ int result = data.length();	/* 예외가 발생할수 있는 코드, 
	                                      String 파라미터의 문자열 수를 int로 받는데,
	                                        null값을 받게 되면 NullpointerException이 발생한다	.
                                                */							
				System.out.println("문자수:"+ result);  
				}
			
			catch(NullPointerException e) {		// NullpointerException이 발생할 경우 (= catch) 어떻게 처리할것인가?
				e.printStackTrace();
				}
			
			finally {					// 예외가 발생하든, 안하든, 마지막으로 실행되는 코드
					System.out.println("예외후 마무리실행");
					}
			}

파라미터로 String 문자열을 받아 문자열 수를 출력해주는 메소드에서, String 문자열 값이 null 이라면 

예외가 발생되어 정상적으로 처리되지않고 종료될 것이다.

그렇기 때문에 예외가 발생될 것으로 예상되는 이 dataLength() 메소드 내부에 try-catch문을 만들어

예외가 발생하면, 어떻게 처리하는지에 대해 예외 처리 코드를 작성한다.

이러한 catch 블록은 다중으로 작성이 가능해서, 여러 예외들에 대한 처리가이드를 적어놓을수 있다.

예외가 발생하면 NullPointerException 클래스의 객체 e가 생성된다.

예외의 정보를 출력하는 메소드들은 대표적으로 3가지가 있다.

  • getMessage(); 에러의 원인을 간단하게 출력한다.
  • toString(); 해당 메소드는 예외의 내용과 원인을 출력해준다.
  • printStackTrace(); 예외 발생 근원지를 찾아 발생 단계별로 출력해준다.
예외 떠넘기기 throws

메소드를 호출한 곳으로 예외를 떠넘길 수 있다. 즉, '예외가 발생하면 해당 메소드를 호출한 곳에서 처리하세요.'라는 것이다. 이경우 해당 메소드를 호출한 곳에서 예외를 받아 처리해야 한다.

 

사용자 정의 예외

예를 들어, 은행에서 예금 출금을 하는데 잔액보다 많은 금액을 출금하려고하면 예외를 발생시켜야 할 것이다.

자바 표준 라이브러리에서 제공하지 않는 예외를 처리하기 위해 사용자가 직접 예외 클래스를 정의해서 처리할수있다.

이러한 사용자 정의 예외는 일반예외, 런타임예외 모두 사용할수있다.

앞서 얘기한 은행에서 잔액보다 많은 예금 출금에 대한 예외를 직접 작성한다면,

 

public class InsufficientException extends Exception {
	public InsufficientException() {}	
    public InsufficientException(String message) {
    	super(message);
    }

InsufficientException이라는 클래스를 작성하고 Exception을 상속받는다.

해당 기본 생성자와, 예외 메시지를 입력받는 생성자를 생성해준다.

예외 메시지는 부모 생성자(Exception) 매개값으로 넘겨줘서, 예외 객체의 공통 메소드인 getMessage()의 리턴값으로 사용하기 위해서이다.

 

예외 발생 시키기 throw new

프로그램을 실행하면서, 개발자가 의도하지 않은 상황이 생길때 예외를 발생시켜 예외 처리를 작성한다.

앞서 예를 든 은행에서 잔액보다 많은 금액을 출금하려할때 예외를 발생시키는 상황으로 코드를 작성해보자.

 

public class Account {
		private long balance;
		public Account() {}
		public long getBalance() {
			return balance;}
		public void deposit(int money) {
			balance += money;
		}
		
		public void withdraw(int money) throws InsufficientException {
			if(balance<money) {
				throw new InsufficientException("잔고부족 : "+ (money-balance)+"모자람");
			}
			balance -= money;
		}
}

계좌 조회, 입금, 출금 기능을 Account 클래스에 다음과 같이 작성하였다.

여기서 출금기능인 withdraw에서 예외가 발생할 것으로 예상되어,

조건문을 통해 예금보다 출금 금액이 많을 경우, InsufficientException 예외를 발생 시키고, 파라미터로 해당 메시지를 담았다. 

public class AccountExam {
public static void main(String[] args) {
	
	Account account = new Account();
	
	//예금하기
	account.deposit(10000);
	//잔액조회
	System.out.println(account.getBalance());
	//출금하기
	try { account.withdraw(12000); }
	catch(InsufficientException e) {
		String message = e.getMessage(); 
		System.out.println(message);
	}
		finally {System.out.println("잔액 : " + account.getBalance()); } 
	}
	
	

}

main 메소드에서 Account 객체를 생성하고,

10,000원을 입금하고 잔액 조회를 하낟.

그리고 12,000원을 출금할 때 try-catch문을 통해 발생된 예외 메시지를 출력하게 해주면,

withdraw() 메소드에서 예외를 발생시키고, 이 예외 메시지를 catch문에서 받아와 출력해 준다.

그리고 마지막으로 finally 구문이 실행되게된다.

 

이번에 배운 예외처리와 Scanner, swtich문을 활용하여 

원하는 기능을 입력하고 해당 기능을 수행하는 코드를 만들어봤다.

사용자 정의 예외 발생뒤 프로그램을 종료하는게 아니라 제대로된 입력값을 받을때까지 다시 반복시키는 부분이 어려웠는데, while(true)와 continue를 활용하여 해결하였다.

 

public class AccountExam {
public static void main(String[] args) {
	Scanner scanner = new Scanner(System.in);
	Scanner control = new Scanner(System.in);
	Account account = new Account();
	
	System.out.println("입력하세요. 입금/조회/출금");
	String order = control.next();
	
	switch(order) { 
	case "입금" :
	System.out.println("입금액을 입력하세요.");
	int money = scanner.nextInt();
	account.deposit(money);
			break;
			//잔액조회
	case "조회" :
	System.out.println("현재 잔액은 "+account.getBalance()+ "원");
			break;
	//출금하기
	case "출금" :

	while(true) {
		System.out.println("출금액을 입력하세요.");
		int outmoney = scanner.nextInt();
		try { account.withdraw(outmoney); 
				}
	
	catch(InsufficientException e) {
		String message = e.getMessage(); 
		System.out.println(message);
			continue;
			}
		break;	// while문 빠져나감
		}	
	break;
	}
	}
}

※해당 게시글은 <이것이 자바다_한빛미디어>를 공부한 내용을 정리한 글로, 틀린 내용이 있다면 댓글로 말씀해주시면 감사드리겠습니다.