자바 - 예외: 초보자를 위한 친절한 가이드
안녕하세요, 미래의 자바 마법사 여러분! 오늘은 자바 예외의 세계로 흥미로운 여행을 떠날 거예요. 프로그래밍에 새로운 사람이라도 걱정 마세요 – 저는 여러분의 친절한 가이드로, 단계별로 모든 것을 설명해 드릴 거예요. 그럼, 뛰어들어보죠!
자바에서 예외란 무엇인가요?
厨房에서 요리를 하고 있는데, 레시피를 따라가다가 갑자기 달걀이 없다는 것을 알게 되었어요! 이는 예상치 못한 문제 아니요? 자바에서는 이러한 예상치 못한 문제를 "예외(exception)"라고 부릅니다.
예외는 프로그램 실행 중 발생하는 이벤트로, 정상적인 명령어 흐름을 방해합니다. 자바의 방식으로 "오류! 무언가 잘못된 것 같아요!"라고 말하는 것입니다.
간단한 예제를 살펴보죠:
public class ExceptionExample {
public static void main(String[] args) {
int[] numbers = {1, 2, 3};
System.out.println(numbers[3]); // 이는 예외를 일으킬 것입니다
}
}
이 코드를 실행하면 오류 메시지를 볼 수 있습니다. 그 이유는 우리가 인덱스 3에 있는 요소에 접근하려고 하지만, 우리의 배열은 인덱스 0, 1, 2에 요소만 있기 때문입니다. 자바는 ArrayIndexOutOfBoundsException
을 던져서 무언가 잘못된 것이라는 것을 알려줍니다.
예외가 발생하는 이유는 무엇인가요?
예외는 여러 가지 이유로 발생할 수 있습니다. 여기 몇 가지 일반적인 이유가 있습니다:
- 유효하지 않은 사용자 입력
- 하드웨어 고장
- 네트워크 문제
- 프로그래밍 오류
예를 들어, 0으로 나누는 오류를 살펴보죠:
public class DivisionByZeroExample {
public static void main(String[] args) {
int numerator = 10;
int denominator = 0;
int result = numerator / denominator; // 이는 예외를 일으킬 것입니다
System.out.println(result);
}
}
이 코드는 ArithmeticException
을 던집니다. 그 이유는 우리가 0으로 나누려고 하고, 수학적으로 정의되지 않았기 때문입니다.
자바 예외 범주
자바 예외는 세 가지 주요 유형으로 분류됩니다:
- 체크된 예외
- 체크되지 않은 예외 (런타임 예외)
- 오류
체크된 예외
이들은 컴파일러가 검사하는 예외입니다. 메서드가 체크된 예외를 던질 수 있다면, 이를 처리하거나 메서드 서명에서 선언해야 합니다.
예를 들어, FileNotFoundException
이라는 체크된 예외를 사용하는 예제를 살펴보죠:
import java.io.File;
import java.io.FileNotFoundException;
import java.util.Scanner;
public class CheckedExceptionExample {
public static void main(String[] args) {
try {
File file = new File("nonexistent.txt");
Scanner scanner = new Scanner(file);
} catch (FileNotFoundException e) {
System.out.println("오류! 파일이 존재하지 않습니다.");
}
}
}
체크되지 않은 예외 (런타임 예외)
이러한 예외는 런타임에 발생하며, 명시적으로 처리하거나 선언할 필요가 없습니다. 보통 프로그래밍 오류 때문에 발생합니다.
예를 들어, NullPointerException
이라는 체크되지 않은 예외를 살펴보죠:
public class UncheckedExceptionExample {
public static void main(String[] args) {
String text = null;
System.out.println(text.length()); // 이는 NullPointerException을 일으킬 것입니다
}
}
오류
오류는 심각한 문제로, 프로그램에서 처리할 수 없는外部 문제이거나 JVM 자체의 문제일 수 있습니다.
예를 들어, OutOfMemoryError
를 살펴보죠:
public class ErrorExample {
public static void main(String[] args) {
int[] hugeArray = new int[Integer.MAX_VALUE]; // 이는 OutOfMemoryError를 일으킬 수 있습니다
}
}
자바 예외 계층 구조
자바 예외는 계층 구조를 따릅니다. 최상위는 Throwable
클래스로, 이는 두 주요 서브클래스를 가지고 있습니다: Exception
과 Error
.
여기 간단한 계층 구조를 보여드립니다:
Throwable
├── Error
└── Exception
└── RuntimeException
자바 예외 클래스 메서드
Throwable
클래스는 모든 예외가 상속받는 유용한 메서드를 제공합니다. 여기 일부 가장 일반적으로 사용되는 메서드가 있습니다:
메서드 | 설명 |
---|---|
getMessage() |
예외에 대한 자세한 메시지를 반환합니다 |
printStackTrace() |
예외의 스택 트레이스를 인쇄합니다 |
toString() |
예외에 대한 짧은 설명을 반환합니다 |
getStackTrace() |
스택 트레이스를 포함하는 배열을 반환합니다 |
이 메서드들을 실제로 사용해 보죠:
public class ExceptionMethodsExample {
public static void main(String[] args) {
try {
int result = 10 / 0;
} catch (ArithmeticException e) {
System.out.println("Message: " + e.getMessage());
System.out.println("ToString: " + e.toString());
e.printStackTrace();
}
}
}
예외 처리: 자바의 예외 핸들링
이제 예외가 무엇인지 이해했으니, 예외를 처리하는 방법을 배워보죠. 자바에서는 try-catch 블록을 사용하여 예외를 처리합니다.
public class ExceptionHandlingExample {
public static void main(String[] args) {
try {
// 예외를 일으킬 수 있는 코드
int result = 10 / 0;
} catch (ArithmeticException e) {
// 예외를 처리할 코드
System.out.println("0으로 나눌 수 없습니다!");
}
}
}
이 예제에서는 "try"로 0으로 나누는 시도를 합니다. 예외가 발생하면 catch 블록의 코드가 실행됩니다.
여러 catch 블록
때로는 같은 코드 블록에서 여러 가지 유형의 예외가 발생할 수 있습니다. 이를 여러 catch 블록으로 처리할 수 있습니다:
public class MultipleCatchExample {
public static void main(String[] args) {
try {
int[] numbers = {1, 2, 3};
System.out.println(numbers[3]); // 이는 ArrayIndexOutOfBoundsException을 일으킬 것입니다
int result = 10 / 0; // 이는 ArithmeticException을 일으킬 것이지만, 도달하지 않습니다
} catch (ArrayIndexOutOfBoundsException e) {
System.out.println("배열 인덱스가 범위를 벗어났습니다!");
} catch (ArithmeticException e) {
System.out.println("0으로 나눌 수 없습니다!");
}
}
}
여러 유형의 예외 처리
만약 여러 예외 유형을 같은 방식으로 처리하고 싶다면, 단일 catch 블록으로 처리할 수 있습니다:
public class MultipleExceptionTypesExample {
public static void main(String[] args) {
try {
// 여러 예외를 일으킬 수 있는 코드
} catch (ArithmeticException | ArrayIndexOutOfBoundsException e) {
System.out.println("계산 또는 배열 인덱스 오류가 발생했습니다!");
}
}
}
throws/throw 키워드
throws
키워드는 메서드 선언에서 이 메서드가 특정 유형의 예외를 던질 수 있음을 지정합니다. throw
키워드는 실제로 예외를 던지는 데 사용됩니다.
public class ThrowsExample {
public static void main(String[] args) {
try {
riskyMethod();
} catch (Exception e) {
System.out.println("예외를 잡았습니다: " + e.getMessage());
}
}
public static void riskyMethod() throws Exception {
throw new Exception("이것은 위험한 작업입니다!");
}
}
finally 블록
finally
블록은 중요한 코드를 실행하는 데 사용됩니다. 예를 들어, 커넥션을 닫거나 파일을 닫는 등의 작업을 수행합니다. 이는 예외가 처리되었든지 않았든 실행됩니다.
public class FinallyExample {
public static void main(String[] args) {
try {
int result = 10 / 0;
} catch (ArithmeticException e) {
System.out.println("0으로 나눌 수 없습니다!");
} finally {
System.out.println("이 코드는 항상 실행됩니다.");
}
}
}
try-with-resources
자바 7에서 도입된 try-with-resources 문은 try 문과 함께 하나 이상의 자원을 선언하는 try 문입니다. 자원은 프로그램이 끝난 후 닫아야 하는 객체입니다.
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
public class TryWithResourcesExample {
public static void main(String[] args) {
try (BufferedReader br = new BufferedReader(new FileReader("test.txt"))) {
String line;
while ((line = br.readLine()) != null) {
System.out.println(line);
}
} catch (IOException e) {
System.out.println("파일을 읽는 중 오류가 발생했습니다.");
}
}
}
이 예제에서 BufferedReader
는 자동으로 try 블록이 끝나면 닫히게 됩니다. 예외가 발생했더라도 마찬가지입니다.
자바에서 사용자 정의 예외
때로는 프로그램에서 특정 오류 상황을 나타내기 위해 자신만의 예외 유형을 만드는 것이 필요할 수 있습니다. 이를 위해 다음과 같이 할 수 있습니다:
class MyCustomException extends Exception {
public MyCustomException(String message) {
super(message);
}
}
public class CustomExceptionExample {
public static void main(String[] args) {
try {
throw new MyCustomException("이것은 내가 만든 사용자 정의 예외입니다!");
} catch (MyCustomException e) {
System.out.println(e.getMessage());
}
}
}
자바의 일반 예외
여기 자바에서 자주 만나는 몇 가지 예외가 있습니다:
-
NullPointerException
: null 객체를 참조하는 참조 변수를 사용할 때 발생합니다. -
ArrayIndexOutOfBoundsException
: 배열의 유효하지 않은 인덱스에 접근할 때 발생합니다. -
ClassCastException
: 객체를 부모 클래스가 아닌 자식 클래스로 캐스팅할 때 발생합니다. -
IllegalArgumentException
: 메서드가 처리할 수 없는 인수를 받을 때 발생합니다. -
IOException
: I/O 작업이 실패했을 때 발생합니다.
예외를 올바르게 처리하는 것은 견고한 자바 프로그램을 작성하는 데 중요한 부분입니다. 예외를 잘 처리하면 예상치 못한 상황에 대처하고, 사용자 경험을 향상시킬 수 있습니다.
이제 자바 예외에 대한 여행은 끝났습니다! 이 가이드가 도움이 되었고, 쉽게 이해할 수 있었기를 바랍니다. 연습을 계속하며, 곧 예외를 잘 처리하는 전문가가 될 것입니다. 코딩을 즐겨요!
Credits: Image by storyset