예외: try...finally 식

예외: try...finally 식

리소스를 정리해야 하는 코드가 예외 때문에 중간에 끊겨도 마무리를 보장해 주는 식이 F#에는 있어요. 바로 try...finally 식인데요, 이 페이지에서 그 쓰임새를 차근차근 살펴볼게요.

출처: https://learn.microsoft.com/en-us/dotnet/fsharp/language-reference/exception-handling/the-try-finally-expression

본문

try...finally 식을 쓰면 코드 블록이 예외를 던지더라도 정리(clean-up) 코드를 실행할 수 있어요.

구문(Syntax)

try
    expression1
finally
    expression2

설명(Remarks)

try...finally 식은 위 구문에서 expression1을 실행하는 동안 예외가 발생했는지와 관계없이 expression2의 코드가 실행되도록 해 줘요.

expression2의 타입은 전체 식의 값에는 영향을 주지 않아요. 예외가 발생하지 않았을 때 반환되는 값은 expression1의 마지막 값이죠. 예외가 발생하면 값은 반환되지 않고, 제어 흐름은 호출 스택에서 다음으로 일치하는 예외 처리기(handler)로 넘어가요. 일치하는 예외 처리기가 없으면 프로그램은 종료됩니다. 그리고 일치하는 처리기의 코드가 실행되기 전이든 프로그램이 종료되기 전이든, finally 분기의 코드는 반드시 실행돼요.

다음 코드는 try...finally 식의 사용 예시예요.

let divide x y =
   let stream : System.IO.FileStream = System.IO.File.Create("test.txt")
   let writer : System.IO.StreamWriter = new System.IO.StreamWriter(stream)
   try
      writer.WriteLine("test1")
      Some( x / y )
   finally
      writer.Flush()
      printfn "Closing stream"
      stream.Close()

let result =
  try
     divide 100 0
  with
     | :? System.DivideByZeroException -> printfn "Exception handled."; None

콘솔에 출력되는 결과는 다음과 같아요.

Closing stream
Exception handled.

출력 결과에서 볼 수 있듯이, 바깥쪽 예외가 처리되기 전에 스트림이 먼저 닫혔어요. 그리고 test.txt 파일에는 test1 텍스트가 들어 있는데, 이는 예외가 바깥쪽 예외 처리기로 제어 흐름을 넘겼음에도 버퍼가 플러시되어 디스크에 기록됐다는 뜻이에요.

여기서 한 가지 꼭 짚고 넘어갈 점이 있어요. try...with 구문은 try...finally 구문과 별개의 구문이에요. 그래서 코드에 with 블록과 finally 블록이 모두 필요하다면 두 구문을 중첩해서 써야 해요. 아래 코드가 그 예시예요.

exception InnerError of string
exception OuterError of string

let function1 x y =
   try
     try
        if x = y then raise (InnerError("inner"))
        else raise (OuterError("outer"))
     with
      | InnerError(str) -> printfn "Error1 %s" str
   finally
      printfn "Always print this."


let function2 x y =
  try
     function1 x y
  with
     | OuterError(str) -> printfn "Error2 %s" str

function2 100 100
function2 100 10

계산 식(computation expression)의 맥락, 특히 시퀀스 식과 비동기 식에서는 try...finally 식에 사용자 지정 구현을 쓸 수 있어요. 자세한 내용은 계산 식(Computation Expressions) 문서를 참고해 주세요.

더 알아보기 (Learn more)