예외(Exception)

ssh·2023년 12월 11일
0

dart

목록 보기
15/22

개요

  • Exception이란 프로그램의 정상적 흐름을 방해하는 이벤트를 말한다.
  • 대표적인 예로, 숫자를 0으로 나눌 때 발생하는 DivisionByZero Exception이 있다.
  • Dart는 Exception을 처리하는 방법으로 Assert, try-catch-finally, stackTrace를 활용한다.
  • Dart 코드는 예외를 발생, 캐치할 수 있다.
  • 예외는 예상하지 못한 일이 발생했다는 것을 의미한다.
  • 예외가 캐치되지 않았다면, 예외를 발생시킨 격리(isolate)가 일시 중단되며 일반적으로 해당 프로그램이 종료된다.
  • Java와 다르게, Dart의 모든 예외는 확인되지 않은 예외다.
  • 메서드는 자신이 어떤 예외를 발생시킬지 선언하지 않고, 개발자에게 예외를 캐치하도록 요구하지도 않는다.
  • 원하는 예외를 정의하는 것도 가능하다.
    • 그러나, Dart 프로그램은 Exception이나 Error 객체 이외에도 모든 non-null 객체를 예외로 발생할 수 있다.
  • 프로그램을 설계할 때 실행시에 예외 상황이 발생할 가능성이 있는 것을 예측하여, 사전에 예외 처리가 되도록 할 필요가 있다.
    • 이럴 때 적절한 조치가 없으면 프로그램은 에러가 나며 죽어버린다.
  • 예상 외의 상황에 적절한 조치를 취하는 것이 예외처리이다.

에러의 종류와 대응책

  1. 문법 에러(syntax error)
  2. 실행 시 에러(runtime error)
  3. 논리 에러(logic error)

에러 상황 별 처리

syntax errorruntime errorlogic error
원인코드의 형식적 오류실행 중에 예상외의 사태가 발생하여 동작이 중지됨기술한 처리 내용에 논리적인 오류가 있음
알아 채는 방법컴파일하면 에러 남실행하면 도중에 강제 종료 됨실행하면 예상외의 값이 나옴
해결 방법컴파일러의 지적을 보고 수정에러원인을 스스로 찾아서 해결해야 함

예외적인 상황들

  • 메모리가 부족할 때
  • 파일을 찾을 수 없을 때
  • 네트워크 통신이 불가능할때

예외의 종류

  • API에는 여러가지 예외적 상황을 표현하는 예외 클래스가 준비되어 있다.
  • 예외 클래스를 상속하여 오리지날 예외 클래스를 정의할 수 있다.

Assert

  • 조건이 거짓일 경우 프로그램을 실행 중단하는 명령어
  • 오직 Debug 중일 때만 실행된다. 배포 코드에서는 프로그램에 영향을 주지 않는다.
    • 코드
      assert(condition, optionalMessage);
      
      void main() {
        var i = 5;
        assert(i > 0, 'A positive integer is required.');
      
      }

Throw

  • thow는 프로그램의 실행을 멈추는 코드다.
  • throw절을 통하여 예외 상황 발생 시 객체 또는 코드 등을 반환할 수 있다.
  • assert와 달리 에러의 확인을 직접 하지는 않는다.
    • assert는 에러를 확인하는 코드를 내장하고 있지만 throw는 에러를 확인하는 코드는 가지고 있지 않기 때문이다.
    • 코드
      // assert는 에러를 확인하는 코드를 내장하고 있다.
        assert(i > 0, 'A positive integer is required.');
      	// 이와 반대로 throw는 에러를 확인하는 코드를 가지고 있지 않다. 그냥 프로그램의 실행만 멈춘다
      	throw Exception('Negative number: $num');
    • 따라서 throw는 종종 if나 switch 문과 함께 사용한다.
      • 코드
        void main() {
          var num = -5;
        
          if (num < 0) {
            throw Exception('Negative number: $num');
          }
        }
  • 다음 예제는 예외를 throwing 또는 raising 하는 코드다
    throw FormatException('Expected at least 1 section');
  • 임의의 객체도 throw 할 수 있다:
    throw 'Out of llamas!';
  • 예외를 발생시키는 것은 표현식이기 때문에, 표현식을 사용할 수 있는 곳이라면, => 구문을 사용하여 예외를 발생시킬 수 있다:
    void distanceTo(Point other) => throw UnimplementedError();

