[Java] 33. 예외(Exception) 처리 하기
예외(Exception)란?
프로그램이 실행 중에 예상치 못한 문제가 발생하는 것을 말합니다.
예를 들어 배달 앱에서, 고객 주소가 비어 있으면 앱이 ‘어떻게 배달하지?’ 라며 멈출 수 있어요.
이런 상황이 바로 예외입니다.
그래서 자바는 '예외(Exception)'라는 기능을 제공해서,
개발자가 문제를 감지하고, 처리할 수 있게 도와줍니다.
예외가 발생하는 이유
예외는 마치 우리가 예상하지 못한 상황을 만났을 때처럼 작동합니다.
- 음식 주문 앱에서 고객이 주소를 입력하지 않음 → “배달할 곳이 없음!”
- 은행 앱에서 잔액이 0원인데 출금 요청 → “돈이 없는데 출금?”
자바에서 예외가 발생하는 대표적인 상황
상황 | 설명 | 발생하는 예외 |
0으로 나누기 | 수학적으로 불가능 | ArithmeticException |
배열 범위 벗어나기 | 없는 인덱스에 접근 | ArrayIndexOutOfBoundsException |
null 값 사용 | 존재하지 않는 객체에 접근 | NullPointerException |
파일이 없음 | 없는 파일을 열려고 함 | FileNotFoundException |
예시
0으로 나누기
public class Main {
public static void main(String[] args) {
int result = 10 / 0;
System.out.println("결과: " + result);
}
}
- 실행 결과 -
Exception in thread "main" java.lang.ArithmeticException: / by zero
➡️ 프로그램은 여기서 멈춰버립니다!
배열 인덱스 오류
int[] nums = {1, 2, 3};
System.out.println(nums[5]); // 존재하지 않는 인덱스
➡️ ArrayIndexOutOfBoundsException 발생!
예외는 우리가 예상하지 못한 일들이 벌어질 때 발생합니다.
자바는 이런 상황을 자동으로 감지해서 '예외'로 알려주고,
개발자가 처리할 수 있도록 도움을 줍니다.
하지만, 예외를 처리하지 않으면 프로그램은 그대로 멈추게 됩니다!
예외 종류
자바 예외는 두 가지로 나뉩니다!
구분 | Checked Exception | Unchecked Exception |
예외 처리 | 반드시 try-catch 또는 throws 필요 | 선택 사항 (처리 안 해도 컴파일됨) |
주로 언제? | 파일, DB, 네트워크 등 외부 자원 처리 | 개발 실수, 논리 오류 |
예시 | IOException, SQLException | NullPointerException, IllegalArgumentException |
- Checked Exception → "꼭 처리해!"
- Unchecked Exception → "필요하면 처리해!"
컴파일 전에 발생하는 예외 (Checked Exception)
import java.io.FileReader;
public class CheckedExample {
public static void main(String[] args) {
// FileReader는 Checked Exception을 반드시 처리해야 함
FileReader reader = new FileReader("hello.txt"); // 컴파일 에러 발생!
}
}
- FileReader는 파일을 읽을 때 파일이 없을 수 있음을 컴파일러가 감지합니다.
- 그래서 IOException을 반드시 try-catch로 감싸거나 throws로 넘겨야 합니다.
- 그렇지 않으면 컴파일 자체가 안 됩니다.
수정 예
import java.io.FileReader;
import java.io.IOException;
public class CheckedExample {
public static void main(String[] args) {
try {
FileReader reader = new FileReader("hello.txt");
} catch (IOException e) {
e.printStackTrace();
}
}
}
컴파일 후 실행 중에 발생하는 예외 (Unchecked Exception)
public class UncheckedExample {
public static void main(String[] args) {
String str = null;
System.out.println(str.length()); // 컴파일은 되지만, 실행 시 NullPointerException
}
}
- str은 null이지만, 컴파일러는 그걸 알 수 없기 때문에 컴파일은 통과합니다.
- 하지만 실행 도중 null.length()를 호출하게 되어 NullPointerException이 발생합니다.
예외처리 기본 문법
1) try-catch — 예외를 직접 처리하는 기본 구조
try {
// 문제가 생길 수 있는 코드
} catch (예외타입 변수명) {
// 문제가 생겼을 때 처리할 코드
}
예시 : 0으로 나누기
public class Main {
public static void main(String[] args) {
try {
int result = 10 / 0; // 문제 발생!
} catch (ArithmeticException e) {
System.out.println("0으로 나눌 수 없어요!");
}
}
}
- 출력 결과 -
0으로 나눌 수 없어요!
10 / 0은 수학적으로 불가능해서 ArithmeticException이 발생합니다.
하지만, catch 블록에서 예외를 잡아주기 때문에 프로그램이 멈추지 않아요!
2) throws — 예외를 호출한 곳에 "전가"하기
public void readFile() throws IOException {
// 파일을 읽는 코드
}
이 메서드는 IOException이 날 수 있기 때문에
직접 처리하지 않고 호출한 쪽에서 처리하라고 "던지는" 방식이에요.
→ 주로 Checked Exception을 처리할 때 사용합니다.
3) finally — 예외 발생 여부와 관계없이 무조건 실행
try {
System.out.println("파일 읽기 시도 중...");
} catch (Exception e) {
System.out.println("에러 발생!");
} finally {
System.out.println("무조건 실행: 파일 닫기 등 자원 정리");
}
에러가 나든 안 나든, finally 블록은 항상 실행됩니다.
파일 닫기, DB 연결 해제 같은 정리 작업에 자주 쓰입니다.
4) 여러 개의 예외를 처리하는 방법
try {
// 어떤 작업
} catch (IOException e) {
// 파일 관련 예외 처리
} catch (NumberFormatException e) {
// 숫자 변환 관련 예외 처리
}
// 또는 자바 7부터는 이렇게도 가능
catch (IOException | NumberFormatException e) {
// 여러 예외 한 번에 처리
}
대표적인 예외 예제
1) NullPointerException
➡ 아무것도 없는(null) 상태에서 무언가 하려고 할 때 발생
String text = null;
System.out.println(text.length()); // ❌ 오류!
- 예외 메시지 -
java.lang.NullPointerException
✅ 예방 팁: null 체크를 먼저 해주세요!
if (text != null) {
System.out.println(text.length());
}
2) ArrayIndexOutOfBoundsException
➡ 배열의 범위를 벗어난 인덱스에 접근할 때 발생
int[] nums = {1, 2, 3};
System.out.println(nums[5]); // ❌ 오류!
- 예외 메시지 -
java.lang.ArrayIndexOutOfBoundsException: Index 5 out of bounds for length 3
✅ 예방 팁: 항상 배열의 길이를 체크하세요.
if (index < nums.length) {
System.out.println(nums[index]);
}
3) NumberFormatException
➡ 문자열을 숫자로 바꿀 때 형식이 잘못되면 발생
String str = "abc";
int num = Integer.parseInt(str); // ❌ 오류!
- 예외 메시지 -
java.lang.NumberFormatException: For input string: "abc"
✅ 예방 팁: 숫자인지 먼저 확인하거나 try-catch로 감싸기
4) ArithmeticException
➡ 수학 연산이 잘못되었을 때 (ex. 0으로 나누기)
int result = 10 / 0; // ❌ 오류!
- 예외 메시지 -
java.lang.ArithmeticException: / by zero
✅ 예방 팁: 나누기 전에 0인지 확인하기
if (divisor != 0) {
int result = 10 / divisor;
}
5) FileNotFoundException
➡ 존재하지 않는 파일을 열려고 할 때 발생
FileReader reader = new FileReader("not_exist.txt");
- 예외 메시지 -
java.io.FileNotFoundException: not_exist.txt (No such file or directory)
✅ 예방 팁: 반드시 try-catch 또는 throws로 처리해야 함
try {
FileReader reader = new FileReader("not_exist.txt");
} catch (FileNotFoundException e) {
System.out.println("파일이 없습니다!");
}
실습 예제
실습 1: 예외를 try-catch로 잡아보자
public class Main {
public static void main(String[] args) {
try {
int result = 10 / 0;
System.out.println("결과: " + result);
} catch (ArithmeticException e) {
System.out.println("0으로 나눌 수 없습니다!");
}
System.out.println("프로그램이 멈추지 않았습니다.");
}
}
- 출력 결과 -
0으로 나눌 수 없습니다!
프로그램이 멈추지 않았습니다.
➡ 예외가 발생해도, 프로그램은 정상 흐름을 이어갈 수 있습니다.
실습 2: 배열 인덱스 예외
public class Main {
public static void main(String[] args) {
int[] nums = {1, 2, 3};
try {
System.out.println(nums[5]); // 존재하지 않는 인덱스
} catch (ArrayIndexOutOfBoundsException e) {
System.out.println("배열 인덱스를 잘못 사용했습니다.");
}
}
}
- 출력 결과 -
배열 인덱스를 잘못 사용했습니다.
➡ 배열은 항상 0부터 시작, 범위를 벗어나면 예외 발생합니다.
실습 3: finally는 언제나 실행된다
public class Main {
public static void main(String[] args) {
try {
System.out.println("파일 읽는 중...");
throw new RuntimeException("가짜 에러!");
} catch (RuntimeException e) {
System.out.println("예외 발생!");
} finally {
System.out.println("무조건 실행되는 finally 블록");
}
}
}
- 출력 결과 -
파일 읽는 중...
예외 발생!
무조건 실행되는 finally 블록
➡ 에러가 나든 말든, finally는 항상 실행됩니다. (자원 정리에 유용)
실습 4: throws로 예외를 넘겨보기
import java.io.*;
public class Main {
public static void main(String[] args) {
try {
readFile(); // 예외 발생 가능
} catch (IOException e) {
System.out.println("파일을 읽는 데 문제가 발생했습니다.");
}
}
public static void readFile() throws IOException {
FileReader reader = new FileReader("없는파일.txt");
reader.read();
}
}
- 출력 결과 -
파일을 읽는 데 문제가 발생했습니다.
➡ throws는 예외를 직접 처리하지 않고 위임하는 방식입니다.
요약 정리
- 예외는 프로그램을 멈추게 하지만, try-catch로 막을 수 있습니다.
- finally는 항상 실행되어 자원 정리에 좋습니다.
- throws는 예외를 호출한 쪽으로 넘기는 선언입니다.
- 예외 클래스 이름만 봐도 어떤 문제인지 알 수 있습니다.
읽어주셔서 감사합니다 😊