예외처리란?
- 예외가 발생하여 프로세스가 강제적으로 종료되는 것을 예외 처리를 통해 프로세스가 강제적으로 종료되지 않게 핸들링하는 것
- 자바 가상 머신은 예외 처리 구문이 있으면 예외 처리가 됐다고 판단하여 프로그램을 강제 종료하지 않는다.
예외 처리 (try - catch - finally)
- 예외 처리 문법은 3가지 요소(try, catch, finally)로 구성돼 있다.
- try : 예외가 발생할 수 있는 코드를 포함하는 블록
- catch(예외 타입) : 예외 타입에 해당하는 예외를 처리하는 코드를 포함하는 블록, 다중 생성 가능
- finally : 예외 발생 유무를 떠나 항상 실행되는 블록, 생략 가능
// 각 예외마다 처리해야할 내용이 다를 경우
try {
// 예외가 발생할 가능성이 있는 코드
} catch (예외 클래스 참조 변수명) {
// 예외 클래스에 해당하는 예외가 발생했을 때 처리
}
...
catch (예외 클래스 참조 변수명) {
// 예외 클래스에 해당하는 예외가 발생했을 때 처리
} finally {
// 항상 실행되는 영역, 생략 가능
}
// 각 예외마다 처리해야할 내용이 같을 경우
try {
// 예외가 발생할 가능성이 있는 코드
} catch (예외 클래스1 | 예외 클래스2 참조 변수명) {
// 예외 클래스1 또는 2에 해당하는 예외가 발생했을 때 처리
} finally {
// 항상 실행되는 영역, 생략 가능
}
예외 처리 과정
현재 색상과 동일한 글은 예시
- try 블록 안의 코드 실행
try { System.out.println(3 / 0); } - 예외 발생
0으로 나눌 수 없기 때문에 예외가 발생함 - JVM이 발생한 예외 타입의 객체 생성
ArithmeticException 타입의 객체 생성 - catch()의 매개변수로 전달
- 예외 타입에 해당하는 catch() 구문이 있을 경우
catch(ArithmeticException e)가 있을 경우- catch() 블록 안의 코드 실행
{ System.out.println("0으로 나눌 수 없습니다."); }
- catch() 블록 안의 코드 실행
- 예외 타입에 해당하는 catch() 구문이 없을 경우
catch(FileNotFoundException e)와 같이 발생한 예외의 타입이 아닌 다른 예외 타입만 존재할 경우- 프로그램 강제 종료
해당하는 예외 타입이 없어 예외 처리가 되지 않아 강제 종료된다.
- 프로그램 강제 종료
- 예외 타입에 해당하는 catch() 구문이 있을 경우
리소스 자동 해제 예외 처리 (try-with-resources)
- Java 7부터는 try-with-resources문을 사용하여 리소스를 자동으로 해제할 수 있다.
- try-with-resources문은 예외 발생 여부와 관계없이 실행이 끝나면 자동으로 close() 메서드를 호출하여 리소스를 해제한다.
- 리소스 객체는 java.lang.AutoCloseable 인터페이스를 구현하여 close() 메서드 포함을 보장해야 한다.
try-with-resources 구조
try (리소스 자동 해제가 필요한 객체 생성) {
// 예외 발생 가능 코드
} catch (예외 클래스명 참조 변수명) { // catch문은 다중 생성 가능
// 예외 발생 시 처리할 코드
} finally {
// 예외 발생 여부에 관계없이 실행할 블록, 생략 가능
}
try-with-resources 사용 예시
public class Main {
public static void main(String[] args){
try (BufferedReader br = new BufferedReader(new FileReader("/Users/wk/desktop/test.txt"))){
System.out.println(br.readLine());
} catch (IOException ie) {
ie.printStackTrace();
}
}
}
finally를 이용하여 리소스 수동 해제 사용 예시
public class Main {
public static void main(String[] args){
BufferedReader br = null;
try {
br = new BufferedReader(new FileReader("/Users/wk/desktop/test.txt"));
System.out.println(br.readLine());
} catch (FileNotFoundException fe) {
System.out.println("파일을 찾을 수 없습니다.");
} catch (IOException ie) {
ie.printStackTrace();
}
finally {
if (br != null) {
try {
br.close();
} catch (IOException ie) {
ie.printStackTrace();
}
}
}
}
예외 처리 (예외 전가)
- 위에서는 예외가 발생할 가능성이 있는 코드를 직접 예외가 발생했을 때의 차선책을 두어 예외 처리를 하였다.
- 이처럼 예외가 발생했을 때 직접 예외를 처리할 수도 있지만, 호출한 지점으로 처리를 예외 처리를 전가시킬 수도 있다.
- 예외를 전가하면 예외 처리 의무를 호출한 메서드가 갖게 된다.
// 예외 전가 구조
리턴 타입 메서드명(매개변수) throws 예외 클래스 타입1, ..., 예외 클래스 타입N { // 단일 가능
// 예외 발생 가능 코드
}
/*
위의 메서드를 호출한 지점으로 예외 처리를 전가함
*/
예시
public class Main {
public static void main(String[] args){
Scanner sc = new Scanner(System.in);
String inp = sc.nextLine();
try {
test(inp);
} catch (InterruptedException ie) {
ie.printStackTrace();
}
}
static void test(String inp) throws InterruptedException {
System.out.println("1초 후 메세지가 출력됩니다.");
Thread.sleep(1000);
System.out.println(inp);
}
}
예외 처리 (사용자 정의 예외 클래스)
- 해당하는 예외 클래스가 없을 때 직접 예외 클래스를 정의하여 예외 처리를 할 수 있다.
- 예 : 계좌 잔액이 음수일 경우
- 예외 클래스의 이름은 Exception으로 끝나는 것이 일반적이다.
사용자 정의 예외 클래스 생성 방법
예외 클래스 생성
- 예외 클래스를 정의하는 방법은 Exception 클래스를 상속하는 방법과 RuntimeException 클래스를 상속하는 방법이 있다.
- Exception : 일반 예외(실행 전 검사)
- RuntimeException : 실행 예외(실행 후 검사)
- 클래스 내부에는 기본 생성자와 String 타입의 매개변수를 갖는 생성자 2개를 선언한다.
- 기본 생성자
- String 타입의 매개 변수를 갖는 생성자 : 예외 메시지 전달용
class CustomException extends Exception { // 또는 RuntimeException
// 기본 생성자 정의
CustomException() {
}
// 문자열을 받는 생성자 정의
CustomException(String str) {
// 상위 클래스 생성자 호출
super(str);
}
}
정의한 클래스 객체 생성
CustomException customException1 = new CustomException();
CustomException customException2 = new CustomException("예외 메세지");
예외 발생시키기
- 고려하는 예외 상황이 발생하면 'throw' 키워드를 이용해 예외를 발생시킨다.
- throw 키워드를 사용하면 바로 예외가 발생한다.
// 객체를 이용하여 예외 발생시키기
throw customException1;
throw customException2;
// 객체를 생성하지 않고 예외 발생시키기
throw new CustomException();
throw new CustomException("예외 메세지");
예외 클래스 생성 예시
- 아래의 예시는 0원의 잔액을 갖고 있는 계좌에서 돈을 출금할 때 예외를 발생시킨 예시
(잘못된 코드일 수도 있습니다.)
public class Main {
public static void main(String[] args){
// 계좌 클래스 인스턴스 생성
Account account = new Account("홍길동", "1234-567");
// 입금 메서드(1000원 입금)
account.deposit(1000);
try {
System.out.println("출금 : " + account.withdraw(2000));
} catch (MinusException me) {
me.printStackTrace();
}
}
}
// 계좌 클래스
class Account {
private String userName;
private String accountNumber;
private int money;
public Account(String userName, String accountNumber) {
this.userName = userName;
this.accountNumber = accountNumber;
}
public void deposit(int money) {
this.money += money;
}
// 현재 보유 금액보다 출금 요청 금액이 클 경우 예외 발생시킴
// 예외는 호출한 지점으로 전가함
public int withdraw(int money) throws MinusException {
if (this.money < money) {
throw new MinusException("계좌 잔액이 부족합니다."); // 예외를 던진 시점에 예외 발생
}
this.money -= money;
return money;
}
}
// 사용자 정의 예외 클래스
class MinusException extends Exception {
public MinusException() {
}
public MinusException(String message) {
super(message);
}
}
Reference
- Do it! 자바 완전 정복
- http://tcpschool.com/java/java_exception_throw
'Langauge > Java-basic' 카테고리의 다른 글
[Java] 예외(Exception) (0) | 2022.08.14 |
---|---|
[Java] 익명 이너 클래스(Anonymous Class) (0) | 2022.08.11 |
[Java] 이너 인터페이스(중첩 인터페이스) (0) | 2022.08.11 |
[Java] 인터페이스란? (0) | 2022.08.07 |
[Java] 추상 클래스와 추상 메소드 (abstract 제어자) (0) | 2022.08.05 |