티스토리 뷰
어플리케이션을 개발하고 운영에 있어서 예외와 에러는 매우 중요한 요소이기에 예외와 에러에 대한 차이점과 예외의 종류 및 처리 방법에 대해 알아보려고 한다.
Error와 Exception
Error(에러)는 프로그램 실행 중에 언제 발생할지 예측하거나 제어할 수 없는 오류이다.
주로 하드웨어 수준에서 발생하며 프로그램의 실행이 중단되어 대부분은 정상 상태로 돌릴 수 없다.
예를 들어, 메모리 부족이나 시스템 충돌에 의해 발생한다.
Exception(예외)는 프로그램의 실행 중에 발생할 수 있는 예측 가능한 오류이다.
예외는 예외 처리를 통해 프로그램이 종료되지 않고 정상 실행 상태를 유지할 수 있다.
예를 들어, 사용자의 잘못된 조작 또는 개발자의 잘못 된 코딩으로 인해 발생한다.
⭐️ 에러와 예외를 나눌 수 있는 기준은 복구 여부이며, 에러는 복구 가능성이 거의 없고 예외는 복구가 가능하다. ⭐️
Exception 의 종류
Exception 은 일반예외와 실행예외 두가지 종류로 나뉘며, 기준은 RuntimeException의 상속 여부이다.

