자바[11] 예외처리
1. 예외 처리
프로그램에서 예외가 발생할 경우 프로그램의 갑작스러운 종료를 막고, 정상 실행을 유지할 수 있도록 예외 처리를 한다.
오류(error) vs 예외(exception)
오류(error)의 종류:
- 시스템 에러: (예) 메모리 부족(OOM: Out-Of-Memory) -> 수정 매우 힘듦, 불가능.
- 컴파일 에러: 문법 오류 -> 반드시 수정!
- 논리적 오류: 프로그램이 정상적으로 컴파일되고 실행/종료가 되지만, 원하는 결과가 나오지 않는 경우 -> 반드시 수정. 수정 힘듦.
- 예외(exception): 프로그램 실행 중에 발생할 수 있는 비정상적인 상황 -> 반드시 수정.
(1) if-else 문장
(2) try-catch 문장
<ExceptionMain01.java>
import java.util.Scanner;
public class ExceptionMain01 {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
System.out.print("정수 x 입력> ");
int x = Integer.parseInt(sc.nextLine());
System.out.print("정수 y 입력> ");
int y = Integer.parseInt(sc.nextLine());
if (y != 0) {
System.out.println("나눈 몫 = " + (x / y));
} else {
System.out.println("0으로는 나눌 수 없습니다.");
}
}
}
try-catch 문장을 사용한 예외 처리:
try {
정상적인 상황에서 실행할 코드들; // (1)
} catch (Exception 타입의 변수 선언) {
예외 상황이 발생했을 때 처리할 코드들; // (2)
} finally {
예외 상황 발생 여부와 상관 없이 반드시 실행할 코드들; // (3)
}
예외가 발생하지 않을 경우: (1) -> (3)
예외가 발생한 경우: (1) -- 예외 발생 --> (2) -> (3)
try-catch 문장에서 catch 블록은 반드시 1개 이상 있어야 함.
catch 블록은 처리하려는 예외의 종류에 따라서 여러개를 작성할 수 있음.
finally 블록은 선택 사항.
<ExceptionMain02.java>
package com.itwill.exception02;
import java.util.Scanner;
public class ExceptionMain02 {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
try {
System.out.print("x = ");
int x = Integer.parseInt(sc.nextLine());
System.out.print("y = ");
int y = Integer.parseInt(sc.nextLine());
System.out.println("x / y = " + (x / y));
} catch (ArithmeticException e) {
System.out.println("y는 0이 될 수 없음.");
System.out.println(e.getMessage());
} catch (NumberFormatException e) {
System.out.println("x, y는 정수로 입력하세요.");
System.out.println(e.getMessage());
} finally {
System.out.println();
}
}
}
<ExceptionMain03.java>
import java.util.Scanner;
public class ExceptionMain03 {
private final Scanner sc = new Scanner(System.in);
public static void main(String[] args) {
ExceptionMain03 app = new ExceptionMain03();
int x = app.inputInteger2(); //app.inputInteger();
System.out.println("x = " + x);
}
public int inputInteger2() {
try {
System.out.println("정수 입력> ");
return Integer.parseInt(sc.nextLine());
} catch (NumberFormatException e) {
System.out.println("정수로 입력하세요...");
return inputInteger2();
}
}
public int inputInteger() {
int result = 0;
while (true) {
try {
System.out.print("정수 입력> ");
result = Integer.parseInt(sc.nextLine());
break;
} catch (NumberFormatException e) {
System.out.println("입력한 내용은 정수가 아닙니다.");
}
}
return result;
}
}
multi-catch 블록
하나의 catch 구문에서 여러개의 Exception 타입 객체를 처리하는 방법.
try {
} catch (ExceptionType1 | ExceptionType | ... e) {
}
(주의) 상속 관계가 있는 예외 클래스들은 multi-catch 블록에서 사용할 수 없음.
가능한 예: catch (ArithmeticException | NumberFormatException e)
컴파일 에러: catch (ArithmeticException | Exception e)
<ExceptionMain05.java>
import java.util.Scanner;
public class ExceptionMain05 {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
try {
System.out.print("x = ");
int x = Integer.parseInt(sc.nextLine());
System.out.print("y = ");
int y = Integer.parseInt(sc.nextLine());
System.out.print("x / y = " + (x / y));
// int[] array = new int[0]; // 오류를 못잡음.
// array[0] = 100;
// System.out.println(array[0]);
} catch (NumberFormatException | ArithmeticException e) {
System.out.println(e.getMessage());
}
}
}
<ExceptionMain06.java>
public class ExceptionMain06 {
public static void main(String[] args) {
// Calculator 타입 객체 생성
Calculator calc = new Calculator();
// throws 선언문이 있는 메스드들 중에서,
// RuntimeException을 상속하는 예외 타입들은 try-catch를 사용하지 않아도 컴파일 에러가 없음.
// RuntimeException이 아닌 예외 타입들은 반드시
// (1) try-catch 문장을 사용하거나
// (2) throws 선언문을 추가해야 함.
// Integer.parseInt(""); //-> 반드시 try-catch를 사용할 필요는 없음.
try {
int result = calc.divide(100, 0);
System.out.println(result);
} catch (Exception e) {
e.printStackTrace();
}
System.out.println("main 정상 종료");
}
}
<Calculator.java>
package com.itwill.exception06;
public class Calculator {
public int divide(int x, int y) throws Exception {
if (y != 0) {
return x / y;
}
throw new Exception("y는 0이 될 수 없음.");
}
}
2. 예외 클래스
JVM은 프로그램을 실행하는 도중에 예외가 발생하면 해당 예외 클래스로 객체를 생성하고 예외 처리 코드에서 객체를 이용할 수 있도록 해준다.
<ExceptionMain03.java>
/*
* 예외 클래스들의 상속 관계:
* Object
* |__ Throwable
* |__ Exception
* |__ RuntimeException
* |__ ArithmeticException, NumberFormatException,NullPointerException, ...
* catch 블록이 여러개인 경우, 하위 타입의 예외를 먼저 catch하고,
* 상위 타입의 예외를 나중에 catch 해야 함.
*/
public class ExceptionMain04 {
public static void main(String[] args) {
try {
} catch (ArithmeticException e) {
} catch (Exception e) {
// 다형성: SuperType car = new SubType();
// Exception 클래스를 상속하는 모든 종류의 예외를 잡을 수 있음.
}
// finally: 예외 상황 발생 여부와 상관 없이 항상 실행되는 블록.
// try 또는 catch 블록에 return 문장이 있어도,
// finally 블록이 실행된 후에 return 문장이 실행됨.
try {
int x = 100;
int y = 0;
System.out.println("몫 = " + (x / y));
System.out.println("end try");
} catch (Exception e) {
System.out.println(e.getMessage());
System.out.println("end catch");
return; // main 메서드 종료
} finally {
System.out.println("언제 출력될까요?");
}
System.out.println("end main");
}
}