티스토리 뷰

Flutter

try-catch 정리해보기

순진이 2024. 7. 11. 19:58

try-catch 구문은 Dart에서 런타임 동안 발생할 수 있는 오류를 처리하기 위한 방법

예외가 발생할 수 있는 구문을 try로 감싸고, catch에서 해당 예외를 처리하게 됨

try {
  //예외 발생 가능성 있는 구문
} catch(exception, stackTrace) {
 //예외 처리
}

Throw

예외를 던지거나 발생시킬 때는 throw라는 키워드를 쓰면 됨

throw FormatException('Expected at least 1 section');

 

 

아래처럼 단순히 임의의 객체(여기서는 String 타입)를 에러로 발생시킬 수 있음

하지만 이렇게 임의의 객체들로 예외를 발생시키다보면, 관리가 어려워지고 가독성이 떨어지기 때문에 제대로 된 설계가 필요.

throw 'Out of llamas!';

 

Catch

"예외를 잡아서 처리하는 부분"

 

catch는 2개의 인자를 받는데, 하나는 필수 인자로 발생한 예외 객체, 나머지 하나는 선택 인자로 StackTrace타입의 객체임

- 첫 번째 인자 (exception) : 필수

예외 객체 자체. 발생한 예외의 구체적인 정보와 메시지 등이 포함

 

- 두 번째 인자 (stackTrace) : 선택

StackTrace의 객체로 예외가 발생한 위치와 호출 스택의 정보를 포함. 이를 통해 예외가 발생한 위치 등을 추적할 수 있음

 

 

Catch로 예외 처리하기

1. 일반적인 처리

가장 기본적으로는 아래처럼 catch 구문에서 모든 예외들을 받아서 처리할 수 있음

  try {
    throw FormatException('This is a format exception');
  } catch (e) {
    print('Caught an exception: $e');
  }
  
  //Caught an exception: FormatException: This is a format exception

 

 

2. 예외별 처리

1번처럼 catch에서 모든 예외를 처리하는 게 아닌, 예외 타입별로 처리하는 방법도 있음

예외에도 Exception, FormatException, HttpException 등 여러 종류가 있고, 예외별로 처리가 가능함

 

on이라는 키워드와 해당 타입을 써주면 그 타입의 예외를 처리하는 구문이 됨

  try {
    throw FormatException('This is a format exception');
  } on FormatException catch (e) {
    print('Caught a FormatException: $e');
  } on IOException catch (e) {
    print('Caught an IOException: $e');
  } catch (e) {
    print('Caught an exception: $e');
  }
  
  //Caught a FormatException: FormatException: This is a format exception

 

위 코드를 보면 해당 예외 타입에 따라 처리를 하고 있고 FormatException을 처리하는 catch 구문으로 빠져 처리되는 걸 알 수 있음

 

 

위 처리는 catch에서 모든 예외를 다 받은 후 처리해도 됨

동일한 결과가 나옴

  try {
    throw FormatException('This is a format exception'); 
  } catch (e) {
    if (e is FormatException) {
      print('Caught FormaException: $e');
    } else if (e is IOException) {
      print('Caught FormaException: $e');
    } else {
      print('Caught Exception: $e');
    }
  }
  
    //Caught a FormatException: FormatException: This is a format exception

 

 

 

예외를 catch할 필요가 없을 때는 굳이 catch라는 키워드를 써주지 않아도 됨!

아래 코드에서 OutOfLlamasException은 예외 객체가 필요없기 때문에 따로 catch 키워드를 쓰지 않았음

try {
  breedMoreLlamas();
} on OutOfLlamasException {
  buyMoreLlamas();
} on Exception catch (e) {
  print('Unknown exception: $e');
} catch (e) {
  print('Something really unknown: $e');
}

Custom Exception

말그대로 Exception도 Custom으로 만들 수 있음.

기존의 Exception을 implements 해서 구현하면 됨

class ValidationException implements Exception {
  final String message;

  ValidationException(this.message);

  @override
  String toString() => 'ValidationException: $message';
}

 

 

 

이렇게 만든 Custom Exception을 기존 예외 타입으로 써주면 됨!

  try {
    throw ValidationException('This is a custom exception');
  } on ValidationException catch (e) {
    print('Caught custom Exception: $e');
  } catch (e) {
    print('Caught Exception: $e');
  }
  
  //Caught custom Exception: ValidationException: This is a custom exception

Finally

try-catch 문에서 함께 사용되는 블록으로, try-catch에서 예외가 발생했는지 여부와 상관없이 try-catch 실행 후 항상 실행되는 구문

finally 블록은 사용 중이던 모든 리소스를 정리하는 데 사용됨

메모리 관리에 도움을 주고 누수를 방지하며 최적의 리소스 사용을 보장해줌

  try {
    throw FormatException('This is a format exception'); 
  } catch (e) {
    if (e is FormatException) {
      print('Caught FormaException: $e');
    } else if (e is IOException) {
      print('Caught FormaException: $e');
    } else {
      print('Caught Exception: $e');
    }
  } finally {
    print('-----Everything is done!');
  }
  
//Caught FormaException: ValidationException: This is a custom exception
//-----Everything is done!

 


rethrow

rethrow란 말 그대로 예외를 다시 던지게 해주는 키워드

기존의 예외 Stack Trace를 그대로 유지하기 때문에 예외 발생 위치와 관련된 정보를 잃지 않고 처리할 수 있게 도와줌

실제로 코드를 쓰다 보면 try-catch 구문을 상위에서 또 호출하는 경우가 많기 때문에 기존의 정보를 잃지 않게 도와주는 건 디버깅 목적에도 큰 도움이 됨!

 

 

아래처럼 rethrow로 해당 예외를 상위로 다시 던질 때, 같은 예외 발생과 함께 어디서 발생했는지를 알 수 있음!

void intermediateFunction() {
  try {
    throw FormatException('This is a FormatException');
  } catch (e) {
    print('[rethrow] intermediateFunction() caught an exception: $e');
    rethrow; // 예외를 다시 던짐
  }
}

void main() {
  //intermediateFunction를 호출하는 상위 호출부
  try {
    intermediateFunction();
  } catch (e, s) {
    print('==================');
    print('main() caught an exception: $e');
    print('==================');
    print('Stack trace: $s');
  }
}

/*
[rethrow] intermediateFunction() caught an exception: FormatException: This is a FormatException
==================
main() caught an exception: FormatException: This is a FormatException
==================
Stack trace: #0      functionThatThrows (file:///home/runner/Dart/main.dart:22:3)
#1      intermediateFunction (file:///home/runner/Dart/main.dart:27:5)
#2      main (file:///home/runner/Dart/main.dart:36:5)
#3      _delayEntrypointInvocation.<anonymous closure> (dart:isolate-patch/isolate_patch.dart:297:19)
#4      _RawReceivePort._handleMessage (dart:isolate-patch/isolate_patch.dart:184:12)
*/

 


try-catch 또한 많이 사용하고 있었지만, 제대로 된 정리 없이 쓰고 있었던 듯하다

특히 finally라는 건 이번에 처음 알게 되었는데, 꽤 유용하게 활용할 수 있을 것 같다!

https://dart.dev/language/error-handling

 

Error handling

Learn about handling errors and exceptions in Dart.

dart.dev

 

공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크