Today I Learned (250709) 5.
예외 (Exception)
- 프로그램이 실행되는 동안 발생할 수 있는 예외적인 상황
- 예외를 처리해주지 않으면 프로그램이 종료되지만, 처리해주면 프로그램이 정상적으로 실행됨
- 모든 종류의 예외는 Exception 클래스를 상속 받아서 구성됨
- Exception 클래스를 상속 받지 않고 Exception 클래스로 객체를 생성해줘도 되지만,
그렇게하면 그 예외가 어떤 타입의 예외인지 알기 어렵기 때문에
예외의 타입을 명확히 하기 위해서 Exception 클래스를 상속 받은 클래스로 객체를 생성해 주는 것이 좋음
var exception = Exception("무슨 예외일까요 ?") // 이렇게 Exception 클래스를 직접 써서 예외 객체를 만들어도 되지만 예외가 발생했을 때 Exception을 보면 어떤 유형의 예외인지 알 수 없음..
예외 종류 - 정의하는 주체에 따라 2가지로 나뉨
- Dart가 미리 정의해 둔 예외
- 사용자가 직접 정의한 예외
1. Dart가 미리 정의해 둔 예외
DeferredLoadException
- 필요한 시점에 로드되도록 설정한 라이브러리가 로드되지 못 했을 때 발생
-
- 라이브러리: 자주 사용하는 코드들을 미리 정의해 두고, 뽑아서 쓸 수 있게 함 !
- 라이브러리를 쓰려면 라이브러리를 불러와야 하는데, 라이브러리를 불러오는 것에 실패하면 예외 발생
DeferredLoadException(String message)
//message에 예외에 대한 설명을 쓰면됨
FormatException
- 데이터가 처리 가능한 형태가 아니어서 데이터를 처리하기 어려울 때 발생
FormatException([String message = "", dynamic source, int? offset])
/* message: 예외에 대한 설명
source: 예외가 발생한 원인이 되는 것
// 오류발생하는모습
String invalidNumber = "abc";
int result = int.parse(invalidNumber);
/* 참고로, int.parse() 는 매개변수에 넣은 문자열을 정수형으로 바꿔줌
매개변수에 넣은 문자열을 정수형으로 바꿀 수 없으면 FormatException 발생
IOException
- 입출력 관련 동작을 하는 중에 발생하는 오류
- 입출력 동작 중에 발생하는 오류 종류
FileSystemException
- 파일을 다룰 때 발생
- 파일에 접근할 수 없는 경우, 파일이 없는 경우, 파일을 찾을 수 없는 경우 정도
HttpException
ProcessException
SignalException
SocketException
StdinException
StdoutException
TlsException
WebSocketException
IOException()
OSError
- 운영체제 레벨에서 발생하는 오류
- 운영체제로부터 받은 오류에 대한 정보를 들고 있음
OSError([String message = "", int errorCode = noErrorCode])
/* message에는 운영체제가 제공하는 예외에 대한 설명이 들어감
운영체제가 설명을 제공하지 않으면 빈 문자열 (””) 적용
errorCode 에는 운영체제가 제공하는 오류 코드가 들어감.
TimeoutException
- 비동기 결과를 기다리는 동안 특정 시간이 초과되었을 때 발생
TimeoutException(String? message, [Duration? duration])
/* message에는 시간 초과가 발생한 원인에 대한 설명이 들어가고,
duration 에는 초과된 시간이 들어감
2. 사용자가 직접 정의한 예외
- Dart가 정의한 예외들이 마음에 안 들어서 커스텀하고 싶을 때 사용
- Exception 클래스를 상속 받아 새로운 예외 클래스를 만듦
class AgeException implements Exception {
final String message;
AgeException(this.message);
}
//상속 받을 때 implements 키워드 사용
class AgeException implements Exception {
final String? message;
AgeException(this.message);
@override
String toString() => message ?? 'AgeException 이 발생했어요 !';
}
/* 예외 클래스도 당연히 @override 통해 재정의 할 수 있음
상속 받은 후에 @override를 통해 재정의 할 수 있음
사용자가 직접 정의한 예외 예시 코드
class AgeException implements Exception {
final String? message;
AgeException(this.message);
}
void printAge(int age) {
if (age < 0) {
throw AgeException(null);
}
print(age);
}
void main() {
try {
printAge(-8);
} catch (e) {
print(e);
}
}
/* printAge()의 매개변수에 음수값을 전달했기 때문에
Instance of 'AgeException’이 출력
class AgeException implements Exception {
final String? message;
AgeException(this.message);
}
void printAge(int age) {
if (age < 0) {
throw AgeException(null);
}
print(age);
}
void main() {
try {
printAge(8);
} catch (e) {
print(e);
}
}
/* printAge()의 매개변수에 0이상의 값을 전달했기 때문에 8만 출력
class AgeException implements Exception {
final String? message;
AgeException(this.message);
@override
String toString() => message ?? 'AgeException 이 발생했어요 !';
}
void printAge(int age) {
if (age < 0) {
throw AgeException(null);
}
print(age);
}
void main() {
try {
printAge(-8);
} catch (e) {
print(e);
}
}
/* printAge()의 매개변수에 음수값을 전달했기 때문에
AgeException 이 발생했어요 ! 출력
class AgeException implements Exception {
final String? message;
AgeException(this.message);
@override
String toString() => message ?? 'AgeException 이 발생했어요 !';
}
void printAge(int age) {
if (age < 0) {
throw AgeException('0 이상의 값을 넣어야 해요 !');
}
print(age);
}
void main() {
try {
printAge(-8);
} catch (e) {
print(e);
}
}
/* AgeException 의 생성자에 null 이 아닌 값을 넣어 주었기 때문에
0 이상의 값을 넣어야 해요 ! 출력
예외에 사용하는 키워드 - 목적에 따라 크게 2가지로 나뉨
1. 발생한 예외를 처리하기 위한 경우 (try, catch, on, finally 사용)
try
- 예외가 발생할 수 있는 코드를 넣는 부분
- 예외 처리 구문을 쓸 때 꼭 넣어야 함
- try의 코드 블록 실행 중에 예외가 발생하면, try의 코드 블록에 있는 뒷 코드들은 실행되지 않음 > catch 문으로 넘어감
try {
// 예외가 발생할 수 있는 코드
}
catch
- try의 코드 블록 실행 중에 예외가 발생했을 때 실행할 코드를 넣는 부분
- try의 코드 블록에서 예외가 발생하지 않으면 실행되지 않음
- 예외 처리 구문을 쓸 때 꼭 넣어야 하고, 개수에 제한이 없음
catch (e) {
print(e);
}
//발생한 예외의 객체가 catch의 매개변수로 전달됨
on
- try의 코드 블록에서 발생할 수 있는 예외 중 특정 타입의 예외를 다루는 부분
- 예외 처리 구문을 쓸 때 넣지 않아도 됨
- 단독으로 사용할 수 없고, catch와 항상 같이 써야함
- 예외 타입이 특정되기 때문에 catch에 객체가 전달되었을 때 그 객체를 가지고 할 수 있는 동작이 더 많음
- on으로 예외 타입을 특정해주지 않으면 Exception이 기본적으로 가지고 있는 4자기 요소만 사용할 수 있음
- on으로 예외 타입을 특정해주면 그 타입이 가지고 있는 요소들을 사용할 수 있음
on IOException catch (e) {
// IOException 이 발생했을 때 실행할 코드
}
finally
- 예외 발생 여부와 상관없이 실행할 코드를 넣는 부분
- try, catch를 모두 거친 후 실행됨
- 예외 처리 구문을 쓸 때 넣지 않아도 됨
finally {
// 예외 처리 후 실행할 코드
}
예시코드
try {
String invalidNumber = "abc";
int result = int.parse(invalidNumber);
print(result);
} catch (e) {
print(e);
}
/* e에 FormatException 클래스의 객체가 전달돼서
FormatException: abc 라고 출력
try 의 코드 블록에 있는 int.parse(invalidNumber); 에서 예외가 발생했기 때문에
그 아래에 있는 print(result); 는 실행되지 않고, catch 문으로 넘어감.
try {
String invalidNumber = "abc";
int result = int.parse(invalidNumber);
print(result);
} on FormatException catch (e) {
print(e);
}
/* 마찬가지로 e 에 FormatException 클래스의 객체가 전달돼서
FormatException: abc 라고 출력.
try {
String invalidNumber = "abc";
int result = int.parse(invalidNumber);
print(result);
} on FormatException catch (e) {
print(e);
} catch (e) {
print(e);
}
/* on FormatException catch (e) { … } 는 FormatException이 발생하면 실행되고,
catch (e) { … } 는 FormatException 이 아닌 다른 예외가 발생하면 실행됨
try {
String invalidNumber = "abc";
int result = int.parse(invalidNumber);
print(result);
} catch (e) {
print(e);
} finally {
print('예외 처리 끝 -');
}
/* FormatException: abc 랑 예외 처리 끝 - 이 차례대로 출력
try {
String validNumber = "123";
int result = int.parse(validNumber);
print(result);
} catch (e) {
print(e);
} finally {
print('예외 처리 끝 -');
}
/* “123” 은 정수형으로 변환할 수 있기 때문에 예외가 발생하지 않음
그래서 result 값인 123 이랑 예외 처리 끝 - 이 차례대로 출력
2. 예외를 의도적으로 발생시키기 위한 경우
throw
- 특정 경우에 예외를 의도적으로 발생시키기 위해 Exception 클래스나 Error 클래스를 통해 생성한 객체를 던짐
ㄴ Exception 클래스나 Error 클래스를 상속 받은 클래스도 가능
- throw를 통해 발생된 예외는 try, catch, on으로 처리할 수 있음
void printAge(int age) {
if (age < 0) {
throw Exception('나이는 0 이상이어야 해요 !');
}
print(age);
}
void main() {
try {
printAge(-8);
} catch (e) {
print(e);
}
}
/* printAge() 의 매개변수에 음수값을 전달하면 Exception 이 발생하기 때문에
Exception: 나이는 0 이상이어야 해요 ! 가 출력
try 의 코드 블록 실행 중에 Exception 이 발생했으니
print(age); 는 실행되지 않음
void printAge(int age) {
if (age < 0) {
throw Exception('나이는 0 이상이어야 해요 !');
}
print(age);
}
void main() {
try {
printAge(8);
} on Exception catch (e) {
print(e);
}
}
/* printAge() 의 매개변수에 0 이상의 값을 전달하면
Exception 이 발생하지 않기 때문에 print(age); 로 8 출력
'춘기IT > 춘기개발' 카테고리의 다른 글
| 비동기 프로그래밍과 Dart (3) | 2025.07.10 |
|---|---|
| 라이브러리를 이용한 확장 (3) | 2025.07.09 |
| 객체 지향 프로그래밍과 Dart (4) - 객체 지향과 상속 (3) | 2025.07.08 |
| 객체 지향 프로그래밍과 Dart (3) - 생성자 / 제네릭 (2) | 2025.07.07 |
| 객체 지향 프로그래밍과 Dart (2) - 클래스와 메서드 (0) | 2025.07.07 |