본문 바로가기

코틀린

코틀린(Kotlin) - 예외 처리

코틀린의 예외처리(exception)는 자바의 예외처리와 비슷합니다.

함수는 정상적으로 종료할 수 있지만, 오류가 발생하면 예외를 던질 수(throw) 있고,

함수를 호출하는 쪽에서는 그 예외를 잡아 처리할 수 있습니다.

발생한 예외를 함수 호출 단에서 처리(catch)하지 않으면, 함수 호출 스택을 거슬러 올라가면서 예외를 처리하는 부분이 나올 때까지 예외를 다시 던지게(rethrow) 됩니다.

 

if (number in 0..100) {
  number
} else {
  throw IllegalArgumentException("0~100사이의 숫자가 아닙니다.")
}

>> number = 200
java.lang.IllegalArgumentException: 0~100사이의 숫자가 아닙니다.

try, catch, finally

자바와 마찬가지로, 예외처리 시 try와 catch, finally 절을 함께 사용합니다.

 

fun readNumber(reader: BufferedReader): Int? { //throws를 명시하지 않아도 됩니다.
  try {
      val line = reader.readLine()
      return Integer.parseInt(line)
  } catch (e: NumberFormatException) { //예외타입을 : 의 오른쪽에 명시합니다.
      return null
  } finally { //자바와 똑같이 작동합니다.
      reader.close()
  }
}

 

자바와 가장 큰 차이는, 메소드 옆에 throws절이 없다는 점입니다.

자바에서는 함수를 작성할 때, 함수 선언 뒤에 throws IOException을 붙여서 예외(exception)를 명시적으로 처리해야 합니다.

하지만, 코틀린에서는 함수가 던지는 예외를 잡아내도 되고, 잡아내지 않아도 됩니다.

이러한 문법은, 실제 자바 프로그래머들이 코딩하는 방식을 고려해서 코틀린을 설계했기 때문인데요,

자바는 예외처리를 강제하지만, 실제론 프로그래머들이 의미 없이 예외를 다시 던지거나, 예외를 잡되 처리하지 않고 그냥 무시하는 코드(e.getStackTrace()...) 를 작성하는 경우가 흔하기 때문입니다.

 

그렇다면, 자원 획득과 해제를 쉽게 처리해주는 자바 7의 try-with-resource 구문도 생각나는데 같은데, 이와 같은 특별한 문법이 코틀린에도 존재합니다!

그것은 바로 "use"함수를 활용하는 것 입니다.

 

//자바 try-with-resource
public String readLineFromFile(String path) throws IOException {
   try (BufferedReader br = new BufferedReader(new FileReader(path))) {
       return br.readLine();
   }
}

 

//코틀린 use함수로 자원 관리
fun readLineFromFile(path: String): String {
    BufferedReader(FileReader(path)).use { br ->
        return br.readLine()
    }
}

 

코틀린에는 자바의 try-with-resource와 같은 기능을 제공하는 "use"라는 함수가 코틀린 표준 라이브러리 안에 들어가 있습니다.

use 함수는 자원에 대한 확장 함수이며, 람다를 호출한 다음에 자원을 닫아주는 식으로 동작하게 됩니다.

정상 종료된 경우는 물론이고, 람다 안에서 예외가 발생한 경우에도 자원을 확실히 닫아주기 때문에, 성능상 유리함을 얻을 수 있습니다.

try를 식으로 사용하기

자바와 코틀린의 중요한 차이를 하나 더 살펴볼 수가 있는데, 코틀린의 try 키워드는 if나 when과 마찬가지로 "식"으로 사용이 가능합니다.

 

val number = try {
    println("try")
    Integer.parseInt("7") //마지막 문장이 결과 값이 된다.
} catch (e: NumberFormatException) {
    println("catch")
    null
}

>> println(number)
try
7

 

try의 코드 블록의 실행이 정상적으로 끝나면, try도 마찬가지로 본문 내부에 있는 마지막 문장이 식의 결과 값이 됩니다.

예외가 발생했을 경우, catch에서 null 값을 반환하도록 선언하였기 때문에, catch가 실행된다면 식의 결과값으로 null이 반환됩니다.