Java에서는 개발자가 직접 예외 클래스를 정의할 수 있으며, 이렇게 만든 예외를 사용자 정의 예외(User-defined Exception) 또는 커스텀 예외(Custom Exception)라고 부릅니다.
사용자 정의 예외를 생성하려면 예외 관련 클래스 중 하나를 상속(extends)해야 합니다. 예외 발생 시 원하는 메시지를 표시하고 싶다면 toString() 메서드를 오버라이드하거나, 슈퍼클래스의 매개변수가 있는 생성자에 String 형태의 메시지를 전달하는 방식을 사용할 수 있습니다.
MyException(String msg){
super(msg);
}
또는,
public String toString(){
return " MyException [예외 메시지]";
}이후 다른 클래스에서 해당 예외를 발생시켜야 하는 지점에서 커스텀 예외 클래스의 객체를 생성하고, throw 키워드를 사용해 예외를 던지면 됩니다.
MyException ex = new MyException();
If(condition……….){
throw ex;
}
커스텀 체크드 예외와 커스텀 언체크드 예외
모든 예외 클래스는 반드시 Throwable의 하위 클래스여야 합니다.
Handle 또는 Declare 규칙(Handle or Declare Rule)에 의해 컴파일러가 자동으로 강제하는 체크드 예외(checked exception)를 작성하려면 Exception 클래스를 상속해야 합니다.
실행 중에 발생하는 런타임 예외(runtime exception)를 작성하려면 RuntimeException 클래스를 상속해야 합니다.
예제: 커스텀 체크드 예외
다음 Java 프로그램은 커스텀 체크드 예외를 생성하고 활용하는 방법을 보여줍니다. 이름이 소문자 알파벳으로만 구성되지 않으면 NotProperNameException을 발생시키는 구조입니다.
import java.util.Scanner;
class NotProperNameException extends Exception {
NotProperNameException(String msg){
super(msg);
}
}
public class CustomCheckedException {
private String name;
private int age;
public static boolean containsAlphabet(String name) {
for (int i = 0; i < name.length(); i++) {
char ch = name.charAt(i);
if (!(ch >= 'a' && ch <= 'z')) {
return false;
}
}
return true;
}
public CustomCheckedException(String name, int age){
if(!containsAlphabet(name)&&name!=null) {
String msg = "Improper name (Should contain only characters between a to z (all small))";
NotProperNameException exName = new NotProperNameException(msg);
throw exName;
}
this.name = name;
this.age = age;
}
public void display(){
System.out.println("Name of the Student: "+this.name );
System.out.println("Age of the Student: "+this.age );
}
public static void main(String args[]) {
Scanner sc= new Scanner(System.in);
System.out.println("Enter the name of the person: ");
String name = sc.next();
System.out.println("Enter the age of the person: ");
int age = sc.nextInt();
CustomCheckedException obj = new CustomCheckedException(name, age);
obj.display();
}
}
컴파일 타임 예외
위 프로그램을 컴파일하면 다음과 같은 오류가 발생합니다. 체크드 예외는 try-catch로 처리하거나 메서드 선언부에 throws로 명시하지 않으면 컴파일 자체가 되지 않습니다.
CustomCheckedException.java:24: error: unreported exception NotProperNameException; must be caught or declared to be thrown
throw exName;
^
1 error
예제: 커스텀 언체크드 예외
커스텀 예외가 상속하는 클래스를 단순히 RuntimeException으로 변경하기만 해도, 해당 예외는 런타임에 발생하는 언체크드 예외가 됩니다.
class NotProperNameException extends RuntimeException {
NotProperNameException(String msg){
super(msg);
}
}앞선 프로그램에서 NotProperNameException 클래스를 위 코드로 교체한 후 실행하면, 컴파일은 정상적으로 통과되지만 프로그램 실행 도중 다음과 같은 런타임 예외가 발생합니다.
런타임 예외
Enter the name of the person:
Krishna1234
Enter the age of the person:
20
Exception in thread "main" july_set3.NotProperNameException: Improper name (Should contain only characters between a to z (all small))
at july_set3.CustomCheckedException.<init>(CustomCheckedException.java:25)
at july_set3.CustomCheckedException.main(CustomCheckedException.java:41)
정리하면, 체크드 예외(Exception 상속)는 컴파일 시점에 처리 여부가 강제되어 안전한 코드 작성에 유리하고, 언체크드 예외(RuntimeException 상속)는 처리를 강제하지 않아 유연하지만 런타임 오류로 이어질 수 있습니다. 상황에 맞게 적절한 부모 클래스를 선택해 커스텀 예외를 설계하는 것이 좋습니다.