✍︎ 일반예외는 컴파일하는 과정에서 예외 처리 코드가 있는지 확인하기 때문에 checked exception 또는 컴파일러 체크 예외(compile-time exception)이라고도 부른다.
✍︎ 실행예외는 컴파일하는 과정에서 예외 처리 코드가 있는지 확인하지 않기 때문에 unchecked exception이라고도 부른다.
주로 프로그램이 실행하는 과정에서 잘못된 데이터를 제공하였을 때 발생한다.
그렇기 때문에 예외가 발생하지 않도록 코드를 작성하거나, 예외가 발생할 수 있는 코드에 대해서 미리 예외 처리를 해줘야 한다.
Exception 처리
자바에서 Exception 을 처리하는 방법은 2가지이다.
1. try-catch-finally
public class Main {
public static void main(String[] args) {
int[] arr = {1, 2, 3};
try {
int value = arr[100];
} catch (ArrayIndexOutOfBoundsException e) {
System.out.println("배열의 인덱스 범위를 초과하였습니다. 인덱스를 다시 설정하세요")
} finally {
System.out.println("또 도전하세요");
}
}
}
try 블록은 예외가 발생할 가능성이 있는 코드를 포함한다.
catch 블록은 try 블록에서 발생한 특정 예외를 처리한다. 여러 개의 catch 블록을 사용해서 다양한 예외를 각각 다르게 처리할 수 있다.
finally 블록은 예외 발생 여부와 상관 없이 항상 실행된다. 만약 예외가 발생하지 않고 try 블록에서 리턴값이 있을경우 finally 블록이 실행되고 나서 값이 리턴된다.
2. throws
public class Main {
public static void main(String[] args) {
try {
int value = getNum();
} catch (ArrayIndexOutOfBoundsException e) {
System.out.println("배열의 인덱스 범위를 초과하였습니다. 인덱스를 다시 설정하세요");
} finally {
System.out.println("또 도전하세요");
}
}
private static int getNum(int[] arr, int index) throws ArrayIndexOutOfBoundsException {
return arr[index]; //여기서 예외 발생
}
}
throws 를 사용하면 예외는 해당 코드를 호출한 곳에서 처리하게 된다.
throws 키워드가 붙어있는 메서드는 반드시 상위 메서드의 try 블록 내에서 호출되어야하고, catch 블록에서 떠넘겨 받은 예외를 처리해야한다.
호출한 메서드는 try-catch로 예외를 처리하도록 되어있던지, 아니면 동일하게 throws 를 사용해서 상위 메서드로 던질 수 있다. 호출한 곳에서도 동일하게 throws 를 사용해서 예외를 던지고 계속 던지다보면 결국 JVM이 예외를 처리하게 된다.
(보통 일반예외는 try-catch 블록을 사용해서 예외를 처리하거나, throws 키워드를 사용해서 예외를 처리할 수 있도록 컴파일러가 알려준다.)
Exception 의 다중 catch 시 주의해야할 점
try 블록 내부에서는 다양한 예외가 발생할 수 있기에, 다중 catch 블록을 작성해야한다.
public class Main {
public static void main(String[] args) {
int[] arr = {1, 2, 3};
Scanner sc = new Scanner(System.in);
String idxString = sc.nextLine();
try {
int idx = Integer.parseInt(idxString);
int value = arr[idx];
} catch (ArrayIndexOutOfBoundsException e) {
System.out.println("배열의 인덱스 범위를 초과하였습니다. 인덱스를 다시 설정하세요");
} catch(NumberFormatException e) {
System.out.println("숫자가 아닙니다");
} finally {
System.out.println("또 도전하세요");
}
}
}
미리 선언된 배열의 요소에 접근하기 위해서 사용자로부터 인덱스 번호를 입력 받도록하였다.
try 블록 내에서 발생할 수 있는 예외로는 배열의 인덱스 범위 초과와 숫자 변환 실패 예외이다.
총 2개의 예외가 발생하는 코드가 있다하더라도 예외가 발생한 코드가 있다면 해당 지점에서 실행을 멈추고 catch 블록으로 이동한다. 즉, 예외가 여러개가 동시에 발생할 수 없다는 것이다.
다중 catch 블록을 작성할 때에는 위에서부터 하위 클래스 -> 상위 클래스 순서로 작성해야한다. try 블록에서 예외가 발생하였을 때, catch 블록은 순차적으로 검색하기 때문에 만약 상위 클래스가 하위 클래스보다 위에 작성되어있다면 하위 클래스의 catch는 실행되지 않는다.
Custom Exception
사용자는 자바에서 기본 제공되는 예외 클래스 외에도 어플리케이션의 요구 사항이나 비즈니스 로직을 반영하여 예외 클래스를 직접 정의할 수 있다. 사용자 정의 예외를 통해 오류의 종류를 명확히 정의할 수 있어서 예외의 이름만으로도 어떤 문제가 발생하였는지 쉽게 이해하고 디버깅할 수 있다. 사용자 정의 예외는 Exception 또는 RuntimeException 클래스를 상속하여 생성할 수 있다.
//일반 예외 (checked exception)
public class FuelEmptyException extends Exception {
public FuelEmptyException() {}
public FuelEmptyException(String message) {
super(message);
}
}
//실행 예외 (unchecked exception)
public class FuelEmptyException extends RuntimeException {
public FuelEmptyException() {}
public FuelEmptyException(String message) {
super(message);
}
}
Exception 클래스를 상속받으면, 일반 예외로 분류되어 컴파일 시점에 예외 처리를 하도록 강제한다.
RuntimeException 클래스를 상속받으면, 실행 예외로 분류되어 컴파일 시점에 예외 처리하도록 알려주지 않기에 필요한 경우에 적절하게 처리하면 된다.
public class Main {
public static void main(String[] args) {
try {
drive();
} catch (FuelEmptyException e) {
System.out.println(e.getMessage());
}
}
//exception을 상속받은 FuelEmptyException
private static void drive(double fuelLevel) throws FuelEmptyException {
if (fuelLevel <= 0) {
throw new FuelEmptyException("연료가 부족합니다");
}
}
}
일반 예외를 상속받은 FuelEmptyException 을 처리하는 방법이다. drive 메서드에서 연료가 0 이하일 때에는 FuelEmptyException 을 발생시켰다. 해당 메서드는 throws 키워드를 사용하여 호출한 곳에서 예외 처리를 하도록 하고, 호출한 곳은 try-catch 블록으로 예외 처리를 해야한다. (상위 계층으로 또 throws 를 할 수 있지만.. 계속 던지다 보면 JVM이 처리하겠지만 더 나은 예외처리로 원하는 출력문을 얻는 것이 중요하다.) 그렇지 않으면 컴파일러는 무조건 예외 처리를 하라고 알려줄 것이다.
예외는 예측 가능한 오류 상황으로 복구가 가능하고, 오류는 예측하기 어렵고 제어할 수 없는 오류 상황으로 복구가 불가능에 가깝다.
예외는 RuntimeException 상속 여부 기준으로 일반예외와 실행예외로 나뉜다.
RuntimeException을 던지지말고 사용자 정의 예외를 만들어서 예외를 명확하게 처리해야한다.
'Language > Java' 카테고리의 다른 글
List Collection (0) | 2024.11.07 |
---|---|
Object 클래스 (0) | 2024.11.05 |
상속에 대하여 (0) | 2024.10.31 |
인터페이스에 대하여 (0) | 2024.10.27 |
추상클래스와 인터페이스 (0) | 2024.10.22 |
- Total
- Today
- Yesterday
- 인스턴스변수
- Hash
- syncronized
- AutoConfiguration
- fail-safe
- Caching
- HashSet
- fail-fast
- Security
- object
- 정적변수
- Sticky Session
- nginx
- HashMap
- @conditional
- 추상클래스
- Spring
- Load Balancer
- JPA
- 티스토리챌린지
- 자동구성
- 고정 세션
- 다중화
- spring boot
- java
- 오블완
- 인터페이스
- nosql
- 로드 밸런서
- Red-Black Tree
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | 5 | ||
6 | 7 | 8 | 9 | 10 | 11 | 12 |
13 | 14 | 15 | 16 | 17 | 18 | 19 |
20 | 21 | 22 | 23 | 24 | 25 | 26 |
27 | 28 | 29 | 30 |