Try-Catch-finally

  • try - catch -finally는 Exception 발생시 처리 방법을 설명하는 코드다.
  • try 코드 내부에는 Exception이 발생할 가능성이 있는 코드를 추가한다.
  • catch 코드에는 각각의 Exception별 프로그램이 취해야 할 행동을 추가한다.
  • finally 코드에는 코드가 정상 실행 되던, exception이 실행 되던 프로그램이 마지막으로 항상 실행해야 할 행동을 추가한다.
  • 예외 처리의 흐름
    try {
    	// 예외가 발생할 수 있는 코드
    } catch (e){
    	// e : 에러의 정보를 담고 있는 객체
    	// 예외처리를 위한 코드
    }
  • Catch문을 사용하여 예외(Exception) 발생 시 예외 코드가 프로그램 전체에 전파(Catching 또는 capturing)되는 것을 방지할 수 있고 예외를 캐치하면 해당 예외를 처리할 수 있다.
    • 코드
      try {
        breedMoreLlamas();
      } on OutOfLlamasException {
        buyMoreLlamas();
      }
    • 막지 않는다면 예외를 rethrow 한다.
  • 한 개 이상의 예외 타입을 발생시키는 코드를 처리할 때, 다수의 catch 절을 사용할 수 있다.
  • 발생된 객체의 타입을 매치하는 첫 번째 catch 절은 해당 예외를 처리한다.
  • catch 절에 타입을 명시하지 않는다면, 해당 절은 발생되는 모든 타입의 예외를 처리할 수 있다
    • 코드
      try {
        breedMoreLlamas();
      } on OutOfLlamasException {
        // 특정한 예외
        buyMoreLlamas();
      } on Exception catch (e) {
        // Exception 타입인 예외
        print('Unknown exception: $e');
      } catch (e) {
        // 타입을 정하지 않은 catch 절로 모든 예외를 처리
        print('Something really unknown: $e');
      }
  • 위의 코드에서 볼 수 있듯이, on 또는 catch를 모두 사용할 수 있다.
  • 예외 타입을 특정해야 할 때는 on을 사용한다.
  • 예외 핸들러가 예외 객체를 필요로 할 때는 catch를 사용한다.
  • catch()에 하나 또는 두개의 매개변수를 전달 할 수 있다.
    • 첫 번째는 발생될 예외
    • 두 번째는 스택 트레이스([StackTrace] 객체)
      • 코드
        try {
          // ···
        } on Exception catch (e) {
          print('Exception details:\n $e');
        } catch (e, s) {
          print('Exception details:\n $e');
          print('Stack trace:\n $s');
        }
  • 예외를 부분적으로 처리하기 위해, rethrow 키워드를 사용하여 에러의 전파를 허용한다.
    • rethrow는 현재 처리 중인 예외를 다시 던지는데 사용됩니다.
    • catch 블록 내에서 예외를 처리한 후에 rethrow를 호출하면, 예외를 현재 블록에서 던질 수 있다.
    • 이를 통해 상위 호출자에게 예외를 전파할 수 있다.
      • 코드
        void misbehave() {
          try {
            dynamic foo = true;
            print(foo++); // 런타임 에러
          } catch (e) {
            print('misbehave() partially handled ${e.runtimeType}.');
            rethrow; // 호출자가 예외를 확인 할 수 있도록 허락
          }
        }
        
        void main() {
          try {
            misbehave();
          } catch (e) {
            print('main() finished handling ${e.runtimeType}.');
          }
        }

