만약 Java 코드에 오류가 있으면, 프로그램은 실행되지 않고 종료된다.
public class ExceptionExam {
public static void main(String[] args) {
int i = 5;
int j = 0;
int k = i / j;
System.out.println(k);
System.out.println(main 종료!!);
}
}
예를 들어, 위와 같은 코드를 실행시키면 ArithmeticException
오류가 발생하며 프로그램이 종료된다.
Java에서는 정수를 0으로 나눌 수 없기 때문이다.
그런데 예외처리를 통해서 오류가 발생하더라도 이를 무시하고 프로그램을 실행 시킬 수 있다.
그 방법은 try-catch-finally를 사용하는 것이다.
기본 형태는 아래와 같다. 여기서 finally는 생략이 가능하며, 필수가 아니다.
try{
/* 예외가 발생할 가능성이 있는 블록 */
// 수행할 코드
} catch(예외클래스 변수명){
/* try블록에서 오류 발생 시 catch 블록으로 이동 */
/* 발생 오류와, 예외 클래스 변수명에 지정한 오류가 일치해야 작동 */
} finally {
/* 오류가 발생했든, 안했든 무조건 실행 */
...
}
try{} 블록에는 오류가 발생할 가능성이 있는 코드를 입력하고,
catch의 () 안에는 발생할 오류클래스타입과 변수명
을 적는다.(ex. ArithmeticException e
)
오류클래스는 ","
를 사용하여 여러 개를 지정할 수도 있다.
그리고 catch의 {} 블록에는, try{}에서 정말 오류가 발생한다면 실행할 코드를 입력한다.
finally{}는 오류가 발생했든, 하지 않든 무조건 실행할 코드가 있다면 입력한다.
여기서 주의할 점은 try-catch를 통해 예외처리를 한다고 하더라도,
무조건 catch 블록이 작동하는 것은 아니다.
발생한 오류가 catch()에 입력한 예외 클래스 변수명과 다를 경우에는
catch 블록이 작동하지 않기 때문이다.
이 때, 필요 시 finally를 통해 오류 여부와 관계없이 무조건 실행할 코드를 작성할 수 있다.
public class ExceptionExam {
public static void main(String[] args) {
int i = 5;
int j = 0;
try{
int k = i / j;
System.out.println(k);
}catch(ArithmeticException e){
System.out.println("정수는 0으로 나눌 수 없습니다. : " + e.toString());
}finally {
System.out.println("오류와 관계없이 실행되는 문장입니다.");
}
}
}
위 코드는 맨 앞에서 예시로 들었던 오류 코드에 try-catch-finally를 적용한 것이다.
catch{}에 발생한 오류 클래스타입을 적고 변수명을 e
로 지정했다.
이제는 프로그램이 종료되는 대신 "정수는 0으로 나눌 수 없습니다." 문장이 출력된다.
그리고 e.toString() 을 통해서 예외 정보를 출력할 수 있다.
이후 finally{} 도 실행된다.
모든 예외는 Exception 클래스를 상속받으므로, catch() 괄호 안에
Exception 타입을 지정한다면 하나의 블록에서 모든 오류를 처리할 수 있다.
메소드를 정의할 때에도 throws 를 사용해 예외를 지정하면 오류가 발생했을 때,
해당 메소드 정의한 쪽에서 직접 예외처리를 하는 게 아니라
메소드를 호출하는 쪽에서 예외를 처리하도록 떠넘길 수 있다.
예를 들어 아래와 같은 메소드가 있고, throws를 사용했다.
*여기서 예외클래스의 변수명은 지정하지 않아도 된다.
public static int divide(int i, int j) throws Exception {
int k = i / j;
return k;
}
아래처럼 divide() 메소드를 호출하는 쪽에서 try-catch문을 사용해
예외를 처리해야한다.
public static void main(String[] args) {
int i = 10;
int j = 0;
try{
int k = divide(i, j);
System.out.println(k);
} catch(ArithmeticException e){
System.out.println("정수는 0으로 나눌 수 없습니다.");
}
}
throws가 아니라, throw 는 인위적으로 Exception을 발생시키고 싶을 때 사용한다.
public static int divide(int i, int j) throws Exception {
int k = i / j;
return k;
}
애초에 정수를 0으로 나누어 오류가 날 코드라면 아래처럼 if 문을 통해 방지할 수 있을 것이다.
public static int divide(int i, int j){
if(j == 0){
System.out.println("2번째 매개변수는 0보다 커야 합니다.");
return 0;
}
int k = i / j;
return k;
}
그런데 return type이 int 인 관계로 어쩔 수 없이 숫자를 리턴해야하는데,
오류인 경우에는 숫자를 리턴하고 싶지 않다.
이럴 때 throw를 사용해 int가 0이면 오류를 발생시키는 것이다.
public static int divide(int i, int j) throws IllegalArgumentException{
if(j == 0){
throw new IllegalArgumentException("정수는 0으로 나눌 수 없습니다.");
}
int k = i / j;
return k;
}
그리고 그 발생하는 오류는 throws를 통해 메소드 호출 시 해결하도록 구현할 수 있다.
public static void main(String[] args) {
int i = 10;
int j = 0;
try{
int k = divide(i, j);
System.out.println(k);
}catch(IllegalArgumentException e){
System.out.println("0으로 나눌 수 없습니다.");
}
}