프로그래밍의 오류 종류
프로그램에서 오류가 발생하면 시스템 레벨에서 프로그램에 문제를 야기하여 원치 않는 버그를 일으키거나, 심각하면 실행 중인 프로그램을 강제로 종료시키도 한다.
프로그램 오류의 원인으로는 정말 다양한 상황이 있을 수 있다. 내부적인 요인으로는 프로그램 설계 로직에 구멍이 있어서 그럴수도 있고, 외부적인 요인으로는 프로그램 자체 문제가 아닌 하드웨어에서 문제가 생겨 프로그램에 오류가 발생할 수 도 있다.
실제로 프로그래밍 할때 겪어본 오류의 종류로는 단순 오타 서부터 시작해서 파일을 불러오는데 정작 파일이 없거나 등 잘못된 설계로 인한 메모리 오류까지 범위도 다양하다.
프로그래밍에서는 이러한 오류를 발생 시점에 따라 크게 3가지로 나눈다.
- 컴파일 에러(compile-time error) : 컴파일시에 발생하는 에러
- 런타임 에러(runtime error) : 실행시에 발생하는 에러
- 논리적 에러(logical error) : 실행은 되지만 의도와 다르게 동작하는것
논리 에러 (Logic Error)
논리적 에러는 이른바 '버그' 라고 생각하면 된다.
프로그램이 실행하고 작동하는데는 아무런 문제가 없는 오류이지만, 결과가 예상과 달라 사용자가 의도한 작업을 수행하지 못하게 되어 서비스 이용에 지장이 생길 수 있다.
예를들어 재고량이 음수가 나오면 안되는데 음수가 나와버리는 경우, 게임 캐릭터가 피가 0이어도 죽지 않는 경우를 들 수 있다.
논리적 오류는 컴퓨터 입장에서는 프로그램이 멀쩡히 돌아가는 것이니 에러 메시지를 알려주지 않는다. 따라서 개발자는 프로그램의 전반적인 코드와 알고리즘을 체크 필요가 있다.
컴파일 에러 (Compillation Error)
컴파일 에러는 컴파일 단계에서 오류 발견하면 컴파일러가 에러 메시지 출력해주는 것을 말한다.
컴파일 에러 발생의 대표적인 원인으로 문법 구문 오류(syntax error)를 들 수 있다.
예를들어 에디터에서 코딩을 할때 맞춤법, 문장부호(;), 선언되지 않은 변수 사용을 하면 아래와 같이 빨간줄로 잘못 되었다라고 컴파일 에러를 일으킨다.
※ 참고
컴파일 에러는 소스 코드를 javac.exe로 컴파일 하는 과정에서 컴파일러가 전반적인 코드를 체크해서 에러 메세지를 보여주는 형태이지만, IDE에서는 일정 주기로 계속 자동으로 컴파일을 해주기 때문에 바로바로 문제를 알 수 있는 것이다.
하지만 컴파일 에러는 그렇게 심각하게 볼 오류 종류는 아니다.
왜냐하면 컴파일 에러가 있다는 것은, 곧 컴파일이 안된다는 의미이며, 이는 즉 프로그램이 만들어지지 않아 프로그램 실행 자체가 불가하기 때문이다. 따라서 개발자는 차후에 일어날 에러를 컴파일러가 미리 멘토링 한다고 생각하며 코드를 수정하면 될 일이다.
런타임 에러 (Runtime Error)
컴파일 에러를 꼼꼼하게 잡아 컴파일에는 문제가 없더라도, 프로그램 실행 중에 에러가 발생해서 잘못된 결과를 얻거나, 혹은 외부적인 요인으로 기계적 결함으로 프로그램이 비정상적으로 종료될 수 있다.
이것이 우리가 집중적으로 파헤쳐 봐야 할 실행 오류(런타임 에러) 이다.
대체로 개발 시 설계 미숙(논리적)으로 발생하는 에러가 대부분이며, 런타임 에러 발생 시 프로그래머가 역추적해서 원인 확인해야 한다. 따라서 이러한 잠재적인 런타임 에러를 방지하기 위해서는 프로그램의 실행 도중 발생할 수 있는 경우의 수를 고려하여 이에 대한 대비를 철저히 해야 한다.
오류(error) 와 예외(exception)
자바 프로그래밍에서는 실행 시(runtime) 발생할 수 있는 오류를 '에러(error)'와 '예외(exception)' 두가지로 구분 하였다.
- 에러(error) : 프로그램 코드에 의해서 수습될 수 없는 심각한 오류
- 예외(exception) : 프로그램 코드에 의해서 수습될 수 있는 다소 미약한 오류
Error은 메모리 부족(OutOfMemoryError)이나 스택오버플로우(StackOverflowError)와 같이 일단 발생하면 복구할 수 없는 심각한 오류이고 예측이 불가능한 녀석이다. 즉, 에러는 JVM 실행에 문제가 생긴 것이므로 개발자가 대처할 방법이 없다.
반면 Exception은 발생하더라도 수습될 수 있는 비교적 덜 심각한 오류를 말한다. 즉 알고리즘 오류로 Exception 예외가 계속 발생한다고 해도 Error 처럼 프로그램이 죽거나 그럴경우는 적기 때문이다.
그렇다고 예외(Exception)가 단어의 어감 처럼 가볍게 볼 녀석은 아니다. 예외에 대한 오류 처리를 제대로 하지 않으면 전혀 예상하지 못한 오류 발생으로 프로그램에 작지 않은 문제를 야기하기 때문이다.
대부분의 예외(Exception)는 개발자가 구현한 로직에서 발생한 실수나 사용자의 영향에 의해 발생한다. 그래서 예외는 에러와 달리 문제가 발생하더라도 이에 대한 대응 코드를 미리 작성해 놓음으로써 어느정도 프로그램의 비정상적인 종료 혹은 동작을 막을 수 있다.
이 예외에 대한 대응 코드가 바로 자바의 예외 처리 문법(try - catch)이다.
따라서 개발자는 예외 처리(exception handling)를 통해 언제나 예외 상황을 처리하여 프로그램이 종료되는 일이 없도록 코드의 흐름을 바꿀 필요가 있다.
※ 참고
[ 예외 처리(exception handling) ]
예외 처리란 프로그램 실행 시 발생할 수 있는 예기치 못한 예외의 발생에 대비한 코드를 작성하는 행위를 말한다.
프로그램 실행도중에 발생하는 에러는 어쩔 수 없지만, 예외는 프로그래머의 실력에 따라 충분히 포괄적으로 방지할 수 있기 때문이다. 따라서 예외 처리의 목적은 예외의 발생으로 인한 실행중인 프로그램의 갑작스런 비정상 종료를 막고, 정상적인 실행상태를 유지하는 것이다.
자바의 예외(Exception) 클래스
예외 클래스의 계층 구조
자바에서는 오류를 Error와 Exception으로 나누었고 이들을 클래스로 구현하여 처리하도록 하였다.
익숙한 IllegalArgumentException을 비롯해 NullPointerException과 IOException도 모두 클래스이다.
JVM은 프로그램을 실행하는 도중에 예외가 발생하면 해당 예외 클래스로 객체를 생성하고서 예외 처리 코드에서 예외 객체를 이용할 수 있도록 해준다. 나중에 배울 getMessage() 나 printStackTrace() 메서드 역시 예외 객체의 메서드를 가져와 오류를 출력하는 것이다.
자바의 오류 클래스 계층 구조를 살펴보면 다음과 같이 구성 되어 있다.
Error 클래스는 위에서 언급한 바와 같이 외부적인 요인으로 인해 발생하는 오류이기 때문에 개발자가 대처 할 수는 없다. 따라서 우리가 중점적으로 봐야할 클래스는 바로 Exception 클래스이다.
※ 참고
[ Throwable 클래스란? ]
오류와 예외 모두 자바의 최상위 클래스인 Object를 상속받는다.
그리고 그 사이에는 Throwable 클래스와 상속관계가 있는데, Throwable 클래스의 역할은 오류나 예외에 대한 메시지를 담는 것이다. 대표적으로 getMessage() 와 printStackTrace() 메서드가 바로 이 클래스에 속해 있다.
당연히 Throwable을 상속받은 Error와 Exception 클래스에서도 위 두 메서드를 사용할수 있게 된다.
위의 예외 클래스 계층 구조는 조금 보기 복잡하니 심플하게 보면 아래와 같다.
자바에서 다루는 모든 예외 오류는 Exception 클래스에서 처리한다. 그리고 아래의 Exception 클래스 트리 구조를 보면 파랑색과 붉은색으로 색깔별로 구분됨을 볼 수 있는데, 이것은 컴파일 에러와 런타임 에러를 따로 클래스로 구분했기 때문이다.
즉, Exception 클래스는 다시 RuntimeException(런타임 에러를 다룸)과 그 외의 자식 클래스 그룹(컴파일 에러를 다룸)으로 나뉘게 된다.
- Exception 및 하위 클래스 : 사용자의 실수와 같은 외적인 요인에 의해 발생하는 컴파일시 발생하는 예외
- 존재하지 않는 파일의 이름을 입력 (FileNotFoundException)
- 실수로 클래스의 이름을 잘못 기재 (ClassNotFoundException)
- 입력한 데이터 형식이 잘못된 경우 (DataFormatException)
- RuntimeException 클래스 : 프로그래머의 실수로 발생하는 예외
- 배열의 범위를 벗어남 (IndexOutOfBoundsException)
- 값이 null인 참조 변수의 멤버를 호출 (NullPointerException)
- 클래스 간의 형 변환을 잘못함 (ClassCastException)
- 정수를 0으로 나누는 산술 오류 (ArithmeticException)
런타임 예외 클래스 종류
코딩하다 보면 자주 보게될 몇가지 중요한 실행(runtime) 예외 클래스에 대해 간단히 정리해보자.
다음 실행 예외 종류를 보고 언제 발생되고, 어떤 오류 메시지가 출력되는지 잘 알아보도록 하자. 숙련된 개발자라면 오류메시지를 보고 바로 오류를 해결할 수 있어야 한다.
ArrayIndexOutOfBoundsException
- 배열의 범위를 넘어선 인덱스를 참조할 때 발생하는 에러
public class RuntimeErrorsExample {
public static void main(String[] args) {
int ary[] = {4, 6, 2}; // ary[0] ~ ary[2]
system.out.println("Result: " + ary[3]);
}
}
ArithmeticException
- 정수를 0으로 나눌 때 발생하는 에러
System.out.println(12/0);
NullPointException
- null 객체에 접근해서 method를 호출하는 경우 발생하는 에러 (객체가 없는 상태에서 객체를 사용하려 했으니)
- 자바 프로그램에서 가장 빈번하게 발생하는 에러
String s = null;
System.out.println(s.length());
NumberFormatException
- 정수가 아닌 문자열을 정수로 변환할 때 예외 발생
- 개발을 하다보면 문자열로 되어있는 데이터를 숫자타입으로 변경하는 경우가 자주 발생하는데, 숫자타입으로 변경할 수 없는 문자를 치환시키려고 하면 발생하는 대표적인 에러
String stringNumber = "3.141592";
int num = Integer.parseInt(stringNumber); // "3.141592"를 정수로 변환할 때 NumberFormatException 예외 발생
// float num = Float.parseFloat(stringNumber); (parsefloat 으로 변경해 주어야 함)
ClassCastException
- 타입 변환은 상위 클래스와 하위 클래스간의 상속 관계 이거나 혹은 구현 클래스와 인터페이스간 일 때만 가능하다.
- 상속, 구현 관계 아니면 클래스는 다른 클래스로 타입을 변환할 수 없는데, 이 규칙을 무시하고 억지로 타입을 변환시킬경우 발생하는 에러이다.
Object x = new Integer(0);
System.out.println( (String)x ); // 정수 객체를 스트링 객체로 캐스팅
InputMismatchException
- 의도치 않는 입력 오류 시 발생하는 예외
import java.util.Scanner;
import java.util.InputMismatchException;
public class InputException {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
System.out.println("정수 3개를 입력하세요");
int n = scanner.nextInt(); // 정수 입력 -> 사용자가 문자를 입력하면 예외 발생
scanner.close();
}
}
컴파일 예외 클래스 종류
IOException
- 컴퓨터 프로그램이 실행될 때 언제 어떤 문제가 발생할지 모르는 일이기 때문에, 컴퓨터와 상호소통 하는 I/O(입력과 출력)에 관해서는 발생할 수 있는 예외에 대해서 까다롭게 규정하고 있다.
- 그래서 입력과 출력을 다루는 메서드에 예외처리(IOException)가 없다면 컴파일 에러가 발생하게 된다.
- 아래 코드는 write() 메소드에서 발생할 수 있는 IOException에 대한 예외를 처리하지 않았으므로 컴파일 시 오류가 발생한다.
- 참고로 print() , println() 메서드를 출력했는데 아무 문제가 없는 이유는 자체적으로 컴파일 예외처리를 미리 해놓았기 때문이다.
public class Exception01 {
public static void main(String[] args) {
byte[] list = {'a', 'b', 'c'};
System.out.write(list);
}
}
FileNotFoundException
- 파일에 접근하려고 하는데 파일을 찾지 못했을 때 발생하는 에러
import java.io.BufferedReader;
import java.io.FileReader;
public class Main {
public static void main(String[] args) throws Exception {
BufferedReader br = new BufferedReader(new FileReader("test.txt")); // 만일 폴더에 test.txt 파일이 없는데 가져올 경우
br.readLine();
br.close();
}
}
Checked Exception / Unchecked Exception
자바의 예외(Exception)는 컴파일 에러와 런타임 에러로 구분된다는 것 쯤은 알고 있을 것이다.
그런데 또다시 예외 종류로서 Checked Exception과 Unchecked Exception 로 나뉜다.
Checked Exception은 컴파일 예외클래스들을 가리키는 것이고, Unchecked Exception은 런타임 예외클래스들을 가리키는 것으로 보면 된다. 쉽게 말하자면, RuntimeException을 상속하지 않은 클래스는 Checked Exception, 반대로 상속한 클래스는 UnChecked Exception으로 분류할 수 있다.
그냥 컴파일 / 런타임 예외로 분류하면 되지, 또다시 Checked / Unchecked Exception으로 재분류 한 이유는 코드 관점에서 예외 처리 동작을 필수 지정 유무에 따라 나뉘기 때문이다.
구분 | Checked Exception | UnChecked Exception |
확인 시점 | 컴파일(Compile) 시점 | 런타임(Runtime) 시점 |
처리 여부 | 반드시 예외 처리해야 한다. | 명시적으로 하지 않아도 된다. |
트랜잭션 처리 | 예외 발생 시 롤백(rollback) 하지 않음. | 예외 발생 시 롤백(rollback)해야 함. |
종류 | Exception을 상속 받는 클래스중 RuntimeException을 제외한 모든 예외 클래스 IOException SQLException |
RuntimeException과 이를 상속받는 모든 클래스 NullPointerException IndexOutOfBoundException |
여기서 RuntimeException은 Exception 클래스의 서브 클래스이기 때문에 Exception의 일종이기도 하지만 자바에서는 RuntimeException과 이를 상속한 클래스를 조금 특별하게 취급한다. 명시적으로 예외 처리를 하지 않아도 되기 때문이다.
코드에서 명시적 예외 처리 유무
두 Checked / Unchecked Exception의 가장 핵심적인 차이는 '반드시 예외 처리를 해야 하는가?' 이다.
Checked Exception은 체크 하는 시점이 컴파일 단계이기 때문에, 별도의 예외 처리를 하지 않는다면 컴파일 자체가 되지 않는다.
따라서 Checked Exception이 발생할 가능성이 있는 메소드라면 반드시 로직을 try - catch로 감싸거나 throws로 던져서 처리해야 한다.
// try - catch 로 예외처리
public static void fileOpen() {
// 파일을 열고 쓰고 닫는 아주 단순한 로직이어도 이에 대한 예외는 checked exception으로 분류 되기 때문에 반드시 try - catch로 감싸주어야 한다.
try {
FileWriter file = new FileWriter("data.txt");
file.write("Hello World");
file.close();
} catch(IOException e) {
e.printStackTrace();
}
}
// -------------------------------------------------------------------------
// throws 로 예외처리
public static void fileOpen() throws IOException {
// 파일을 열고 쓰고 닫는 아주 단순한 로직이어도 이에 대한 예외는 checked exception으로 분류 되기 때문에 반드시 try - catch로 감싸주어야 한다.
FileWriter file = new FileWriter("data.txt");
file.write("Hello World");
file.close();
}
반면에 Unchecked Exception의 경우는 명시적인 예외 처리를 하지 않아도 된다.
Unchecked Exception도 예외이긴 하지만, 개발자의 충분한 주의로 미리 회피할 수 있는 경우가 대부분이라 그나마 상대적으로 미약한 예외로 처리되어 자바 컴파일러는 별도의 예외 처리를 하지 않도록 설계 되어 있기 때문이다.
따라서 에러를 일부러 일으키는 코드가 있더라도 try - catch 처리하지 않더라도 컴파일도 되고 실행까지 가능하다.
public class Main {
public static void main(String[] args) {
// 일부러 예외를 무한적으로 발생시켜도 에러로그만 쌓이지 프로그램 자체는 왠만해선 죽지는 않는다. (미약한 오류이기 때문에)
while(true) {
String s = null;
s.length(); // NullPointException - Unchecked Exception 이어서 예외를 발생시키는 옳지 못한 코드임에도 불구하고 빨간줄이 없다
}
}
}
Rollback 여부
@Service
@RequiredArgsConstructor
@Transactional
public class MemberService {
private final MemberRepository memberRepository;
// (1) RuntimeException 예외 발생
public Member createUncheckedException() {
final Member member = memberRepository.save(new Member("yun"));
if (true) {
throw new RuntimeException();
}
return member;
}
// (2) IOException 예외 발생
public Member createCheckedException() throws IOException {
final Member member = memberRepository.save(new Member("wan"));
if (true) {
throw new IOException();
}
return member;
}
}
(1) RuntimeException 예외 발생 발생시키면 yun이라는 member는 rollback이 진행된다. 하지만
(2) IOException 예외 발생이 되더라도 wan은 rollback이 되지 않고 트랜잭션이 commit까지 완료한다.
--- Ynu Log
Hibernate:
/* insert yun.blog.exception.member.Member */
insert
into
member
(id, name)
values
(null, ?)
2019-05-16 00:55:16.117 TRACE 49422 --- [nio-8080-exec-2] o.h.type.descriptor.sql.BasicBinder : binding parameter [1] as [VARCHAR] - [yun]
2019-05-16 00:55:16.120 ERROR 49422 --- [nio-8080-exec-2] o.a.c.c.C.[.[.[/].[dispatcherServlet] : Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed; nested exception is java.lang.RuntimeException] with root cause
java.lang.RuntimeException: null
--- Wan Log
Hibernate:
/* insert yun.blog.exception.member.Member */
insert
into
member
(id, name)
values
(null, ?)
2019-05-16 00:55:43.931 TRACE 49422 --- [nio-8080-exec-4] o.h.type.descriptor.sql.BasicBinder : binding parameter [1] as [VARCHAR] - [wan]
2019-05-16 00:55:43.935 ERROR 49422 --- [nio-8080-exec-4] o.a.c.c.C.[.[.[/].[dispatcherServlet] : Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception
java.io.IOException: null
at yun.blog.exception.member.MemberService.createCheckedException(MemberService.java:27) ~[classes/:na]
로그 메시지를 보면 member yun, wan 모두 insert 쿼리는 보이지만 yun rollback이 진행되고 wan은 rollback이 되지 않고 commit까지 된다.
💡 왜 Checked Exception은 Rollback되지 않는 것일까?
기본적으로 Checked Exception는 복구가 가능하다는 메커니즘을 가지고 있다. 예를 들어서 특정 이미지 파일을 찾아서 전송해주는 함수에서 이미지를 찾지 못했을 경우 기본 이미지를 전송하는 복구 전략을 가질 수 있게 된다.
public void sendFile(String fileName){
File file;
try {
file = FileFindService.find(fileName);
} catch (FileNotFoundException e){ // FileNotFoundException은 IOException으로 checked exception이다.
// 파일을 못찾았으니 기본 파일을 찾아서 전송 한다
file = FileFindService.find("default.png");
}
send(file);
}
"기본적으로 난(컴퓨터) 컴파일 단계에서 Exception을 알려줬어!! 그래서 네가 복구를 작업을 진행했을 수도 있으니까 Rollback은 진행하지 않을게"라는 의미가 있다고 생각한다. (주관적인 생각.)
하지만 이런 식의 예외는 복구하는 것은 아니라 일반적인 코드의 흐름으로 제어해야 한다.
public void sendFile(String fileName){
if(FileFindService.existed(filename)){
// 파일이 있는 경우 해당 파일을 찾아서 전송
send(FileFindService.find(fileName));
}else{
// 파일이 있는 없는 경우 기본 이미지 전송
send(FileFindService.find("default.png"));
}
}
하지만 현실은…
하지만 우리가 일반적으로 Checked Exception 예외가 발생했을 경우 복구 전략을 갖고 그것을 복구할 수 있는 경우는 그렇게 많지 않다.
유니크해야 하는 이메일 값이 중복돼서 SQLException이 발생하는 경우 어떻게 복구 전략을 가질 수 있을까?
유저가 입력했던 이메일 + 난수를 입력해서 insert 시키면 가능은 하겠지만 현실에서는 그냥 RuntimeException을 발생시키고 입력을 다시 유도하는 것이 현실적이다.
여기서 중요한 것은 해당 Exception을 발생시킬 때 명확하게 어떤 예외가 발생해서 Exception이 발생했는지 정보를 전달해주는 것이다. 위 같은 경우에는 DuplicateEmailException (Unchecked Exception)을 발생 시는 것이 바람직하다.
Checked Exception을 만나면 더 구체적인 Unchecked Exception을 발생시켜 정확한 정보를 전달하고 로직의 흐름을 끊어야 한다. 우리는 JPA에 구현체를 가져다 사용하더라도 Checked Exception을 직접 처리하지 않는 이유도 다 적절한 RuntimeException으로 예외를 던져주고 있기 때문이다.
Checked를 Unchecked 예외로 변환하기
앞서 checked exception은 반드시 try - catch 문으로 감싸야된다고 했었다.
하지만 코드마다 일일히 예외처리하는 것도 귀찮고 오히려 가독성을 해친다고 생각할 경우, 그냥 unchecked exception으로 변환시켜 컴파일에게 예외처리를 강제하지 않게 할수있다.
예를 들어 checked exception의 종류의 예외를 포함한 코드를 작성하면 컴파일러가 예외 처리(try - catch)를 강제한다.
가장 대표적인 예로 FileWriter 클래스를 이용해 파일을 불러오는 코드를 작성하면 반드시 try - catch로 감싸주어야 컴파일이 된다.
이런식으로 설계한 이유는, 처음 자바 언어를 개발 했을때 프로그래밍 경험이 적은 사람도 보다 견고한 프로그램을 작성할 수 있도록 유도하기 위해서인데, 실제로 별것 아닌 예외도 checked exception 으로 등록한 것이 꽤 많다.
자바 프로그래밍 언어가 처음 개발되던 1990년대와 지금의 컴퓨터 환경은 많이 달라졌기 때문에, 실제로 런타임 예외로 처리해도 될 것들이 아직도 checked exception으로 등록되어 강제적으로 try - catch 문을 사용해야 하는 불편함이 있고, 또한 로직상 Runtime Exception으로 할 수 밖에 없는 경우가 있기 때문에, 추가된 기법이라고 생각하면 된다.
따라서 연결된 예외(chained exception)을 이용해, checked 예외를 unchecked 예외로 바꾸면 예외처리가 선택적이 되므로 억지로 거추장 스러운 예외처리를 하지 않아도 된다.
class MyCheckedException extends Exception { ... } // checked excpetion
public class Main {
public static void main(String[] args) {
install();
}
public static void install() {
throw new RuntimeException(new IOException("설치할 공간이 부족합니다."));
// Checked 예외인 IOException을 Unchecked 예외인 RuntimeException으로 감싸 Unchecked 예외로 변신 시킨다
}
}
예상 면접 질문 및 답변
Q. 예외(Exception)란?
예외(Exception)란 입력 값에 대한 처리가 불가능하거나, 프로그램 실행 중에 참조된 값이 잘못된 경우 등 정상적인 프로그램의 흐름을 어긋나는 것을 말한다. 자바에서 예외는 개발자가 직접 처리할 수 있기 때문에 예외 상황을 미리 예측하여 핸들링할 수 있다.
Q. 에러(Error)란?
**에러(Error)**는 시스템에 무엇인가 비정상적인 상황이 발생한 경우에 사용된다. 주로 자바 가상머신에서 발생시키는 것이며 예외와 반대로 이를 애플리케이션 코드에서 잡을 수 없다.
Q. Checked Exception에 대해 설명하라
Checked Exception은 RuntimeException을 상속하지 않은 클래스이며, 명시적인 예외 처리를 해야 한다. 컴파일 시점에 확인할 수 있고 트랜잭션 안에서 동작할 때 Checked Exception이 발생하면 롤백(rollback)되지 않는다는 특징이 있다.
Q. UnChecked Exception에 대해 설명하라
UnChecked Exception은 RuntimeException을 상속한 클래스이며, 명시적인 예외 처리를 하지 않는다. 런타임 시점에 확인할 수 있고 트랜잭션 안에서 동작할 때 UnChecked Exception이 발생하면 롤백(rollback)된다는 특징이 있다.
Q. 예외(Checked Exception)를 처리하는 방식에 대해 설명하라
예외 상황을 파악하고 문제를 해결해서 정상 상태로 복구하는 예외 복구 방식, 예외 처리를 직접 담당하지 않고 호출한 쪽으로 넘기는 예외 처리 회피, 적절한 예외로 전환해서 넘기는 예외 전환 방식이 있다.
Q. 올바른 예외 처리 방식
예외 복구 전략이 명확하고 복구가 가능하다면 Checked Excetpion을 try-catch로 잡아서 예외를 복구하는 것이 좋다. 복구가 불가능한 Checked Exception이 발생하면 더 구체적인 UnChecked Exception을 발생시키고 예외에 대한 메시지를 명확하게 전달하는 것이 좋다. 무책임하게 상위 메서드에 throw로 예외를 던지는 것은 상위 메서드의 책임이 증가하기 때문에 좋지 않은 방법이다.
참고