오류(error)와 예외(exception)
소스코드를 작성할 때 문법상 오류가 날 경우 컴파일 자체가 되지 않으며 에러를 발생시킵니다. 문법에 맞지 않은 코드를 컴파일하려고 하면 컴파일러는 문법 오류(syntax error)를 발생시킵니다.
또한 문법상 오류는 없지만 프로그램이 실행되면서 발생하는 오류가 있습니다.
이와 같이 컴퓨터에서 시스템이 동작하면서 예상치 못한 사태가 발생하여 프로그램이 영향받는 것을 오류와 예외로 구분할 수 있습니다.
오류(error)는 시스템에서 프로그램에 문제를 발생시키며 실행 중인 프로그램을 종료시킵니다.
이러한 오류는 예측하여 처리할 수 없는 것이 대부분입니다.
하지만 예외(exception)는 오류와 마찬가지로 프로그램을 비정상적으로 종료시키지만 발생할 수 있는 상황을 미리 예측하여 처리할 수 있습니다.
따라서 개발자는 예외 처리(exception handling)를 통해 프로그램의 비정상적인 종료를 방지할 수 있습니다.
요약
exception : 코드에서 발생하며 예측, 처리 가능
- (checked exception) : 컴파일 단계에서 확인. 반드시 예외 처리 필수
- RuntimeException : 런타임 단계에서 확인. 개발자의 부주의로 발생
error : jvm에서 발생 (우리가 건드릴 수 없다)
Exception의 구조
자주 사용되는 예외 클래스
클래스 | 설명 |
ClassCastException | 수행할 수 없는 타입 변환이 진행될 경우 |
ArrayIndexOutOfBoundsException | 배열에 잘못된 인덱스를 사용하여 접근할 경우 |
NullPointerException | null 객체의 인스턴스 메소드를 호출하는 등의 경우 |
ArithmeticException | 산술 연산에서 정수를 0으로 나누는 등 연산을 수행할 수 없는 경우 |
try{
// 예외가 발생할 수 있는 명령문들
} catch(발생하면 잡아줄 예외) {
// 예외가 발생했을 때 명령;
} finally {
// 정상 종료 or 예외 발생 상관없이 무조건 실행되어야 하는 명령;
}
예외 처리인 try / catch / finally문의 형태입니다.
try 영역에 예외가 발생할 수 있는 명령문을 작성하며 catch 영역에 예외가 발생했을 때의 명령을 작성합니다.
또 finally 영역에는 정상 종료나 예외 발생에 상관없이 무조건 실행하는 명령을 입력합니다.
예외 처리의 순서
1. try 블록에 도달한 프로그램의 제어는 try 블록 내의 코드를 실행합니다.
이때 만약 예외가 발생(throw) 하지 않고, finally 블록이 존재하면 프로그램의 제어는 바로 finally 블록으로 이동합니다.
2. try 블록에서 예외가 발생하면 catch 핸들러는 다음과 같은 순서로 적절한 catch 블록을 찾게 됩니다.
2-1. 스택에서 try 블록과 가장 가까운 catch 블록부터 차례대로 검사합니다.
2-2. 만약 적절한 catch 블록을 찾지 못하면, 바로 다음 바깥쪽 try 블록 다음에 위치한 catch 블록을 차례대로 검사합니다.
2-3. 이러한 과정을 가장 바깥쪽 try 블록까지 계속 검사하게 됩니다.
2-4. 그래도 적절한 catch 블록을 찾지 못하면, 예외는 처리되지 못합니다.
3. 만약 적절한 catch 블록을 찾게 되면, throw 문의 피연산자는 예외 객체의 형식 매개변수로 전달됩니다.
4. 모든 예외 처리가 끝나면 프로그램의 제어는 finally 블록으로 이동합니다.
5. finally 블록이 모두 처리되면, 프로그램의 제어는 예외 처리문 바로 다음으로 이동합니다.
package com.test01;
import java.util.InputMismatchException;
import java.util.Scanner;
public class MTest {
public static void main(String[] args) {
MTest cacul = new MTest();
System.out.println(cacul.calculation());
// 10, 0 -> java.lang.ArithmeticException: / by zero
// a -> java.util.InputMismatchException
}
public int calculation() {
int res = 0;
while(true) {
try {
res = inputNum() / inputNum();
break;
} catch(InputMismatchException e) {
//e.printStackTrace(); //무슨 에러인지 보여줌
System.out.println("잘못 입력하셨습니다. 숫자만 입력해주세요.");
} catch(ArithmeticException e) {
System.out.println("0으로는 나눌수 없습니다. 다시 입력해주세요.");
} finally {
System.out.println("계산 완료");
}
//System.out.println(res);
}
return res;
}
public static int inputNum() {
int n = 0;
System.out.println("숫자만 입력하세요 : ");
Scanner sc = new Scanner(System.in);
n = sc.nextInt();
return n;
}
}
위의 코드는 2개의 숫자를 입력받아 첫 번째 입력 숫자를 두 번째 입력 숫자로 나누는 코드입니다.
try {
res = inputNum() / inputNum();
break;
} catch(InputMismatchException e) {
//e.printStackTrace(); //무슨 에러인지 보여줌
System.out.println("잘못 입력하셨습니다. 숫자만 입력해주세요.");
} catch(ArithmeticException e) {
System.out.println("0으로는 나눌수 없습니다. 다시 입력해주세요.");
} finally {
System.out.println("계산 완료");
}
try / catch / finally문을 보겠습니다.
try영역에서 입력받은 두 숫자를 나누는 명령을 입력하였습니다.
나눌 때 발생할 수 있는 문제는 0으로 나누었을 때와 숫자가 아닌 문자를 입력했을 때 발생할 것이라 예상할 수 있습니다.
따라서 해당 오류를 예상하여 방지할 수 있도록 할 수 있습니다.
또한 catch영역에 e.printStackTrace(); 를 입력하게 되면 컴파일시 무슨 에러가 발생했는지 콘솔창에 보여줍니다.
또한 throw 키워드를 이용하여 예외를 발생시킬 수 있습니다.
MTest.java
package com.test02;
import java.util.InputMismatchException;
import java.util.Scanner;
public class MTest {
public static void main(String[] args) {
int a = 0;
try {
System.out.println("숫자로 입력해 주세요.");
Scanner sc = new Scanner(System.in);
a = sc.nextInt();
int result = 1 / a;
if ( a == 100) {
throw new MyException();
}
if ( a == 666) {
throw new InputMismatchException();
}
} catch(InputMismatchException e) {
System.out.println("문자와 666이외의 숫자를 입력해주세요.");
} catch(MyException e) {
e.printStackTrace();
System.out.println("100이외의 숫자를 입력해주세요.");
} catch(Exception e) {
System.out.println("예외가 발생했습니다.");
}
System.out.println(a);
}
}
MyException.java
package com.test02;
public class MyException extends Exception {
public MyException() {
this("내가 만든 예외");
}
public MyException(String message) {
super(message);
}
}
위의 코드는 정수를 나눌 수 있는 숫자를 입력받아 나눌 수 없으면 예외를 발생시키는 코드입니다.
100을 입력하게 되면 예외가 발생하고 666을 입력하면 다른 숫자를 입력하라는 예외가 발생합니다.
throws 키워드의 경우 해당 메소드 내부에서 발생할 수 있는 예외를, 메소드 호출하는 곳으로 위임하는 역할을 합니다.
private static void trycatch throws IOException{}
이처럼 메소드에 사용되며 주로 자동완성으로 사용하곤 합니다.
'Java 관련 > Java' 카테고리의 다른 글
[Java] 쓰레드(Thread) (0) | 2021.11.20 |
---|---|
[Java] 입출력(IO - InputOutput) (0) | 2021.11.19 |
[Java] Comparable & Comparator (0) | 2021.11.17 |
[Java] 이터레이터(iterator) (0) | 2021.11.16 |
[Java] Map Collection(맵) (0) | 2021.11.15 |