본문 바로가기
C#

조건문으로 처리 vs 예외로 처리

by 아마도개발자 2025. 8. 20.


개발을 하다 보면 어떻게 예외 처리를 해야 하나 고민하게 된다. 조건문(if)으로 처리할지, 예외(Exception)를 던질지 선택 해야 하는 순간이 항상 있다.

어느 상황에서 조건문을 사용할 지, 혹은 예외를 사용할 지 알아보자.


1.조건문과 예외의 역할 차이

  • 조건문(Validation / Guard Clause)
    • 예상 가능한 시나리오에서 분기 처리
    • 정상적인 흐름에 해당(비즈니스 로직에서의 예외) 
    • ex) 로그인 Validation 실패
  • 예외(Exception)
    • 예상하기 힘들거나 복구가 불가능한 상황
    • 시스템 오류, 인프라 장애 같은 비정상적인 흐름 
    • ex) DB연결 실패, 네트워크 통신 불가, 파일이 손상되어 파일 파싱 불가

 

2. 예시

 

- 조건문

public bool Login(string id, string password)
{
    if (id != "MyID")
    {
    	return false;
    }
    	
    if (password != "MyPassword")
    {
    	return false;
    }
    
    return true;
}
  • 아이디, 비밀번호의 검증은 예측이 가능한 상황이므로 if 조건문으로 처리

 

- 예외

public string ReadFileContent(string path) 
{
    try
    {
    	return File.ReadAllText(path);
    }
    catch(IOException ex)
    {
        // 파일 시스템 자체 문제(디스크 오류 등)
        throw new ApplicationException("File access failed.", ex);
    }
}
  • 파일을 읽는 과정에서 비정상적 오류 발생으로 예외 처리

예외처리 시 예외를 타입별로 나눌 때 범위가 가장 큰 예외를 마지막으로 작성해야 한다는 것을 주의해야 함.

public void ProcessFile(string path)
{
    try
    {
        // 잠재적으로 예외가 발생할 수 있는 코드
        var fileContent = File.ReadAllText(path);
        ProcessContent(fileContent);
    }
    catch (FileNotFoundException ex) // 더 구체적인(파생된) 예외
    {
        // FileNotFoundException에 대한 복구 로직
        Logger.LogError($"파일을 찾을 수 없습니다: {ex.Message}");
        CreateDefaultFile(path);
    }
    catch (IOException ex) // 덜 구체적인 예외
    {
        // IOException에 대한 복구 로직
        Logger.LogError($"파일 IO 오류: {ex.Message}");
        NotifyAdmin("파일 접근 문제가 발생했습니다.");
    }
    catch (Exception ex) // 가장 기본적인 예외 (항상 마지막에 위치)
    {
        // 일반적인 예외에 대한 복구 로직
        Logger.LogError($"예상치 못한 오류: {ex.Message}");
        throw; // 복구할 수 없는 경우 다시 throw하여 상위 호출자에게 전파
    }
}

 

또한, 복구할 수 없는 예외일 경우 상위 예외를 전달한다.

public class DataService
{
    public void SaveData(Data data)
    {
        // 이 메서드는 데이터베이스 연결 실패와 같은 심각한 오류를 처리하지 않음
        // 대신 상위 호출자에게 전파하여 처리하도록 함
        _repository.Save(data); // 예외가 발생하면 그대로 전파됨
    }
}

public class ApiController
{
    private readonly DataService _dataService;

    public IActionResult SaveData(DataDto dto)
    {
        try
        {
            var data = _mapper.Map<Data>(dto);
            _dataService.SaveData(data); // 여기서 예외가 발생할 수 있음
            return Ok("데이터가 성공적으로 저장되었습니다.");
        }
        catch (DbConnectionException ex)
        {
            // API 계층에서 데이터베이스 연결 오류 처리
            _logger.LogError(ex, "데이터베이스 연결 오류");
            return StatusCode(503, "서비스를 일시적으로 사용할 수 없습니다.");
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "데이터 저장 중 예상치 못한 오류");
            return StatusCode(500, "내부 서버 오류");
        }
    }
}



예외/제어 코드 작성 시 위 사항을 유의하여 작성하니 코드가 굉장히 간결해지고 가독성이 높아짐을 느꼈다.