예외 클래스 정의

  • 예외 클래스를 직접 정의하는 방법으로 class에 Exception 인터페이스를 implements하고 toString을 override해서 if문으로 특정 조건일 때 Exception을 반환하면, 직접 만든 Exception을 사용할 수 있다.
    • 코드
      class UnsupportedMusicFileException implements Exception {
        final String? _message;
      
        const UnsupportedMusicFileException({
          required String? message,
        }) : _message = message;
      
        
        String toString() {
          if (_message == null) return 'UnsupportedMusicFileException';
          return 'UnsupportedMusicFileException{_message: $_message}';
        }
      }
      
      void main() {
        UnsupportedMusicFileException exception =
            UnsupportedMusicFileException(message: null);
        print(exception);
      }

java에서의 try-catch

  • java에서 retrofit2 라이브러리 사용시 try-catch문 사용
    • 코드
      private void loadMovies(String url, final int index) {
              // retroift 생성
              Retrofit retrofit = new Retrofit.Builder()
                      .baseUrl(API.base_url) // 기본적으로 적용되는 서버 URL (반드시 / 로  마무리)
                      .addConverterFactory(GsonConverterFactory.create()) // JSON 데이터를 GSON 라이브러리로 파싱하고 데이터를 Model에 자동으로 담는 converter
                      .build(); // build()로 생성
      
              MovieService movieService = retrofit.create(MovieService.class);
              // Retrofit 클래스로 interface 객체를 구현
      
              Call<MovieResponse> call = movieService.getMovies(url);
              //   url 변수를 인수로 전달하여 movieService 개체에서 호출
              //   일반 유형이 MovieResponse인 Call 개체를 반환
              //   Call 개체는 서버에서 영화 데이터를 가져오기 위해 실행될 비동기 요청
              //   Call 개체를 변수 call에 할당하여 실행 요청을 대기열에 넣고 응답을 비동기적으로 처리하는 데 사용
              try {
                  call.enqueue(new Callback<MovieResponse>() {
      
                      @Override
                      public void onResponse(Call<MovieResponse> call, retrofit2.Response<MovieResponse> response) {
                          //progressDialog.dismiss();
                          if (response.isSuccessful()) { // 통신 성공했을 때
                              MovieResponse movieResponse = response.body();
                                Log.d(TAG, "body: 성공:\n" + movieResponse);
                              assert movieResponse != null;
                                Log.d(TAG, "response: 성공:\n" + movieResponse.toString());
                              if (movieResponse != null) {
                                  List<Movie> movieList = movieResponse.getResults(); // 응답 내용 변수에 입력
                                  switch (index) {
                                      case 0:
                                      case 1:
                                      case 2:
                                      case 3:
                                      case 4:
                                      case 5:
                                      case 6:
                                      case 7:
                                      case 8:
                                      case 9:
                                      case 10:
                                      case 11:
                                      case 12:
                                      case 13:
                                      case 14:
                                      case 15:
                                      case 16:
                                      case 17:
                                      case 18:
                                          movieList1[index].addAll(movieList);
                                          break;
                                  }
                              }
                          } else {
                              // API 호출이 실패한 경우
                                Log.d(TAG, "onResponse: 실패");
                          }
                      }
      
                      @Override // 네트워크 오류
                      public void onFailure(Call<MovieResponse> call, Throwable t) {
                          t.printStackTrace();
                            Log.d(TAG, "onFailure: " + t.getMessage());
                      }
                  });
              } catch (Exception e) {
                    Log.d(TAG, "Exception: " + e.getMessage());
      
              }
          }
    • java에서 쓰던 try-catch문은 try-on-catch문이라고 한다.
    • dart에서 on은 exception 객체가 필요없을 때 안써도 되고 catch는 exception 객체가 필요할 때 사용한다.
    • 특정 exception만 지정해서 예외처리를 하고싶다면 on-catch구문을 사용한다.
    • java와는 다르게 dart의 예외는 확인되지 않은 예외라는 차이점이 있다.

0개의 댓글

관련 채용 정보