[Java 22] 자바 - 예외 처리

학습목표

  1. 실행예외의 대표적인 경우를 살펴본다.
  2. 예외 처리방법에 대해 정확히 이해하고 활용한다.

예외와 예외 클래스

예외에는 두가지 종류가 있습니다. 하나는 일반 예외(Exception)이고, 다른 하나는 실행 예외(Runtime Exception)입니다. 일반 예외와 실행 예외 클래스를 구분하는 방법은 일반 예외는 Exception을 상속받지만, Runtime Exception을 상속받지 않는 클래스들이고, 실행 예외는 RuntimeExcaeption을 상속받는 클래스입니다.


실행 예외

실행예외는 자바 컴파일러가 체크를 하지 않기 때문에 오로지 개발자의 경험에 의해서 예외 처리 코드를 삽입해야 합니다.

NullPointExcaeption

이는 객체 참조가 없는 상태, 즉 null 값을 갖는 참조 변수로 객체 접근 연산자인 도트(.)를 사용했을 때 발생합니다. 객체가 없는 상태에서 객체를 사용하려고 하여 예외가 발생하는 것입니다.

예제

public class Exception {
	public static void main(String[] args) {
		String data = null;
		System.out.println(data.toString());
	}
}

data 변수는 null값을 가지고 있기 때문에 String 객체를 참조하고 있지 않습니다. 따라서 NullPointException이 발생하는 것입니다.


ArrayIndexOutOfBoundsException

배열에서 인덱스 범위를 초과하여 사용할 경우 발생합니다.

예제

public class Exception {
	public static void main(String[] args) {
		String data1 = args[0];
		String data2 = args[1];
		System.out.println(data1);
		System.out.println(data2);
	}
}


NumberFormatException

프로그램 개발하다 보면 무자열로 있는 데이터를 숫자로 변경하는 경우가 자주 발생합니다. 보통 다음과 같이 코드를 작성하게 됩니다.

반환타입 메소드명(매개변수) 설명
int Integer.parseInt(String s) 주어진 문자열을 정수로 변환해서 리턴
double Double.parseDouble(String s) 주어진 문자열을 실수로 변환해서 리턴


이와 같은 메소드들은 매개값인 문자열이 숫자로 변환될 수 있다면 숫자를 리턴하지만, 숫자로 변환될 수 없는 문자가 포함되어 있으면, NumberFormatException이 발생합니다.


예제

public static void main(String[] args) {
		String data1 = "100";
		String data2 = "a100";
		
		int value1 = Integer.parseInt(data1);
		int value2 = Integer.parseInt(data2);	// NumberFormatException 발생
		
		int result = value1 + value2;
		System.out.println(data1 + "" + data2 + "" + result);
	}
}


ClassCastException

타입 변환(Casting)은 상위 클래스와 하위 클래스 간에 발생하고 구현 클래스와 인터페이스 간에도 발생합니다. 이러한 관계가 아니면 클래스는 다른 클래스로 타입 변환할 수 없습니다. 억지로 타입변환 시도할 경우 ClassCastException이 발생합니다.

예제

public class Exception {

	public static void main(String[] args) {
		Dog dog = new Dog();
		changeDog(dog);

		Cat cat = new Cat();
		changeDog(cat);
	}
	public static void changeDog(Animal animal) {
		//if (animal instanceof Dog) {	// instaceof 연산자로 ClassCaseException 확인 가능
		Dog dog = (Dog) animal;		// ClassCaseException 발생 
		//}
	}
	static class Animal {}
	static class Dog extends Animal {}
	static class Cat extends Animal {}
}


예외 처리 코드

try 블록에는 예외발생 가능 코드가 위치합니다. try 블록의 코드가 예외 없이 정상 실행 시 catch 블록의 코드는 실행되지 않고 finally 블록의 코드를 실행합니다. 만약 try 블록의 코드에서 예외가 발생하면 즉시 실행을 멈추고 catch 블록으로 이동하여 예외 처리 코드를 실행합니다.

예외처리

예제

