Java 예외(Exception) 처리 방법 (feat. throws, throw)
Java에서 예외(Exception)를 발생시키는 방법에 대해 알아보겠습니다. 예외 처리는 Java 프로그램이 실행 중 예상치 못한 오류가 발생했을 때 프로그램이 비정상적으로 종료되지 않고, 이를 처리할 수 있는 방법을 제공합니다. 예외는 주로 파일 접근 오류, 네트워크 오류, 숫자 계산 오류, 타입 변환 오류 등 다양한 상황에서 발생할 수 있으며, 이러한 상황을 개발자가 사전에 인지하고 예외 처리를 통해 프로그램의 안정성을 높일 수 있습니다.
### 1. 예외의 개념과 종류
Java의 예외는 `Throwable` 클래스를 기반으로 한 두 가지 큰 종류로 나뉩니다:
1. **Checked Exception (체크 예외)**
- 컴파일 타임에 반드시 예외 처리를 해야 하는 예외입니다. 컴파일러가 `try-catch` 블록 또는 `throws` 선언을 요구합니다.
- 대표적으로 `IOException`, `SQLException`, `ClassNotFoundException` 등이 있습니다.
2. **Unchecked Exception (언체크 예외)**
- 실행 시점에 발생하는 예외로, `RuntimeException` 클래스를 상속한 예외들입니다. 이 예외는 컴파일러가 예외 처리를 강제하지 않습니다.
- 대표적으로 `NullPointerException`, `ArrayIndexOutOfBoundsException`, `ArithmeticException` 등이 있습니다.
### 2. 예외 발생 시키기 (`throw` 키워드 사용법)
Java에서는 `throw` 키워드를 사용해 예외를 강제로 발생시킬 수 있습니다. `throw`는 특정 조건이 만족될 때 예외를 명시적으로 던질 때 사용되며, 발생시키려는 예외 객체를 지정해야 합니다.
```java
throw new Exception("예외 메시지");
```
예를 들어, 특정 값이 0일 때 `ArithmeticException`을 발생시키는 코드는 다음과 같습니다.
```java
public void divide(int a, int b) {
if (b == 0) {
throw new ArithmeticException("0으로 나눌 수 없습니다.");
}
System.out.println("결과: " + (a / b));
}
```
위의 코드에서 `b`가 0일 경우 `ArithmeticException` 예외가 발생합니다. 이와 같이 `throw` 키워드를 통해 실행 중 특정 조건에서 예외를 발생시킬 수 있습니다.
### 3. 사용자 정의 예외 클래스
Java에서는 `Exception` 클래스를 상속하여 사용자 정의 예외를 만들 수 있습니다. 사용자 정의 예외를 만들면 프로그램 로직에 맞춘 세부적인 예외 처리가 가능해집니다. 예를 들어, 은행 애플리케이션에서 출금할 금액이 잔고보다 많을 경우 발생시키는 `InsufficientFundsException` 예외를 작성해 보겠습니다.
#### 사용자 정의 예외 클래스 생성하기
```java
public class InsufficientFundsException extends Exception {
public InsufficientFundsException(String message) {
super(message);
}
}
```
#### 사용자 정의 예외 발생시키기
```java
public class BankAccount {
private double balance;
public BankAccount(double balance) {
this.balance = balance;
}
public void withdraw(double amount) throws InsufficientFundsException {
if (amount > balance) {
throw new InsufficientFundsException("잔고 부족: 현재 잔고는 " + balance + "입니다.");
}
balance -= amount;
System.out.println("출금 완료: 남은 잔고는 " + balance + "입니다.");
}
}
```
위의 예제에서는 `withdraw` 메소드가 `InsufficientFundsException` 예외를 발생시킵니다. 사용자는 잔고가 부족할 경우에만 예외가 발생하므로, 프로그램 내에서 이를 처리할 수 있습니다.
### 4. `try-catch`로 예외 처리하기
`throw` 키워드로 예외를 발생시키면, 예외를 처리하지 않는 한 프로그램은 비정상 종료됩니다. 이를 방지하려면 `try-catch` 구문을 사용하여 예외를 잡아내고 처리할 수 있습니다. 예를 들어, 앞서 작성한 `BankAccount` 클래스를 사용하는 코드는 다음과 같이 작성할 수 있습니다.
```java
public class Main {
public static void main(String[] args) {
BankAccount account = new BankAccount(1000);
try {
account.withdraw(1500);
} catch (InsufficientFundsException e) {
System.out.println("예외 발생: " + e.getMessage());
}
}
}
```
위 코드에서는 `InsufficientFundsException`이 발생했을 때 `catch` 블록에서 예외 메시지를 출력합니다. 이로써 프로그램이 비정상 종료되지 않고, 예외 상황을 처리하여 계속 진행될 수 있습니다.
### 5. `throws` 키워드를 통한 예외 전달
메소드 내부에서 예외를 발생시키는 경우, 호출된 메소드로 예외를 전달하고 싶다면 `throws` 키워드를 사용할 수 있습니다. `throws`는 메소드 시그니처에 선언되며, 예외를 발생시킨 메소드를 호출한 메소드가 예외를 처리하게 합니다.
#### `throws` 예제 코드
```java
public void readFile(String filePath) throws IOException {
FileReader file = new FileReader(filePath);
BufferedReader fileInput = new BufferedReader(file);
// 파일에서 첫 줄을 읽어오기
System.out.println(fileInput.readLine());
fileInput.close();
}
```
위 메소드에서는 파일을 읽을 때 `IOException`이 발생할 수 있습니다. 이 경우 `readFile` 메소드는 `IOException`을 직접 처리하지 않고 호출한 메소드로 전달합니다.
```java
public static void main(String[] args) {
try {
readFile("test.txt");
} catch (IOException e) {
System.out.println("파일 읽기 오류: " + e.getMessage());
}
}
```
이와 같이 `throws` 키워드를 사용해 예외를 호출한 쪽으로 전달하면, 코드가 더 간결해지고 예외 처리의 책임을 호출자에게 넘길 수 있습니다.
### 6. `finally` 블록을 통한 리소스 해제
Java에서는 `try-catch-finally` 구문을 통해 예외 발생 여부에 상관없이 항상 실행되는 `finally` 블록을 사용할 수 있습니다. `finally` 블록은 주로 열려 있는 리소스(파일, 네트워크 연결 등)를 해제할 때 사용됩니다.
```java
public void readFile(String filePath) {
BufferedReader fileInput = null;
try {
FileReader file = new FileReader(filePath);
fileInput = new BufferedReader(file);
System.out.println(fileInput.readLine());
} catch (IOException e) {
System.out.println("파일 읽기 오류: " + e.getMessage());
} finally {
if (fileInput != null) {
try {
fileInput.close();
} catch (IOException e) {
System.out.println("파일 닫기 오류: " + e.getMessage());
}
}
}
}
```
위 코드에서는 파일을 읽는 동안 예외가 발생하더라도 `finally` 블록이 실행되어 파일 리소스가 닫히도록 보장합니다.
### 7. `try-with-resources` 구문
Java 7부터는 `try-with-resources` 구문이 도입되어, `AutoCloseable` 인터페이스를 구현한 객체에 대해 자동으로 리소스를 해제할 수 있습니다. 이를 통해 `finally` 블록 없이도 리소스를 안전하게 닫을 수 있습니다.
```java
public void readFile(String filePath) {
try (BufferedReader fileInput = new BufferedReader(new FileReader(filePath))) {
System.out.println(fileInput.readLine());
} catch (IOException e) {
System.out.println("파일 읽기 오류: " + e.getMessage());
}
}
```
`try-with-resources` 구문을 사용하면 `fileInput` 객체가 `try` 블록이 끝나는 시점에 자동으로 닫히므로 코드가 더 깔끔하고 안전합니다.
'게으른 개발자의 끄적거림' 카테고리의 다른 글
Java Int형과 Integer 차이 완벽 정리 (0) | 2024.11.06 |
---|---|
.gif파일이란? (개념, 장단점 등) (2) | 2024.11.04 |
document객체란? (feat. 주요 메서드) (0) | 2024.10.22 |
프로시저(PROCEDURE)란? (0) | 2024.10.21 |
.pdf파일이란? (1) | 2024.10.17 |