예외(Exception)는 프로그램 실행 중에 발생하는 예상치 못한 이벤트나 오류를 나타냅니다. 이러한 이벤트들은 프로그램의 정상적인 실행 흐름을 방해하거나 중단시킬 수 있습니다. 예외는 주로 코드 내에서 발생하는 상황으로, 프로그래머가 제어할 수 있거나 예방할 수 있는 상황에서 발생할 수 있습니다.
정의: 예외는 실행 중인 프로그램에서 예상치 못한 상황이나 오류를 나타냅니다. 이는 프로그램이 예상치 못한 입력, 잘못된 API 사용, 파일이 없는 등의 상황에서 일어날 수 있습니다.
발생 원인: 주로 코드 내에서 발생하며, 프로그래머의 부주의, 잘못된 사용, 또는 외부 조건에 의해 발생할 수 있습니다.
복구: 예외는 일반적으로 try-catch 블록을 사용하여 처리할 수 있습니다. 이를 통해 예외 상황에서 프로그램이 계속 실행될 수 있도록 대체 동작을 제공하거나, 사용자에게 적절한 메시지를 표시할 수 있습니다.
종류: 예외는 크게 두 가지로 나뉩니다. 체크 예외(Checked Exception)는 컴파일 시간에 확인되며, 코드에서 명시적으로 처리해야 합니다. 언체크 예외(Unchecked Exception)는 런타임에 발생하며, 코드에서 예외 처리를 강제하지 않습니다.
예시: 일반적인 예외로는 NullPointerException, ArrayIndexOutOfBoundsException, IOException 등이 있습니다.
처리: 예외는 try-catch 블록을 사용하여 처리할 수 있습니다. 또한 throws 키워드를 사용하여 예외를 호출한 메서드로 전파시킬 수도 있습니다.
예외 처리 코드는 주로 try
, catch
, 그리고 선택적으로 finally
블록을 사용하여 구성됩니다. 이들 블록은 프로그램에서 예외를 처리하고 예외 상황에 대응하는 데 사용됩니다.
try 블록: 예외가 발생할 수 있는 코드를 포함하는 블록입니다. try
블록 내에서 예외가 발생하면 해당 예외를 처리하는 catch
블록으로 제어가 전달됩니다.
catch 블록: try
블록에서 발생한 예외를 처리하는 데 사용되는 블록입니다. 여러 개의 catch
블록이 있을 수 있으며, 각 catch
블록은 특정 유형의 예외를 처리합니다. 발생한 예외와 일치하는 첫 번째 catch
블록이 실행됩니다.
finally 블록: finally
블록은 예외 발생 여부에 관계없이 항상 실행되는 블록입니다. 주로 리소스의 해제나 정리 등을 위해 사용됩니다. finally
블록은 생략 가능하며, try
블록이나 catch
블록의 실행 후 항상 실행됩니다.
아래는 간단한 코드 예제를 통해 try
, catch
, finally
블록의 사용을 보여줍니다:
public class ExceptionHandlingExample {
public static void main(String[] args) {
try {
// 예외가 발생할 수 있는 코드
int result = divide(10, 0);
System.out.println("결과: " + result); // 이 부분은 실행되지 않음
} catch (ArithmeticException e) {
// ArithmeticException이 발생한 경우의 처리
System.out.println("0으로 나눌 수 없습니다.");
} finally {
// 예외 발생 여부와 관계없이 항상 실행되는 코드
System.out.println("finally 블록 실행");
}
}
// 예외를 발생시키는 메서드
private static int divide(int numerator, int denominator) {
return numerator / denominator;
}
}
이 예제에서 try
블록 내에서 divide
메서드를 호출하고 있습니다. divide
메서드는 0으로 나누기를 시도하므로 ArithmeticException
이 발생합니다. 이 예외는 catch
블록에서 처리되고, 그 후 finally
블록이 실행됩니다. 만약 catch
블록이 없다면 예외는 상위 호출자로 전파됩니다.
예외 처리에서 여러 예외를 동일하게 처리하고 싶을 때, 두 개 이상의 예외 클래스를 파이프(|
)로 연결하여 하나의 catch
블록에서 처리할 수 있습니다. 이렇게 하면 여러 예외 유형에 대해 동일한 예외 처리 코드를 공유할 수 있습니다.
예를 들어, IOException
과 SQLException
두 예외를 동일한 방식으로 처리하고 싶다면 아래와 같이 작성할 수 있습니다:
try {
// 예외가 발생할 수 있는 코드
// ...
} catch (IOException | SQLException e) {
// IOException 또는 SQLException이 발생한 경우의 처리
System.out.println("IO 또는 SQL 예외 발생: " + e.getMessage());
} finally {
// 예외 발생 여부와 관계없이 항상 실행되는 코드
}
이 코드에서 catch
블록은 IOException
과 SQLException
을 동시에 처리합니다. 이렇게 함으로써 중복 코드를 피하고 여러 예외에 대한 공통 처리 로직을 재사용할 수 있습니다.
Java 7부터는 이러한 다중 예외 처리 문법이 도입되었으며, 이를 통해 코드의 가독성을 높이고 유지보수를 쉽게 할 수 있습니다.
throws
키워드는 메소드에서 발생한 예외를 직접 처리하지 않고, 메소드를 호출한 곳으로 예외를 떠넘길 때 사용됩니다. 이 키워드는 메소드 선언부에서 사용되며, 예외가 발생할 수 있는 메소드에서 사용됩니다.
public class Example {
// 예외를 떠넘기는 메소드
public void myMethod() throws CustomException {
// 메소드에서 발생한 예외 처리 로직
if (someCondition) {
throw new CustomException("Some custom exception message");
}
// 예외가 발생하지 않았을 경우의 코드
}
// 메소드를 호출한 곳에서 예외 처리
public static void main(String[] args) {
Example example = new Example();
try {
example.myMethod();
} catch (CustomException e) {
// 예외 처리 로직
System.out.println("Custom exception caught: " + e.getMessage());
}
}
}
위의 예제에서 myMethod()
는 CustomException
이 발생할 수 있는 메소드입니다. 이 메소드에서 예외가 발생하면 throws CustomException
을 사용하여 해당 예외를 직접 처리하지 않고 호출한 곳으로 예외를 전파합니다. 이렇게 하면 main
메소드에서 해당 예외를 적절히 처리할 수 있습니다.
throws
를 사용하여 예외를 떠넘길 때는 주의해야 합니다. 호출한 곳에서는 해당 예외를 처리해야 하거나, 동일하게 throws
를 사용하여 상위 호출자로 떠넘겨야 합니다.
public class Example {
public void myMethod() throws Exception {
// 예외가 발생할 수 있는 코드
if (someCondition) {
throw new CustomException("Some custom exception message");
}
// 다른 예외가 발생할 수 있는 코드
if (anotherCondition) {
throw new AnotherException("Another exception message");
}
// 예외가 발생하지 않았을 경우의 코드
}
public static void main(String[] args) {
Example example = new Example();
try {
example.myMethod();
} catch (Exception e) {
// 모든 예외를 처리하는 코드
System.out.println("Exception caught: " + e.getMessage());
}
}
}
사용자 정의 예외(또는 사용자 정의 예외 클래스)는 Java에서 기본으로 제공되는 예외 클래스 외에 프로그래머가 직접 만들어 사용하는 예외 클래스를 의미합니다. 이를 통해 특정 상황이나 조건에서 발생하는 예외를 더 명확하게 표현하고, 프로그램의 가독성을 높이며 디버깅을 용이하게 할 수 있습니다.
사용자 정의 예외를 만들기 위해서는 보통 기존의 Exception
클래스나 그 하위 클래스를 확장(상속)하여 새로운 예외 클래스를 정의합니다.
// 사용자 정의 예외 클래스 정의
class CustomException extends Exception {
public CustomException() {
super("This is a custom exception.");
}
public CustomException(String message) {
super(message);
}
}
// 사용자 정의 예외를 발생시키는 예제 메소드
public class Example {
public void myMethod() throws CustomException {
// 특정 조건에서 예외 발생
if (someCondition) {
throw new CustomException("Custom exception message");
}
// 예외가 발생하지 않았을 경우의 코드
}
public static void main(String[] args) {
Example example = new Example();
try {
example.myMethod();
} catch (CustomException e) {
// 사용자 정의 예외 처리
System.out.println("Custom exception caught: " + e.getMessage());
}
}
}