ZIO로 안전한 예외 처리하기

CHEESE·2023년 7월 26일
0

OSSCA 2023

목록 보기
3/7
post-thumbnail

ZIO로 예외 처리하기

ZIO.attempt()로 실패할 가능성이 있는 코드를 감싸고 catchAll()로 예외 발생 시 처리할 수 있다.

def sliceString(str: String): ZIO[Any, RuntimeException, String] = {
    ZIO.attempt(str.substring(0, 5))
      .catchAll(_ => ZIO.fail(new RuntimeException("예외 발생")))
  }
}

위 코드에서 sliceString()은 문자열을 인자로 받아 ZIO[R, E, A] 타입을 리턴한다.
str.substring(0,5)를 실행하되, 중간에 예외가 발생하면 RuntimeException을 발생시키도록 처리했다.

  • E(RuntimeException)은 이 함수가 RuntimeException을 발생시킬 수 있다는 것을 의미한다. 실제로 위 코드에서는 RuntimeException이 아닌 다른 예외는 발생할 수 없다.
  • A(String)은 이 함수가 성공적으로 종료될 경우 String을 리턴한다는 것을 의미한다. str.substring(0,5)의 반환값이 리턴되는 것을 기대할 수 있다.

실습

override def run: ZIO[Any with ZIOAppArgs with Scope, Exception, Unit] =
    for {
      result <- sliceString("happy birthday")
      _ <- zio.Console.printLine(result)
    } yield ()
  • 실행 결과
happy
override def run: ZIO[Any with ZIOAppArgs with Scope, Exception, Unit] =
    for {
      result <- sliceString("go")
      _ <- zio.Console.printLine(result)
    } yield ()
  • 실행 결과
timestamp=2023-07-26T11:55:55.846525Z level=ERROR thread=#zio-fiber-1 message="" cause="Exception in thread "zio-fiber-4" java.lang.RuntimeException: 예외 발생
	at Main$.$anonfun$sliceString$3(Main.scala:12)
	at zio.ZIO$.$anonfun$fail$1(ZIO.scala:3146)
	at zio.ZIO$.$anonfun$failCause$3(ZIO.scala:3155)
	at <empty>.Main.sliceString(Main.scala:12)
	at <empty>.Main.run(Main.scala:6)"

try-catch와 다른 점

위에서 작성한 sliceString을 try-catch로 바꾸면 아래와 같이 구현할 수 있다.

def sliceString(str: String): Serializable = {
    try {
      str.substring(0, 5)
    } catch {
      case e: _ => new Exception(s"예외 발생")
    }
}

크게 2가지 차이점이 있다.

  • 반환되는 타입을 알 수 없음
    - ZIO로 구현한 것과 다르게 타입 추론시 Serializable이 나온 것을 볼 수 있다.
  • 어떤 예외가 발생하는지 알 수 없음

결론

  • ZIO를 사용하면 좀 더 type-safe하게 코드를 구현할 수 있더라

0개의 댓글