[JAVA] 프로그램 오류 및 예외 처리
프로그램 오류
프로그램 오류가 발생할 경우 프로그램 문제를 야기시킨다.
그러면 버그가 발생하거나 프로그램이 강제종료되는 경우가 있다.
프로그래밍에서 오류가 발생하는 시점 3가지가 있다.
- 컴파일 에러(Compilation error) : 컴파일 시 발생하는 오류
- 런타임 에러(Runtime error) : 실행 시 발생하는 오류
- 논리적 에러(Logical error) : 작성 의도와 다르게 동작
컴파일 에러(Compilation error)
컴파일러는 구문체크, 번역, 최적화를 계산한다.
자주 발생하는 컴파일 에러 중 하나는 구문 오류(syntax error)이다.
컴파일 에러는 IDE(인텔리제이, 이클립스 등)에서 자동으로 컴파일 체크를 해주기 때문에 금방 오류를 확인할 수 있다.
런타임 에러(Runtime error)
에러와 예외
- 에러(error) : 프로그램 코드에 의해 수습될 수 없는 심각한 오류
예외(exception) : 프로그램 코드에 의해 수습될 수 있는 다소 미약한 오류
- 예외처리 정의와 목적
- 정의 : 프로그램 실행 시 발생할 수 있는 예외의 발생에 대비한 코드를 작성하는 것
- 프로그램 비정상 종료를 막고, 정상적인 실행상태를 유지하는 것
논리적 에러(Logical error)
일명 ‘버그’다. 게임을 해봤던 사람들이라면 한 번쯤은 겪었을 것이다.
프로그램 실행은 잘 되지만 예기치 못한 문제가 발생한다.
작업이 생각한 의도와 다르게 수행된 경우이다.
이 경우 프로그램은 문제 없는 것으로 인식하기 때문에 개발자가 미리 확인을 하는 것이 좋다.
자바의 예외처리
프로그램 오류가 발생할 경우 예기치 못한 종료가 발생할 수 있지만 일부 경우 예외처리로 방지할 수 있다.
try-catch문
try-catch
문은 아래 코드처럼 작성할 수 있다.
catch
괄호 안에 Exception
을 사용하면 모든 예외를 처리할 수 있다.
1
2
3
4
5
6
7
try {
// 예외가 발생할 수 있는 문장
} catch (Exception1 e1) {
// Exception1에서 에러가 발생했을 경우, 처리해야 될 문장
} catch {
// 에러가 발생했을 경우, 처리해야 될 문장
}
try-catch문은 문장이 하나더라도 괄호 생략이 불가능하다.
try
블록에서 예외가 발생하였을 경우- 발생한 예외와 일치하는
catch
문이 있는지 확인한다. - 일치하는
catch
문이 있다면 수행하고 해당try-catch
문을 빠져나와 다음 문장을 수행한다. - 만약 일치하는
catch
문이 없다면 예외 처리되지 못한다.
- 발생한 예외와 일치하는
try
블록에서 예외가 발생하지 않은 경우catch
문은 생략하고 다음 문장을 이어서 수행한다.
1
2
3
4
5
6
7
8
9
10
11
12
public class Main {
public static void main(String[] args) {
try {
System.out.println("3");
// 강제적으로 예외 발생
throw new ArithmeticException();
System.out.println("4");
} catch (ArithmeticException e) {
System.out.println("오류발생");
}
}
}
위 코드에 강제적으로 예외를 발생시켜 보았다.
코드를 실행하면 “3”이 출력되고 예외가 발생하여 “4” 출력은 넘어가게 된다.
catch문에서 발생한 예외와 맞는 예외 값을 찾는다.
그러므로 “3” 출력 후 “오류발생”이라는 문자열을 출력하게 된다.
멀티 catch블록
멀티 catch블록은 여러 catch블록을 '|'
기호를 이용하여, 내용이 같은 catch블록을 하나로 합친 것이다.
1
2
3
4
5
6
7
try {
...
} catch (Exception1 e) {
System.out.println(e);
} catch (Exception2 e) {
System.out.println(e);
}
위 코드처럼 Exception1
과 Exception2
의 예외 발생처리가 같을 때 멀티 catch 블록을 사용하면 중복된 코드를 줄일 수 있다.
1
2
3
4
5
6
// 멀티 catch 블록 사용
try {
...
} catch (Exception1 | Exception2 e) {
System.out.println(e);
}
- 하지만 멀티 catch 블록에 사용될 클래스가 부모 자식 관계일 경우 컴파일 에러가 난다.
예외 발생시키기
연산자 new를 이용해 발생시키려는 예외 클래스의 객체를 만들어 throw 키워드를 사용해 예외를 발생시킬 수 있다.
1
2
3
4
5
6
7
8
9
10
11
12
13
public class Main {
public static void main(String[] args) {
try {
System.out.println("Hi");
throw new ArithmeticException("111");
} catch (ArithmeticException e) {
System.out.println("오류코드 : " + e);
}
}
}
> Hi
> 오류코드 : 111
printStackTrace()와 getMessage()
- printStackTrace()
- 예외발생 당시 호출스택에 있던 메소드의 정보와 예외 메세지를 출력
- getMessage()
- 발생한 예외클래스의 인스턴스에 저장된 메세지를 얻을 수 있다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
public class Main {
public static void main(String[] args) {
try {
System.out.println("3");
System.out.println("4");
throw new ArithmeticException("오류");
} catch (ArithmeticException e) {
System.out.println(e.getMessage());
e.printStackTrace();
}
}
}
> 3
> 4
> 오류
> java.lang.ArithmeticException: 오류
at Main.main(Main.java:6)
- 3과 4는 정상적으로 출력된다.
- 이후 예외발생으로 해당 예외발생에 맞는 catch문을 수행하게 된다.
- 예외발생 메세지로 “오류”를 작성하여 getMessage()로
"오류"
라는 문자열이 출력하게 된다. - 이후
printStackTrace()
로 참조변수를 통해 생성된 인스턴스에 접근하여 예외발생 내용을 화면에 출력이 되었다.
Checked Exception & Unchecked Exception
자바의 예외는 컴파일 에러, 런타임 에러, 논리적 에러가 있다.
근데 예외 종류에도 Checked Exception과 Unchecked Exception이 있다.
간단히 아래 표로 이해할 수 있다.
Checked Exception | Unchecked Exception | |
---|---|---|
설명 | 컴파일 예외클래스들을 가리키는 것 | 런타임 예외클래스들을 가리키는 것 |
처리 여부 | 반드시 예외 처리 | 명시적 처리 안 해도 됨 |
메소드 예외 선언
- 현재까지는 예외 처리 방법이 2가지(
try-catch
,예외 선언
)가 있었다. - 메소드 호출 시 발생가능한 예외를 호출하는 곳으로 알리는 것
- throw : 예외 발생시키는 키워드
- throws : 메소드 예외 선언 시 사용
finally블록
try-catch
에 이어 예외 발생여부 관계없이 수행되어야 하는 코드를 작성할 수 있다.
finally
블록은 try-catch
맨 마지막에 위치해야 한다.
1
2
3
4
5
6
7
try {
// 예외 처리가 발생할 수 있는 코드
} catch () {
// 해당 예외 발생 시 처리해 줄 코드
} finally () {
// 예외 발생 여부 상관없이 수행되어야되는 코드
}
사용자 정의 예외 만들기
직접 예외 클래스를 정의할 수 있다.
부모는 Exception, RuntimeException 중에 선택해야 한다.
1
2
3
4
5
6
class MyException extends Exception {
// 사용자가 발생시키는 예외
MyException(String msg){ // 문자열을 매개변수로 받는 생성자
super(msg); // 부모 Exception 클래스의 생성자 호출
}
}
연결된 예외
- 예외를 다른 예외로 감싸는 것
Checked Exception를 Unchecked Exception로 변경
- 필수처리를 선택처리로 변경할 때 사용된다.
- 선택처리로 변경하게 된다면 예외처리를 강제로 할 필요가 없게 할 수 있다.
1
2
3
4
5
6
7
8
9
10
11
12
13
class SpaceException extends Exception {
SpaceException (String msg) {
super(msg);
}
}
static void startInstall() throws SpaceException, MemoryException {
if(!enoughSpace())
throw new SpaceException("공간 부족");
if(!enoughMemory())
// Checked 예외를 Unchecked 예외인 RuntimeException으로 감싸 Unchecked 예외로 변경한다.
throw new RuntimeException(new MemoryException("메모리 부족"));
}