개발지식 먹는 하마 님의 블로그
Java - 예외 처리 본문
❓ 예외(Exception)
프로그램 중 발생하는 비정상적인 상황
파일을 읽으라고 했는데 파일이 존재하지 않거나,
어떤 수를 0으로 나누려는 등의 비정상적인 상황에서 예외가 발생한다.
예외 처리는 if와 else로도 처리가 가능하지만,
자바가 보유한 예외 처리 기능을 사용하는 편이 보다 명확하고 바람직한 프로그래밍 구조를 이룰 수 있다.
📌 Java의 예외 구조
Jave는 오류와 예외로 나뉘고,
예외 안에서 Unchecked Exception과 Checked Exception으로 나뉜다.
✅ 예외와 오류의 차이
예외와 오류의 차이는 다음과 같다.
구분 | 예외 Exception | 오류 Error |
정의 | 프로그램 실행 중 발생하는 예외적인 상황 | 시스템 레벨에서 발생하는 복구가 불가능한 문제 |
복구 가능 여부 | 적절한 처리 후 정상적인 실행 가능 | 복구가 어려움 |
발생 시 프로그램 | 예외가 발생해도 프로그램이 종료되지 않음 | 프로그램이 종료됨 |
예시 | 잘못된 입력, 리소스 부족 등 | 메모리 부족, JVM 내부 문제 등 |
✅ Unchecked Exception과 Checked Exception의 차이
예외 | Unchecked Exception | Checked Exception |
예외 처리 여부 | 강제 X | 강제 |
예외 발생 시점 | 실행 중 예외 발생 | 컴파일에서 예외 검사 |
구분 | 개발자의 실수로 주로 발생 | 외부 환경 문제 (파일, 네트워크 등) |
둘의 가장 큰 차이는 예외 처리의 강제성 여부이다.
Unchecked Exception은 이에 해당하는 Runtime Exception의 이름과 같이 런타임 중에 발생하는 예외이기 때문에
프로그램을 실행하기 전까지는 여기서 예외가 발생하는지 아닌지를 알 수 없다.
반면, Checked Exception은 런타임 전인 컴파일 단계에서 예외가 발생하여 프로그램이 종료될 수 있다.
따라서 반드시 catch로 처리하도록 해 안정성을 보장해 주는 것이다.
Unchecked Exception은 사전 검사로 예방이 가능하기 때문에 굳이 예외처리를 강제하지 않는다.
오히려 이를 try-catch를 사용해 해결하려고 하면 코드가 불필요하게 복잡해질 수 있다.
📌 예외 처리 방법
☑️ try - catch
Java의 기본적인 예외 처리기이다.
try {
//코드 실행
throw new Exception("오류"); //오류 던지기
}
catch(ExceptionType e) {
//try문 실행 중 발생하는 오류를 처리
}
//다음 코드
- 비정상적인 오류가 발생한다고 프로그램이 종료되지 않는다.
- try 또는 catch 문을 실행한 후, try-catch 밑의 문장도 실행된다.
- catch는 해당 catch와 연결된 try문 내의 예외만 처리한다.
try {
//코드 실행
throw new Exception("오류"); //오류 던지기
}
try {
//코드 실행
throw new Exception("오류"); //오류 던지기
}
catch(ExceptionType e) {
//try문 실행 중 발생하는 오류를 처리
}
두 개의 try문이 있고 throw하는 예외가 동일하다고 할 때,
맨 밑의 catch문이 두 try문의 예외를 모두 처리되는 것이 아니다.
각 try문은 각자의 예외만 잡아서 처리한다.
따라서, 위의 예시에서 첫번째 try문은 본인만의 catch 블록이 필요하다.
🖍️ 처리해야 할 예외가 여러 개일 때
서로 다른 예외를 처리하기 위해 여러 개의 catch문을 사용할 수 있다.
- switch문처럼 먼저 선언된 예외 타입부터 검사한다.
- 따라서, 구체적인 예외를 먼저 선언하고 Exception과 같은 일반적인 예외를 나중에 선언한다.
try {
//오류 던지기
}
catch(FileNotFoundException e){
//파일을 찾을 수 없다는 구체적인 예외
}
catch(IOException e){
//그보다 더 넓은 범위의 일반적인 예외(혹은 부모)
}
☑️ throw
특정 상황에서 예외를 처리하고 싶을 때, 이를 던진다고 한다.
🖍️ 예외를 던지는 2가지 방법
☝️ 오류가 발생할 수 있는 구문을 try문 안에 선언한다.
✌️ 예외가 발생한 메소드가 다른 메서드에게 예외의 처리를 떠넘긴다.
public class TestDemo(){
public static char readOneChar() throws IOException, ExceptionType2 (){
//사용자의 입력을 받는 함수
//예외 발생 시, main에 예외를 던짐
return (char)System.in.read();
}
public static void main(String[] args){
try {
readOneChar();
}
catch {
//readOneChar()에서 넘겨받은 예외를 처리
}
}
}
메서드 헤딩에 예외 선언을 할 때는 여러 개의 예외를 처리할 수도 있기 때문에 throws를 사용한다.
throw 뒤에 꼭 s가 붙어야 하고 ', '를 통해 여러 개의 예외를 선언할 수 있다.
물론 예외를 넘겨 받은 메서드는 다시 예외를 선언하여 자신을 호출한 메서드에게로 예외를 떠넘길 수 있다.
궁극적으로는 catch 블록으로 예외를 잡는 메서드가 반드시 있어야 한다.
throw로 던진 오류는 반드시 catch 잡아서 처리해야 한다.
catch 블록으로 오류를 잡아 처리하지 않으면 오류가 발생하며 프로그램의 실행이 강제 종료된다.
❓❗ catch로 다 잡아서 처리해야 한다더만 안 써도 문제없는데?
while (true) {
int choice = 0;
try {
throw new InputMismatchException();
}
//없어도 오류가 발생하지 않음
catch (InputMismatchException e) {
System.out.println("제대로 된 번호를 입력해주세요.\n");
sc.nextLine();
continue;
}
}
위의 예시에서 InputMismatchException()을 처리하는 catch문을 제거해도 오류 없이 프로그램이 계속 동작한다.
이유가 뭘까?
바로 InputMismatchException의 상위 개념이 RuntimeException이기 때문이다.
RuntimeException가 catch 블록 없이도 정상 실행되는 이유
- RuntimeException은 Unchecked Exception의 대표적인 클래스이다.
따라서, 예외 처리가 강제되지 않는다. - 실제로 예외가 발생하지 않는 이상 catch 블록이 없어도 정상적으로 동작한다.
다만, 예외가 발생했을 때 catch 블록으로 처리하지 않는다면,
이를 무시하고 계속 진행하거나 프로그램이 종료될 수 있다.
멀티 쓰레드를 사용하는 경우,
그 스레드가 메인이라면 프로그램 전체가 종료될 수 있고
아니라면 해당 스레드만 종료될 수 있다.
catch문 사용이 필수는 아니지만 예외 발생 시,
해당 예외를 확인하고 프로그램 흐름에 영향을 주지 않도록 처리해 주기 위해
적절히 catch문을 사용해주어야 한다!
☑️ 이건 무조건 처리해야 해 finally
- 생략이 가능하다.
- 예외 발생 여부와 관계없이 마지막에 항상 finally 블록의 내용이 실행된다.
- 일반적으로 반드시 마무리되어야 할 내용을 포함시킨다.
'Java' 카테고리의 다른 글
Java - 배열과 리스트 (1) | 2025.02.06 |
---|---|
Java - 인터페이스 (0) | 2025.02.05 |
Java - 오버로딩, 오버라이딩 (1) | 2025.02.04 |
Java - 상속 (1) | 2025.02.03 |
구글 Java 스타일 가이드 (1) | 2025.01.21 |