Linux Exception Handling
CPU에서 발생하는 대부분의 예외는 Linux에서 오류 조건[error conditions]으로 해석됩니다. 그 중 하나가 발생하면 커널은 예외를 발생시킨 프로세스에 비정상적인 조건을 알리는 신호를 보냅니다. 예를 들어 프로세스가 0으로 나누기를 수행하면 CPU는 "나누기 오류"를 발생시킵니다." 예외가 발생하고 해당 예외 처리기가 현재 프로세스에 SIGFPE 시그널를 보낸 다음 복구 또는 (해당 신호에 대해 시그널 핸들러가 설정되지 않은 경우) 중단하는 데 필요한 단계를 수행합니다.
※ Linux Signal
# kill -l
1) SIGHUP 2) SIGINT 3) SIGQUIT 4) SIGILL
5) SIGTRAP 6) SIGABRT 7) SIGBUS 8) SIGFPE
9) SIGKILL 10) SIGUSR1 11) SIGSEGV 12) SIGUSR2
13) SIGPIPE 14) SIGALRM 15) SIGTERM 16) SIGSTKFLT
17) SIGCHLD 18) SIGCONT 19) SIGSTOP 20) SIGTSTP
21) SIGTTIN 22) SIGTTOU 23) SIGURG 24) SIGXCPU
25) SIGXFSZ 26) SIGVTALRM 27) SIGPROF 28) SIGWINCH
29) SIGIO 30) SIGPWR 31) SIGSYS 34) SIGRTMIN
35) SIGRTMIN+1 36) SIGRTMIN+2 37) SIGRTMIN+3 38) SIGRTMIN+4
39) SIGRTMIN+5 40) SIGRTMIN+6 41) SIGRTMIN+7 42) SIGRTMIN+8
43) SIGRTMIN+9 44) SIGRTMIN+10 45) SIGRTMIN+11 46) SIGRTMIN+12
47) SIGRTMIN+13 48) SIGRTMIN+14 49) SIGRTMIN+15 50) SIGRTMAX-14
51) SIGRTMAX-13 52) SIGRTMAX-12 53) SIGRTMAX-11 54) SIGRTMAX-10
55) SIGRTMAX-9 56) SIGRTMAX-8 57) SIGRTMAX-7 58) SIGRTMAX-6
59) SIGRTMAX-5 60) SIGRTMAX-4 61) SIGRTMAX-3 62) SIGRTMAX-2
63) SIGRTMAX-1 64) SIGRTMAX
번호 | 시그널 이름 | 발생 및 용도 | 디폴트 action | 리눅스 버전 |
1 | SIGHUP(HUP) | hangup 시그널; 전화선 끊어짐 | 종료 | POSIX |
2 | SIGINT(INT) | interrupt 시그널; Ctrl + c ;실행을중지 | 종료 | ANSI |
3 | SIGQUIT(QUIT) | quit 시그널; Ctrl + \ | 종료(코어덤프) | POSIX |
4 | SIGILL(ILL) | 잘못된 명령 | ANSI | |
5 | SIGTRAP(TRAP) | 트렙 추적 | POSIX | |
6 | SIGIOT(IOT) | IOT 명령 | 4.2 BSD | |
7 | SIGBUS(BUS) | 버스 에러 | 4.2 BSD | |
8 | SIGFPE(FPE) | 부동 소수점 에러 | 종료 | ANSI |
9 | SIGKILL(KILL) | 무조건적으로 즉시 중지한다. | 종료 | POSIX |
10 | SIGUSR1(USR1) | 사용자 정의 시그널1 | 종료 | POSIX |
11 | SIGSEGV(SEGV) | 세그멘테이션 위반 | ANSI | |
12 | SIGUSR2(USR2) | 사용자 정의 시그널2 | 종료 | POSIX |
13 | SIGPIPE(PIPE) | 읽으려는 프로세스가 없는데 파이프에 쓰려고 함 | 종료 | POSIX |
14 | SIGALRM(ALRM) | 경보(alarm) 시그널; alarm(n)에 의해 n초 후 생성됨 | 종료 | POSIX |
15 | SIGTERM(TERM) | 일반적으로 kill 시그널이 전송되기 전에 전송된다. 잡히는 시그널이기 때문에 종료되는 것을 트랙할 수 있다. | 종료 | ANSI |
16 | SIGTKFLT | 코프로세서 스택 실패 | ||
17 | SIGCHLD(CHLD) | 프로세스 종료시 그 부모 프로세스에게 보내지는 시그널 | 무시 | POSIX |
18 | SIGCONT(CONT) | STOP 시그널 이후 계속 진행할 때 사용. ; 정지 되지 않은 경우 무시됨 | POSIX | |
19 | SIGSTOP(STOP) | 정지 시그널; SIGSTP과 같으나 잡거나 무시할 수 없음 | 프로세스 정지 | POSIX |
20 | SIGTSTP(TSTP) | 키보드에 의해 발생하는 시그널로 Ctrl+Z로 생성된다. ; 터미널 정지 문자 | 프로세스 정지 | POSIX |
21 | SIGTTIN | 백그라운드에서의 제어터미널 읽기 | 프로세스 정지 | POSIX |
22 | SIGTTOU | 백그라운드에서의 제어터미널 쓰기 | 프로세스 정지 | POSIX |
23 | SIGURG | 소켓에서의 긴급한 상태 | 4.2 BSD | |
24 | SIGXCPU | CPU 시간 제한 초과 setrlimit(2) 메뉴얼 패이지 참조 | 4.2 BSD | |
25 | SIGXFSZ | 파일 크기제한 초과 setrlimit(2) 메뉴얼 패이지 참조 | 4.2 BSD | |
26 | SIGVTALRM | 가상 시간 경고 setitimer(2) 메뉴얼 패이지 참조 | 4.2 BSD | |
27 | SIGPROF | 프로파일링 타이머 경고. setitimer(2) 메뉴얼 페이지 참조 | 4.2 BSD | |
28 | SIGWINCH | 윈도우 사이즈 변경 | 4.3 BSD, Sun | |
29 | SIGIO | 기술자에서 입출력이 가능함. fcntl(2) 메뉴얼 참조 | 4.2 BSD | |
30 | SIGPWR | 전원 실패 | System V | |
31 | UNUSED | 사용 안함 |
리눅스 시그널 처리
- 리눅스는 시그널(signal) 메커니즘을 통해 예외 상황을 처리할 수 있습니다.
- 시그널은 프로세스에게 특정 이벤트가 발생했음을 알리는 메커니즘으로, 예외 상황에 따라 적절한 조치를 취할 수 있습니다.
- 프로그램은 시그널 핸들러(signal handler)를 등록하여 특정 시그널을 처리할 수 있습니다. 시그널 핸들러는 시그널이 발생하면 실행되는 함수입니다.
리눅스에서는 이러한 예외처리 메커니즘을 사용하여 예외 상황을 처리합니다. 이를 통해 프로그램은 예외적인 상황에서도 안정적으로 동작하고 오류를 처리하며, 예외 상황에 대한 적절한 조치를 취할 수 있습니다. 각각의 방식은 프로그래밍 언어나 라이브러리에 따라 다를 수 있으며, 개발자는 해당 언어나 라이브러리의 문서를 참조하여 적절한 예외 처리 방식을 선택해야 합니다.
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
// SIGINT 핸들러 함수
void sigint_handler(int signum) {
printf("Caught SIGINT signal\n");
// 여기서 필요한 동작 수행
// ...
}
// SIGFPE 핸들러 함수
void sigfpe_handler(int signum) {
if (signum == FPE_INTDIV) {
printf("Caught SIGFPE signal (Divide error)\n");
// Divide error 예외 처리 동작 수행
// ...
} else {
printf("Caught SIGFPE signal (Unknown)\n");
// 알 수 없는 SIGFPE 예외 처리 동작 수행
// ...
}
}
// SIGTERM 핸들러 함수
void sigterm_handler(int signum) {
printf("Caught SIGTERM signal\n");
// 여기서 필요한 동작 수행
// ...
exit(signum); // 프로그램 종료
}
int main() {
// SIGINT 핸들러 등록
signal(SIGINT, sigint_handler);
// SIGFPE 핸들러 등록
signal(SIGFPE, sigfpe_handler);
// SIGTERM 핸들러 등록
signal(SIGTERM, sigterm_handler);
// 무한 루프
while (1) {
// 프로그램 실행 중인 동안 여기서 작업 수행
// ...
}
return 0;
}
Java Exception Handling
Throwable
자바에서 Throwable은 모든 예외와 오류의 최상위 클래스입니다. Throwable은 예외와 오류 모두를 포함하며, 이를 통해 예외 처리 및 오류 처리를 일관되게 다룰 수 있습니다. Throwable은 다음과 같은 주요 특징을 갖습니다:
1. 계층 구조: Throwable은 예외와 오류를 처리하기 위한 계층 구조를 형성합니다. 이 계층 구조는 Throwable 클래스를 상속하는 Exception과 Error 클래스로 구성됩니다.
2. 예외 처리: Throwable과 그 하위 클래스인 Exception은 예외 처리를 위해 사용됩니다. 예외는 프로그램의 정상적인 실행 흐름을 방해하는 상황을 나타내며, 개발자는 예외를 적절하게 처리하여 예외 상황에 대응할 수 있습니다.
3. 오류 처리: Throwable의 하위 클래스인 Error는 프로그램에서 복구할 수 없는 치명적인 오류를 나타냅니다. Error는 주로 시스템 수준의 문제를 나타내며, 개발자는 이러한 오류에 대해서는 대응하기보다는 종료하거나 로깅하는 등의 작업을 수행해야 합니다.
4. 예외 처리 메커니즘: Throwable 클래스 계층 구조는 예외 처리 메커니즘을 구현하는 데 사용됩니다. 예외는 try-catch 블록을 사용하여 처리하거나, throws 절을 통해 상위 호출자로 전파할 수 있습니다.
5. 필수 메서드: Throwable 클래스는 예외 및 오류 처리에 필요한 다양한 메서드를 제공합니다. 예를 들어, getMessage()는 예외에 대한 상세한 메시지를 반환하고, printStackTrace()는 예외의 호출 스택 추적을 출력하는 등의 기능을 제공합니다.
6. 사용자 정의 예외: 개발자는 Throwable의 하위 클래스인 Exception을 확장하여 사용자 정의 예외 클래스를 만들 수 있습니다. 이를 통해 특정 예외 상황에 대한 처리 로직을 구현할 수 있습니다.
Throwable과 그 하위 클래스들은 자바에서 예외 및 오류 처리를 위한 중요한 요소이며, 프로그램의 안정성과 신뢰성을 향상시키는 데 도움을 줍니다.
public class Throwable implements Serializable {
private static final long serialVersionUID = -3042686055658047285L;
private transient Object backtrace;
private String detailMessage;
public Throwable() {
fillInStackTrace();
}
public Throwable(String message) {
fillInStackTrace();
detailMessage = message;
}
public String getMessage() {
return detailMessage;
}
public String toString() {
String className = getClass().getName();
String message = getMessage();
return (message != null) ? (className + ": " + message) : className;
}
public void printStackTrace() {
printStackTrace(System.err);
}
public void printStackTrace(PrintStream stream) {
printStackTrace(new PrintWriter(stream));
}
public void printStackTrace(PrintWriter writer) {
writer.println(this);
if (backtrace != null) {
// 스택 트레이스 정보 출력
} else {
// 예외 발생 지점부터의 스택 트레이스 출력
}
}
public Throwable fillInStackTrace() {
// 스택 트레이스 정보 채우기
return this;
}
// 기타 메서드 및 멤버 변수 생략...
}
- Throwable 클래스는 Serializable 인터페이스를 구현하고 있습니다. 예외 객체가 직렬화되어 전송되거나 저장될 수 있도록 해줍니다.
- Throwable 클래스에는 예외 메시지를 저장하기 위한 detailMessage 필드와, 스택 트레이스 정보를 저장하기 위한 backtrace 필드가 있습니다. backtrace 필드는 transient로 선언되어 직렬화에서 제외됩니다.
- Throwable 클래스에는 예외 메시지를 반환하는 getMessage() 메서드와 예외 정보를 문자열로 반환하는 toString() 메서드가 있습니다.
- 스택 트레이스를 출력하는 메서드로는 printStackTrace()가 제공됩니다. 이 메서드는 System.err에 스택 트레이스 정보를 출력합니다. printStackTrace(PrintStream stream) 및 printStackTrace(PrintWriter writer) 메서드를 통해 출력 스트림을 지정할 수도 있습니다.
- fillInStackTrace() 메서드는 예외 발생 지점부터의 스택 트레이스 정보를 채우는 역할을 합니다.
※transient 키워드는 자바 직렬화(Java Serialization)에서 사용되는 특수한 키워드입니다. transient 키워드가 필드 앞에 붙으면 해당 필드는 직렬화 과정에서 제외됩니다. Throwable 클래스의 backtrace 필드에 transient 키워드가 사용된 이유는 다음과 같습니다:
1. 직렬화 시 필드 제외: Throwable 객체를 직렬화할 때, backtrace 필드는 스택 트레이스 정보를 담고 있으므로 직렬화 대상에서 제외해야 합니다. transient 키워드를 사용하여 backtrace 필드를 직렬화 과정에서 제외시킵니다.
2. 직렬화 크기 감소: backtrace 필드는 스택 트레이스 정보를 저장하는 데 큰 용량을 차지할 수 있습니다. 직렬화 시 backtrace 필드를 제외하면 직렬화 크기를 줄일 수 있습니다.
3. 스택 트레이스 재생성: 직렬화된 Throwable 객체를 역직렬화할 때 backtrace 필드가 제외되었기 때문에, 스택 트레이스 정보를 다시 생성해야 합니다. 이를 위해 fillInStackTrace() 메서드가 호출되어 스택 트레이스 정보를 채웁니다. 즉, transient 키워드는 Throwable 클래스의 backtrace 필드를 직렬화에서 제외하여 직렬화 크기를 감소시키고, 역직렬화 시에는 스택 트레이스 정보를 다시 생성하는 역할을 수행합니다. 이를 통해 직렬화와 역직렬화 과정의 효율성을 개선할 수 있습니다.
Unchecked
"Unchecked"라는 용어는 자바에서 "Unchecked Exception" 및 "Unchecked Error"를 지칭하는 데 사용됩니다. 여기서 "Unchecked"는 예외 또는 오류의 발생 여부를 컴파일러가 확인하지 않는다는 의미입니다.
1. Unchecked Exception: Unchecked Exception은 컴파일러가 예외 처리를 강제화하지 않는 예외를 의미합니다. 이러한 예외는 RuntimeException 클래스 및 그 하위 클래스들을 포함하며, 개발자가 명시적인 예외 처리를 강제받지 않습니다. 따라서 예외를 처리하거나 전파하는 것은 개발자의 선택입니다. 대표적인 예시로는 NullPointerException, ArrayIndexOutOfBoundsException, ArithmeticException 등이 있습니다.
2. Unchecked Error: Unchecked Error는 실행 중 발생하는 심각한 오류를 의미합니다. 이러한 오류는 컴파일러가 확인하지 않으며, 프로그램의 실행 도중 예상치 못한 상황이 발생할 수 있습니다. Unchecked Error는 Error 클래스 및 그 하위 클래스들을 포함하며, 개발자가 직접적으로 이러한 오류를 처리할 필요는 없습니다. 예시로는 OutOfMemoryError, StackOverflowError 등이 있습니다.
Unchecked라는 용어는 예외 또는 오류가 발생했을 때 컴파일러가 예외 처리를 확인하지 않는다는 점을 강조합니다.
(Unchecked Exception 또는 Unchecked Error는 코드를 작성할 때 컴파일러가 컴파일 에러를 발생시키지 않습니다)
따라서 이러한 예외 및 오류는 개발자가 명시적으로 처리할 필요는 없지만, 발생할 경우 프로그램의 실행이 중단될 수 있으므로 적절한 예외 처리 또는 오류 대응을 고려해야 합니다.
컴파일러는 Unchecked Exception 또는 Unchecked Error를 throws 선언이나 try-catch 블록을 사용하여 처리하도록 강제하지 않습니다. 따라서 개발자는 이러한 예외 또는 오류를 명시적으로 처리하지 않아도 컴파일이 가능합니다.
예를 들어, 다음은 Unchecked Exception인 `NullPointerException을 발생시키는 코드입니다:
public class UncheckedExceptionExample {
public static void main(String[] args) {
String str = null;
System.out.println(str.length()); // NullPointerException 발생
}
}
위의 코드는 컴파일 에러를 발생시키지 않습니다. 그러나 실행 시 NullPointerException 런타임 에러가 발생하게 됩니다.
이러한 Unchecked Exception 또는 Unchecked Error는 코드를 작성할 때 컴파일 에러를 발생시키지 않지만, 프로그램 실행 중 예외가 발생할 수 있습니다. 따라서 예외 처리나 오류 대응을 적절히 고려하여 프로그램을 작성해야 합니다.
Checked
Checked Exception은 컴파일러가 예외 처리를 강제화하는 예외를 말합니다. Checked Exception은 RuntimeException 클래스를 상속받지 않는 예외 클래스들을 포함합니다.
Checked Exception은 개발자가 예외 처리를 명시적으로 해야 하며, 컴파일러는 해당 예외를 처리하지 않은 경우 컴파일 에러를 발생시킵니다. 이는 예외 처리를 강제화하여 예외 상황에 대한 명확한 대응을 유도하는 것입니다.
주로 외부 리소스와의 상호 작용이 필요한 I/O 작업, 네트워크 통신, 데이터베이스 액세스 등에서 발생하는 예외들이 Checked Exception의 대표적인 예입니다. 몇 가지 예시로는 IOException, SQLException, FileNotFoundException 등이 있습니다.
Checked Exception을 처리하기 위해서는 try-catch 블록을 사용하여 예외를 직접 처리하거나, 해당 예외를 호출자에게 전파하기 위해 throws 선언을 사용하여 예외를 위임할 수 있습니다. 이를 통해 예외 상황에 대한 적절한 처리를 할 수 있습니다.
따라서, Checked Exception은 개발자가 예외 처리를 명시적으로 해야 하며, 컴파일러가 이를 강제화하여 예외 처리를 유도하는 예외입니다.
Error
자바에서는 Throwable 클래스 계층 구조의 하위 클래스인 Error를 사용하여 프로그램에서 복구할 수 없는 치명적인 오류를 나타냅니다.
public class Error extends Throwable {
private static final long serialVersionUID = 4980196508277280342L;
public Error() {
super();
}
public Error(String message) {
super(message);
}
public Error(String message, Throwable cause) {
super(message, cause);
}
public Error(Throwable cause) {
super(cause);
}
// 기타 메서드 및 멤버 변수 생략...
}
- Error 클래스는 Throwable 클래스를 상속하고 있으며, 자체적으로 추가적인 메서드와 멤버 변수를 가지고 있을 수 있습니다. 위의 예시에서는 Error 클래스의 생성자들이 정의되어 있습니다.
- Error 클래스는 보통 심각한 시스템 수준의 오류를 나타내는데 사용됩니다. 예를 들어, OutOfMemoryError, StackOverflowError와 같은 오류들이 Error 클래스의 하위 클래스로 구현되어 있습니다.
- 주의할 점은 일반적인 상황에서 개발자가 Error 클래스를 사용할 필요는 없으며, 대부분의 경우 이러한 오류는 시스템 수준에서 처리되어야 합니다. Error 클래스는 일반적인 예외 처리 흐름과는 다른 동작을 수행하므로, 프로그램에 직접 사용하는 것은 권장되지 않습니다.
주요한 치명적인 오류들은 다음과 같습니다:
1. OutOfMemoryError: JVM의 힙 메모리 공간이 부족한 경우 발생하는 오류입니다. 프로그램이 필요한 메모리를 할당할 수 없을 때 발생하며, 주로 대용량 데이터 처리나 무한 재귀 호출 등으로 인해 발생할 수 있습니다.
2. StackOverflowError: 호출 스택(Stack)이 너무 깊게 쌓여 스택 메모리 공간을 초과한 경우 발생하는 오류입니다. 주로 무한 재귀 호출이나 스택 메모리 부족으로 인해 발생할 수 있습니다.
3. NoClassDefFoundError: 클래스를 찾을 수 없는 경우에 발생하는 오류입니다. 클래스 파일이 존재하지 않거나, 클래스 파일이 잘못되었거나, 클래스 패스에 문제가 있는 경우에 발생할 수 있습니다.
4. UnsupportedClassVersionError: 클래스 파일의 버전이 현재 JVM에서 지원되지 않는 경우 발생하는 오류입니다. 클래스 파일이 더 높은 버전의 JVM에서 컴파일되었을 때, 현재 사용 중인 낮은 버전의 JVM에서 이 오류가 발생할 수 있습니다.
5. InternalError: JVM 내부에서 발생하는 치명적인 오류를 나타내는 오류입니다. JVM 자체의 구현 버그나 서브시스템에서 발생하는 오류로, 일반적으로 프로그램 코드로 복구할 수 없는 문제를 나타냅니다.
이러한 오류들은 프로그램에서 복구할 수 없는 치명적인 문제를 나타내므로, 주로 예외 처리 메커니즘을 사용하여 처리하지 않고 프로그램 실행을 중단하거나 적절한 조치를 취해야 합니다.
다음은 Error 클래스의 하위 클래스인 오류들을 사용하여 작성된 간단한 예제 코드입니다:
1. OutOfMemoryError
public class OutOfMemoryExample {
public static void main(String[] args) {
try {
List<Integer> list = new ArrayList<>();
while (true) {
list.add(1);
}
} catch (OutOfMemoryError e) {
System.out.println("Out of memory error occurred!");
}
}
}
위의 예제에서는 ArrayList에 계속해서 1을 추가하면서 힙 메모리 공간을 초과하여 OutOfMemoryError를 발생시키는 코드입니다. OutOfMemoryError가 발생하면 catch 블록이 실행되고 Out of memory error occurred! 메시지가 출력됩니다.
2. StackOverflowError
public class StackOverflowExample {
public static void recursiveMethod() {
recursiveMethod();
}
public static void main(String[] args) {
try {
recursiveMethod();
} catch (StackOverflowError e) {
System.out.println("Stack overflow error occurred!");
}
}
}
위의 예제에서는 recursiveMethod() 메서드에서 자기 자신을 재귀적으로 호출하면서 스택 메모리를 초과하여 StackOverflowError를 발생시키는 코드입니다. StackOverflowError가 발생하면 catch 블록이 실행되고 Stack overflow error occurred 메시지가 출력됩니다.
3. NoClassDefFoundError
public class NoClassDefFoundExample {
public static void main(String[] args) {
try {
// 없는 클래스를 참조하여 오류 발생
Class.forName("com.example.NonExistentClass");
} catch (ClassNotFoundException e) {
System.out.println("Class not found error occurred!");
}
}
}
위의 예제에서는 존재하지 않는 클래스인 com.example.NonExistentClass를 Class.forName() 메서드를 통해 참조하면서 NoClassDefFoundError를 발생시키는 코드입니다. NoClassDefFoundError가 발생하면 catch 블록이 실행되고 Class not found error occurred! 메시지가 출력됩니다.
4. NegativeArraySizeException
public class NegativeArraySizeExceptionExample {
public static void main(String[] args) {
try {
// 더 높은 버전의 클래스 파일을 사용하여 오류 발생
int[] array = new int[-1];
} catch (NegativeArraySizeException e) {
System.out.println("NegativeArraySizeException class version error occurred!");
}
}
}
이러한 예제 코드는 해당 오류들을 강제로 발생시키기 위한 간단한 예시입니다. 실제로 이러한 오류들은 프로그램 실행 중에
예상치 못한 문제가 발생했을 때 자동으로 발생합니다.
※이러한 오류들은 프로그램의 실행을 계속할 수 없는 심각한 문제를 나타내며, 예외 처리 메커니즘을 통해 복구할 수 없는 경우가 대부분입니다.
예를 들어, OutOfMemoryError는 JVM의 힙 메모리가 부족한 경우 발생하며, 힙 메모리를 동적으로 확장할 수 없기 때문에 복구가 어렵습니다.
StackOverflowError는 호출 스택이 너무 깊게 쌓여 스택 메모리를 초과한 경우로, 스택의 크기를 동적으로 조정할 수 없으므로 복구가 어렵습니다.
NoClassDefFoundError는 필요한 클래스를 찾을 수 없는 경우 발생하며, 클래스 파일이 존재하지 않거나 잘못된 클래스 경로일 경우입니다. 이 경우에는 클래스가 필요한 상황에서 복구할 수 없으므로 예외를 처리하고 오류 메시지를 사용자에게 표시하는 등의 대응을 할 수 있습니다.
UnsupportedClassVersionError는 클래스 파일의 버전이 현재 JVM에서 지원되지 않는 경우 발생합니다. 버전 호환성 문제로 인해 프로그램을 복구할 수 없는 경우가 많습니다.
따라서, 이러한 치명적인 오류들이 발생하는 경우 일반적으로 프로그램의 실행을 중단하고 오류에 대한 로깅 또는 사용자에게 오류 메시지를 표시하는 등의 작업을 수행하는 것이 일반적입니다.
Exception
Exception 클래스는 자바에서 일반적인 예외를 나타내는 클래스입니다. 아래는 Exception 클래스의 간단한 예시 소스 코드입니다:
public class Exception extends Throwable {
private static final long serialVersionUID = -3387516993124229948L;
public Exception() {
super();
}
public Exception(String message) {
super(message);
}
public Exception(String message, Throwable cause) {
super(message, cause);
}
public Exception(Throwable cause) {
super(cause);
}
// 기타 메서드 및 멤버 변수 생략...
}
- Exception 클래스는 Throwable 클래스를 상속하고 있으며, 자체적으로 추가적인 메서드와 멤버 변수를 가지고 있을 수 있습니다. 위의 예시에서는 Exception 클래스의 생성자들이 정의되어 있습니다.
- Exception 클래스는 일반적인 예외 상황을 나타내는 데 사용됩니다. 개발자가 직접 예외를 발생시키기 위해 사용할 수도 있습니다. 예를 들어, IOException, ClassNotFoundException, NullPointerException 등이 Exception 클래스를 상속받아 구현된 예외들입니다.
- Exception 클래스를 상속받은 구체적인 예외 클래스들은 특정한 예외 상황을 나타내며, 해당 예외에 대한 추가적인 기능과 메서드를 제공합니다.
주의할 점은 예외 처리를 할 때는 구체적인 예외 클래스를 사용하는 것이 좋습니다. Exception 클래스를 직접 사용하기보다는 예외 상황에 맞는 하위 클래스를 활용하여 예외 처리를 하는 것이 더 명확하고 유연한 코드 작성을 도와줍니다.
RunTimeException
RuntimeException 클래스는 자바에서 Unchecked Exception을 나타내는 클래스입니다. 아래는 RuntimeException 클래스의 예시 소스 코드입니다:
public class RuntimeException extends Exception {
private static final long serialVersionUID = -7034897190745766939L;
public RuntimeException() {
super();
}
public RuntimeException(String message) {
super(message);
}
public RuntimeException(String message, Throwable cause) {
super(message, cause);
}
public RuntimeException(Throwable cause) {
super(cause);
}
// 기타 메서드 및 멤버 변수
/**
* Returns the detail message string of this throwable.
*
* @return the detail message string of this {@code Throwable} instance
* (which may be {@code null}).
*/
public String getMessage() {
// 예외의 상세 메시지 반환
return super.getMessage();
}
/**
* Returns a short description of this throwable.
*
* @return a string representation of this throwable.
*/
public String toString() {
// 예외의 간단한 설명 반환
return super.toString();
}
/**
* Prints this throwable and its backtrace to the standard error stream.
*/
public void printStackTrace() {
printStackTrace(System.err);
}
/**
* Prints this throwable and its backtrace to the specified print stream.
*
* @param stream {@link PrintStream} to use for output
*/
public void printStackTrace(PrintStream stream) {
// 스택 트레이스 정보를 지정된 출력 스트림에 출력
super.printStackTrace(stream);
}
/**
* Prints this throwable and its backtrace to the specified print writer.
*
* @param writer {@link PrintWriter} to use for output
*/
public void printStackTrace(PrintWriter writer) {
// 스택 트레이스 정보를 지정된 출력 writer에 출력
super.printStackTrace(writer);
}
// ...
// 기타 멤버 변수, 상수 등...
}
RuntimeException 클래스는 Exception 클래스를 상속하고 있으며, 예외 처리에 필요한 생성자와 메서드를 상속받아 사용합니다. 위의 예시에서는 RuntimeException 클래스의 생성자들이 정의되어 있습니다.
RuntimeException 클래스는 주로 프로그래밍 오류와 관련된 예외를 나타내는 데 사용됩니다. 이러한 예외는 개발자의 실수에 의해 발생하는 경우가 많으며, 예측하기 어렵고 컴파일 단계에서 확인하기 어렵습니다.
주의할 점은 RuntimeException과 그 하위 클래스들은 예외 처리를 강제화하지 않습니다. 개발자가 예외를 처리하거나 예외를 전파하는 것은 선택 사항입니다. 따라서 이러한 예외를 사용할 때는 예외 상황에 대한 적절한 처리를 고려하여 프로그램의 안정성을 유지해야 합니다.
자바에서 RuntimeException과 그 하위 클래스들을 Unchecked Exception으로 분류한 이유는 다음과 같습니다:
1. 프로그래밍 오류: RuntimeException은 주로 프로그래밍 오류를 나타내는 예외입니다. 이러한 오류는 개발자의 실수에 의해 발생하는 경우가 많으며, 컴파일 단계에서 확인하기 어렵습니다. 예를 들어, NullPointerException, ArrayIndexOutOfBoundsException, ClassCastException 등이 RuntimeException의 하위 클래스로 분류됩니다. 이러한 예외들은 코드 상의 오류나 잘못된 사용으로 발생하며, 미리 예측하고 처리하기 어렵습니다.
2. 예외 처리 강제화 제외: RuntimeException과 그 하위 클래스들은 예외 처리를 강제화하지 않습니다. Checked Exception과는 달리, 개발자가 명시적으로 예외를 처리하거나 예외를 전파하는 것이 강제되지 않습니다. 이는 개발자가 예외 처리에 대한 부담을 덜어주고 코드의 가독성을 향상시킵니다.
3. 예외 처리 유연성: Unchecked Exception인 RuntimeException과 그 하위 클래스들은 예외 처리를 강제화하지 않기 때문에 개발자가 예외 처리에 유연성을 가질 수 있습니다. 개발자는 예외를 처리하거나 처리하지 않고 상위 호출자로 전파하는 선택을 할 수 있습니다. 이는 예외 처리를 보다 유연하게 할 수 있게 합니다.
4. 일반적인 예외 상황: RuntimeException과 그 하위 클래스들은 일반적인 예외 상황을 나타내는데 사용됩니다. 이러한 예외는 주로 코드에서 잘못된 사용, 잘못된 인자 전달, 부적절한 상태 등을 나타냅니다. 이러한 예외들은 개발자가 코드를 작성하는 과정에서 예상하고 대응할 수 있으며, 컴파일러가 강제적인 예외 처리를 요구하지 않아도 되는 경우가 많습니다. Unchcked Exception으로 분류된 RuntimeException과 그 하위 클래스들은 예외 처리에 있어서 개발자에게 유연성과 편의성을 제공합니다. 그러나 주의해야 할 점은 Unchecked Exception도 예외 상황에 대한 적절한 처리가 필요하며, 코드 안정성을 유지하기 위해 예외 처리를 고려해야 한다는 것입니다.
Other Exception
Checked Exception은 RuntimeException을 상속받지 않는 예외 클래스들을 포함하는 범주입니다. Checked Exception은 컴파일러가 예외 처리를 강제화하며, 개발자는 해당 예외를 명시적으로 처리하거나 예외를 전파해야 합니다. 이에 따라 Checked Exception에는 몇 가지 특징이 있습니다:
1. 예외 처리 강제화: Checked Exception은 컴파일러가 예외 처리를 강제화합니다. 개발자는 예외를 처리하는 코드를 작성하거나, 해당 예외를 throws 선언을 통해 호출자에게 전파해야 합니다. 이는 예외에 대한 명시적인 처리를 유도하여 안정성을 높이는 데 도움을 줍니다.
2. 컴파일 에러 발생: Checked Exception을 처리하지 않거나 전파하지 않으면 컴파일 에러가 발생합니다. 이는 예외를 무시하거나 처리하지 않고 코드를 실행할 수 없게 만들어 프로그래머가 예외 처리에 대한 책임을 인식하도록 합니다.
3. 외부 리소스와의 상호 작용: Checked Exception은 주로 외부 리소스와의 상호 작용에서 발생하는 예외로 사용됩니다. 파일 I/O, 네트워크 통신, 데이터베이스 액세스 등에서 예외가 발생할 수 있으며, 이러한 예외들은 개발자가 예측하고 대응할 수 있는 상황입니다.
대표적인 Checked Exception의 예시로는 IOException, SQLException, FileNotFoundException 등이 있습니다. 이러한 예외들은 주로 외부 리소스 액세스와 관련된 작업에서 발생하며, 코드에서 명시적인 예외 처리를 수행해야 합니다.
Checked Exception은 컴파일러가 예외 처리를 강제화하므로 예외에 대한 적절한 처리를 고려하여 프로그램의 안정성과 신뢰성을 유지하는 데 도움을 줍니다.
※JVM은 실행 중인 스레드에서 처리되지 않은 예외(uncaught exception)가 발생할 경우, 등록된 기본 또는 사용자 정의 UncaughtExceptionHandler를 통해 이를 처리합니다. UncaughtExceptionHandler는 스레드에서 처리되지 않은 예외를 잡아내고 특정 동작을 수행하는 인터페이스입니다.
기본적으로 JVM은 스레드에서 처리되지 않은 예외가 발생하면 해당 스레드의 ThreadGroup에 등록된 기본 UncaughtExceptionHandler를 호출합니다. 기본 UncaughtExceptionHandler는 예외를 적절히 처리하지 않고, 단순히 예외 정보를 출력한 후 프로그램을 종료시킵니다.
개발자는 Thread 클래스의 setDefaultUncaughtExceptionHandler() 메서드를 사용하여 기본 UncaughtExceptionHandler를 변경할 수 있습니다. 또는 스레드마다 개별적으로 setUncaughtExceptionHandler() 메서드를 사용하여 해당 스레드의 UncaughtExceptionHandler를 설정할 수도 있습니다.
다음은 UncaughtExceptionHandler를 사용하여 예외를 처리하는 간단한 예제 코드입니다:
public class UncaughtExceptionExample {
public static void main(String[] args) {
Thread.setDefaultUncaughtExceptionHandler((thread, throwable) -> {
System.out.println("Uncaught exception occurred in thread: " + thread.getName());
throwable.printStackTrace();
// 추가적인 예외 처리 또는 종료 등의 동작을 수행할 수 있습니다.
});
// 예외가 발생하는 스레드
Thread thread = new Thread(() -> {
throw new RuntimeException("Uncaught exception occurred!");
});
thread.start();
}
}
위의 예제에서는 setDefaultUncaughtExceptionHandler() 메서드를 사용하여 기본 UncaughtExceptionHandler를 설정하고 있습니다. 설정된 핸들러는 예외가 발생한 스레드와 예외 정보를 출력하는 동작을 수행합니다. 추가적인 예외 처리 또는 프로그램 종료와 같은 동작을 수행하려면 해당 핸들러 내에서 구현할 수 있습니다.
UncaughtExceptionHandler를 사용하여 예외를 처리하면 예외가 스레드에서 처리되지 않고 전파되는 경우에 대응할 수 있으며, 예외 정보를 로깅하거나 예외 상황에 대한 추가 조치를 취할 수 있습니다.
'Java' 카테고리의 다른 글
Java Collection Framework-1 (0) | 2024.04.09 |
---|---|
Functional Interface (0) | 2024.04.09 |
Callable & ExecutorService (0) | 2024.04.09 |
Generics 4 (0) | 2024.04.09 |
Jenerics 3 (0) | 2024.04.09 |