public class Exception {
	public static void main(String[] args) {
		try {
			Class cl = Class.forName("java.lang.String2");
		} catch(ClassNotFoundException e) {
			System.out.println("클래스가 존재하지 않습니다.");
		}
	}
}


예외 떠넘기기

throws 키워드는 메소드 선언부 끝에 작성되어 메소드에서 처리하지 않은 예외를 호출한 곳으로 떠넘기는 역할을 합니다.

리턴타입 메소드명(매개변수, ...) throws 예외클래스1, 예외클래스2, ... {
}

다음과 같이 throws Exception만으로 모든 예외 간단히 떠넘길 수 있습니다.

리턴타입 메소드명(aoroqustn, ...) throws Exception {
}

throws 키워드가 붙어있는 메소드는 반드시 try 블록 내에서 호출되어야 합니다. 그리고 catch 블록에서 떠넘겨 받은 예외를 처리해야 합니다.

public class ThrowsMain {
	public static void main(String[] args) {
		try {
			findClass();
		} catch(ClassNotFoundException e) {
			System.out.println("클래스가 존재하지 않습니다.");
		}
	}
	
	public static void findClass() throws ClassNotFoundException {
		Class cl = Class.forName("java.lang.String2");
	}
}


사용자 정의 예외와 예외 처리

개발을 하다보면 자바 표준 API에서 제공하는 예외 클래스가 부족하게 느껴질 수 있습니다. 자바에서는 개발자가 직접 예외를 정의해서 만들 수 있도록 하는 사용자 정의 예외가 존재합니다.

사용자 정의 예외 클래스 선언

// 일반 예외 시 Exception, 실행 예외 시 RuntimeException
public class XXXException extends [ Exception | RuntimeException ] {
	public XXXException() { }	// 매개변수 없는 기본 생성자
	public XXXException(String message) { super(message); } // 예외 발생원인 전달용 생성자
}

예제 1

public class BalanceInsufficientException extends Exception{	//Exception 상속
	public BalanceInsufficientException() {}
	public BalanceInsufficientException(String message) {
		super(message);
	}
}


예외 발생시키기

try {
	method();
} catch(XXXException e) {
	// 예외처리
}

예제 2

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 BalanceInsufficientException {
		if(balance < money) {
			throw new BalanceInsufficientException("잔고부족" + (money-balance) + " 모자람");
		}
		balance -= money;
	}
}


예외 정보 얻기

모든 예외 객체들은 Exception을 상속하기 때문에 Exception이 가지고 있는 메소드들을 모든 예외 객체에서 호출할 수 있습니다. 그중에서도 가장 많이 사용되는 메소드는 getMessage()와 printStackTrace()입니다.

다음과 같이 “예외 메시지”에는 예외 발생 원인에 대한 설명이 포함됩니다.

throw new XXXException("예외 메시지");  // 

더 상세한 원인을 세분화하기 위해 getMessage() 메소드의 리턴값을 통해 예외 발생 코드를 추적해서 모두 콘솔에 출력해줍니다.

} catch(Exception e) {
	String message = e.getMessage();
}


예제

[Account] 사용자 정의 예외 발생시키기

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 BalanceInsufficientException {
		if(balance < money) {
			throw new BalanceInsufficientException("잔고부족 : " + (money-balance) + " 모자람");
		}
		balance -= money;
	}
}

[AccountMain] 사용자 정의 예외 발생시키기, 실행 클래스

public class AccountMain {
	public static void main(String[] args) {
		Account account = new Account();

		account.deposit(10000);
		System.out.println("예금액 : " + account.getBalance());

		try {
			account.withdraw(30000);
		} catch (BalanceInsufficientException e) {
			String message = e.getMessage();
			System.out.println(message);
			System.out.println();
			e.printStackTrace();
		}
	}
}

실행결과

예금액 : 10000
잔고부족 : 20000 모자람

day0503.BalanceInsufficientException: 잔고부족 : 20000 모자람
	at day0503.Account.withdraw(Account.java:18)
	at day0503.AccountMain.main(AccountMain.java:11)

태그:

카테고리:

업데이트:

댓글남기기