프로그램의 오류
컴파일 에러 : 컴파일 시에 발생하는 에러
System.out.println("자바")
위의 코드처럼 뒤에
;을 붙이지 않으면 나타나는 에러가 대표적인 컴파일 에러이다.
런타임 에러 : 실행 시에 발생하는 에러
int[] arr = {1,2,3,4};
System.out.println(arr[10]);
위의 코드는 코드상에선 오류가 없지만 배열의 10번째 방이 없기 때문에 실행시에 에러가 발생하고 이러한 에러를 런타임 에러라고 한다.
논리적 에러 : 실행은 되지만, 의도와 다르게 동작하는 것
int[] arr = {1,2,3,4};
System.out.println("first data : " + arr[1]);
위의 코드는 컴파일 에러나 런타임 에러가 발생하지 않지만, 코드 작성자의 실수로 인해 의도한 first data를 배열의 두번째 값으로 출력했다. 이러한 에러를 논리적 에러라고 한다.
예외처리 try ~ catch ~ finally 문
try ~ catch ~ finally 문의 구조
try{
예외가 발생할 수 있는 문장1
예외가 발생할 수 있는 문장2
...
} catch(예외클래스명 객체명) {
해당 예외 발생시 수행할 문장
...
catch 블럭은 여러개 쓸 수 있다.
} finally {
예외 발생 유무에 상관없이 무조건 실행할 문장
finally 블럭은 생략 가능하다.
}
public class Main{
public static void main(String[] args) {
try {
Scanner sc = new Scanner(System.in);
System.out.print("아무 숫자나 입력하세요 : ");
int a = sc.nextInt();
} catch (Exception e) {
System.out.println("숫자만 입력해주세요.");
} finally {
System.out.println("프로그램 종료.");
}
}
}
위의 코드를 보자. try문 안에서 먼저 사용자에게 숫자값을 하나 입력받는다. 이 때 사용자는 숫자가 아닌 다른 값을 입력할 수 있기 때문에 그 경우에 대한 예외 처리를 해주어야 한다. 따라서 숫자가 아닌 다른 값을 입력하는 예외 발생시 catch문으로 들어가 "숫자만 입력해주세요"가 출력되는 것이다. 그리고 finally 문 안에 있는 것은 예외 가 발생 유무에 상관없이 무조건 실행한다.
public class Main{
public static void main(String[] args) {
try {
Scanner sc = new Scanner(System.in);
System.out.print("0이 아닌 아무 숫자나 입력하세요 : ");
int a = sc.nextInt();
System.out.println(5/a);
} catch (ArithmeticException e) {
System.out.println("'0이 아닌' 숫자를 입력하세요.");
} catch (InputMismatchException e) {
System.out.println("0이 아닌 '숫자'을 입력해주세요");
}
}
}
위의 코드를 보자. 숫자값을 하나 입력받아 5를 그 숫자로 나눈 값을 출력하려고 한다. 이 때 생각할 수 있는 오류는 두 가지 이다. 첫 번째로 입력받은 숫자가 0이거나, 두 번째로 입력받은 값이 숫자가 아니거나 이다. 따라서 0으로 나누었을 때 발생하는 예외인
ArithmeticException과sc.nextINT()에 숫자가 아닌 다른 값을 입력했을 때 발생하는 예외인InputMismatchException클래스들을 이용해서 catch문을 두개 사용할 수 있다.
Exception 클래스
public class Main{
public static void main(String[] args) {
try {
Scanner sc = new Scanner(System.in);
System.out.print("0이 아닌 아무 숫자나 입력하세요 : ");
int a = sc.nextInt();
System.out.println(5/a);
} catch (Exception e) {
System.out.println("0이 아닌 숫자를 입력하세요.");
}
}
}
위의 코드를 보자. 여기서도 생각해볼 수 있는 예외는 0을 넣었을 때와 숫자가 아닌 값을 넣을 때 두가지이다. 그때의 예외 클래스인
ArithmeticException클래스와InputMismatchException클래스 모두Exception클래스를 상속받고있기 때문에Exception클래스 하나만을 써서 모든 예외를 잡아낼 수 있다.하지만 사용자의 입장에서, 발생할 수 있는 예외의 종류를 세분화해 각 케이스마다 적절한 설명을 출력해주는 것이 더 편하다. 따라서 생각해볼 수 있는 각각의 예외를 모두 잡아 적절한 설명문을 출력해준 후 마지막 catch 문에서 생각하지 못했던 예외를 잡기 위해
Exception클래스를 써주는게 좋다.
예외 발생시키기
키워드 throw 를 사용해서 고의로 예외를 발생시킬 수 있다.
public class Main{
public static void main(String[] args) {
try {
Exception e = new Exception("고의로 예외 발생.");
throw e;
// throw new Exception("고의로 예외 발생."); 한줄로도 가능
} catch (Exception e) {
System.out.println("에러가 발생했습니다 : " + e.getMessage());
}
}
}
메서드에 예외 선언하기
throws 키워드를 사용하며, 메서드 선언부 내부에서 발생하는 예외를 무시하고 호출한 곳으로 해당 예외를 떠넘기게 된다. 따라서 호출한 곳에서는 try~catch 문으로 예외를 잡아줘야한다.
public class Main{
public static void main(String[] args) {
try {
System.out.println(method(3));
} catch (Exception e) {
System.out.println("0으로 나눌 수 없습니다.");
}
}
static int method(int x) throws Exception {
int a = 0;
return x/a;
}
}
위의 코드를 보자. method 메서드에서 매개변수 x를 받아와 a로 나눈다. 그런데 a의 값이 0으로 초기화 되어 있으므로 예외가 발생할 것이다. 따라서
throws Exception으로 예외를 무시한다.그리고 main 메서드에서 method 메서드를 선언할 때
try~catch문으로 발생하는 예외를 잡아준다.