배운것들을 정리합니다.
三昧境

Flutter/Dart Language

[플러터 Flutter] 예외처리 try-catch와 throw, finally

ujo_orr 2024. 7. 16. 01:18

try-catch 구문은 Dart 언어의 예외 처리(exception handling) 메커니즘의 일부입니다.
여기서 예외란 프로그램의 정상적인 실행 흐름을 방해하는 사건입니다.
이는 코드작성의 오류, 네트워크 통신오류, 기기오류 등 다양하게 발생할 수 있습니다.

try-catch를 사용하여 실행 중 발생할 수 있는 예외(에러)를 포착하고 적절히 처리할 수 있습니다.

// 기본구조

try {
  // 예외가 발생할 수 있는 코드
} catch (e) {
  // 예외가 발생했을 때 실행되는 코드
}

 


 

try 블록

try {
  // 예외가 발생할 수 있는 코드
}

예외가 발생할 수 있는 코드를 포함합니다.
여기서 예외가 발생하면 프로그램의 흐름이 try블록을 벗어나 가장 먼저 일치하는 catch블록으로 이동합니다.

 

catch(e) 블록

} catch (e) {
  // 나머지 모든 예외를 처리하는 코드
}

위 블록에서 처리되지 않은 나머지 모든 예외를 처리합니다.
예외 타입에 상관없이 발생한 모든 예외를 잡아서 처리할 수 있습니다.

여기서 (e)는 발생한 예외 객체입니다.

 

예를들면

void main() {
  String str = "123a";

  try {
    int number = int.parse(str);
    print("Converted number: $number");
  } catch (e) {
    print("Error: $e");
  }
}

// 출력 Error: FormatException: 123a


"123a"라는 문자열을 숫자(정수)로 변환할때 "a"라는 문자열이 섞여있기 때문에 변환이 되지 않습니다.
그렇기에 try에서의 매서드가 실행되지 않으니 catch쪽으로 넘겼고 "Error: $e" 가 나오는 모습입니다.

만약 여기서 "123a"가 아닌 "123"이면 

catch문으로 넘어가지 않고 try문의 "Converted number : $number"가 정상적으로 출력이 되는것을 볼 수 있습니다.

 


 

여러개의 catch 블록

try {
  // 예외가 발생할 수 있는 코드
} on SpecificException catch (e) {
  // 특정 예외를 처리하는 코드
} on AnotherException catch (e) {
  // 다른 특정 예외를 처리하는 코드
} catch (e) {
  // 나머지 모든 예외를 처리하는 코드
}

다양한 유형의 예외를 별도로 처리할 수 있도록 여러 개의 catch블록을 사용할 수 있습니다.

void main() {
  try {
    // 예외가 발생할 수 있는 코드
    throw FormatException("This is a FormatException");
  } on FormatException catch (e) {
    // FormatException 예외를 처리하는 코드
    print("Caught a FormatException: $e");
  } on IOException catch (e) {
    // IOException 예외를 처리하는 코드
    print("Caught an IOException: $e");
  } catch (e) {
    // 나머지 모든 예외를 처리하는 코드
    print("Caught an unknown exception: $e");
  }
}

이러한 형식처럼 여러번의 거름망을 사용할 수 있습니다.

여기서 FormatException나 IOException는 Dart에서 미리 정의된 예외 클래스입니다.

 

  • Exception
    • 모든 예외의 기본 클래스입니다.
    • 사용자 정의 예외를 만들 때 주로 이 클래스를 상속합니다.
  • Error
    • 심각한 프로그램 오류를 나타내는 기본 클래스입니다.
    • 주로 시스템에서 발생하는 오류에 사용됩니다.
    • Error의 하위 클래스들은 시스템에서 심각한 문제를 나타냅니다.
  • FormatException
    • 잘못된 형식으로 인해 발생하는 예외입니다.
    • 예를 들어, 문자열을 정수로 변환하려 할 때 해당 문자열이 숫자가 아닌 경우 발생할 수 있습니다.
  • IOException
    • 입출력(I/O) 작업 중에 발생하는 예외입니다.
    • 예를 들어, 파일을 읽거나 쓸 때 발생하는 오류를 처리할 때 사용됩니다.
    • IOException은 dart:io 라이브러리에 정의되어 있으므로 이를 사용하려면 해당 라이브러리를 임포트해야 합니다.
  • ArgumentError
    • 잘못된 인수가 함수에 전달될 때 발생합니다.
  • RangeError
    • 값이 허용된 범위를 벗어날 때 발생합니다.
  • StateError
    • 객체의 상태가 잘못되었을 때 발생합니다.
  • TypeError
    • 잘못된 타입이 사용될 때 발생합니다.
  • UnimplementedError
    • 구현되지 않은 기능이 호출될 때 발생합니다.
    • 주로 미완성 메서드에서 사용됩니다.
  • UnsupportedError
    • 지원되지 않는 기능이 호출될 때 발생합니다.
  • ConcurrentModificationError
    • 객체가 반복 중에 수정될 때 발생합니다.
    • 주로 컬렉션에서 사용됩니다.

 

import 'dart:io';

void main() {
  try {
    // 예외가 발생할 수 있는 코드
    throw RangeError('Index out of range');
  } on FormatException catch (e) {
    print('Caught a FormatException: $e');
  } on IOException catch (e) {
    print('Caught an IOException: $e');
  } on RangeError catch (e) {
    print('Caught a RangeError: $e');
  } on ArgumentError catch (e) {
    print('Caught an ArgumentError: $e');
  } on Exception catch (e) {
    print('Caught a general exception: $e');
  } catch (e) {
    print('Caught an unknown exception: $e');
  } finally {
    print('This block is always executed.');
  }
}

이러한식으로 여러개의 catch블록을 사용할 수 있습니다.

 


throw

 

throw 키워드는 Dart에서 예외를 발생시키는 데 사용됩니다.

예외 객체를 인수로 받아서 실행 중에 예외를 던지며 예외 객체는
위에 서술해두었던 Exception 클래스나 Error 클래스, 혹은 이들의 서브클래스여야 합니다.

또한, Dart에서는 어떤 객체라도 예외로 던질 수 있지만, 일반적으로는 Exception이나 Error 사용합니다.

void main() {
  try {
    validateAge(-1);
  } catch (e) {
    print('Caught an exception: $e');
  }
}

void validateAge(int age) {
  if (age < 0) {
    throw ArgumentError('Age cannot be negative');
  } else {
    print('Age is valid');
  }
}

validateAge 함수는 age를 검사하여 음수인 경우 ArgumentError 예외를 던집니다.
main 함수는 validateAge 함수를 호출하고 try-catch 구문을 사용하여 예외를 처리합니다.

 


 

finally

 

finally 구문은 예외가 발생하든 발생하지 않든 상관없이 항상 특정 코드를 실행할 수 있게 해줍니다.
finally 블록은 예외 처리 후 자원 정리와 같은 작업에 유용합니다. (ex. 파일닫기)

import 'dart:io';

void main() {
  File file = File('example.txt');
  RandomAccessFile? raf;

  try {
    // 파일을 열고 내용을 읽음
    raf = file.openSync(mode: FileMode.read);
    String contents = raf.readStringSync(raf.lengthSync());
    print('File contents: $contents');
  } catch (e) {
    // 예외를 처리하는 코드
    print('An error occurred: $e');
  } finally {
    // 항상 실행되는 코드
    // 파일을 닫는 작업
    if (raf != null) {
      raf.closeSync();
    }
    print('File closed');
  }
}

이처럼 예외 발생 여부와 상관없이 항상 실행됩니다.