-
3-4. 함수 정의하기 : 예외 처리Study(종료)/Kotlin 22.09.13 ~ 12.18 2022. 9. 26. 12:51
3장 정리
3-4. 함수 정의하기 : 예외 처리
3.5 예외 처리
함수가 비정상적으로 오류가 발생한 경우 예외를 던질 수 있다(Throw Exception)
예외가 발생한 경우, 함수를 호출한 쪽에서 예외를 잡아내거나(catch), 함수 호출 스택의 위로 예외가 전달될 수 있다.
1) 예외 던지기
에외를 던질 때는 아래와 같은 일이 벌어진다.
- 프로그램은 예외를 잡아내는 핸들러(excption handler)를 찾는다. 예외와 일치하는 핸들러가 있다면 그 핸들러가 에외를 처리한다.
- 현재 함수 내부에서 핸들러를 찾을 수 없다면 함수 실행이 종료되고 함수가 스택에서 제거(pop)된다.
그리고 함수를 호출한 문맥 안에서 예외 핸들러 검색을 수행한다. 이런 경우 예외를 호출자에게 전파(propagate)했다고 말한다.
- 프로그램 진입점에 이를 때 까지 예외를 잡아내지 못하면(예외 핸들러가 없다면) 현재 스레드가 종료된다.
문자열이 잘못된 경우 어떤 값을 돌려주는 대신 오류를 발생시키도록 해보자
fun parseIntNumber(s: String): Int{ var num = 0; if(s.length !in 1..31) throw NumberFormatException("Not a number: $s") for(c in s){ if(c !in '0'..'9') throw NumberFormatException("Not a number: $s") num = num*10 + (c - '0') } return num } fun main() { // val a = "foo" // println(parseIntNumber(a)) // NumberFormatException: Not a number: foo // val b = "20s" // println(parseIntNumber(b)) // NumberFormatException: Not a number: 20s val c = "109" println(parseIntNumber(c)) // 109 }
2) try 문으로 예외 처리하기
코틀린에서 예외를 처리할 때는 try - catch 문을 사용한다.
위 코드에서 주석처리된 부분을 실행하면, 다음 코드가 실행되지 않고 비정상 종료된다.
이제 이 부분을 실행해도 비정상종료되지 않고 다음 코드가 실행되게 변경해보자.
import java.lang.NumberFormatException fun parseIntNumber(s: String): Int{ var num = 0 try{ if(s.length !in 1..31) throw NumberFormatException("Not a number: $s") for(c in s){ if(c !in '0'..'9') throw NumberFormatException("Not a number: $s") num = num*10 + (c - '0') } }catch (e: NumberFormatException){ println(e.toString()) num = Integer.MIN_VALUE } return num } fun main() { val a = "foo" val b = "20s" val c = "109" println(parseIntNumber(a)) // java.lang.NumberFormatException: Not a number: foo // -2147483648 println(parseIntNumber(b)) // java.lang.NumberFormatException: Not a number: foo // -2147483648 println(parseIntNumber(c)) // 109 }
코드가 마지막줄까지 도달하는 것을 볼 수 있다.
catch 블록은 선언된 순서대로 예외 타입을 검사하기 때문에
어떤 타입을 처리할 수 있는 catch 블록을 그 타입의 상위 타입을 처리할 수 있는 catch 블록보다 앞에 작성해야 한다.
그렇지 않으면 상위 타입을 잡아내는 핸들러가 하위 타입인 예외도 모두 잡아내버린다.
fun parseIntNumber(s: String): Int{ var num = 0 try{ if(s.length !in 1..31) throw NumberFormatException("Not a number: $s") for(c in s){ if(c !in '0'..'9') throw NumberFormatException("Not a number: $s") num = num*10 + (c - '0') } }catch (e: Exception){ println(e.toString()) num = Integer.MIN_VALUE }catch (e: NumberFormatException){ // 죽은 코드 println(e.toString()) num = Integer.MAX_VALUE } return num }
위 코드에서 NumberFormatException은 Exception의 하위 타입이기 떄문에
두 번째 catch 블록인 NumberFormatException은 실제로는 죽어있는 코드이다.
try 문에 finally 블록을 사용할 수 있다. finally 블록은 try 블록은 떠나기 전에 프로그램이 어떤 일을 수행하도록 만들어준다.
주로 try 블록 앞이나 내부에서 할당한 자원을 해제할 때 유용하다.
예를 들어 파일, 네트워크 연결을 닫거나 DB와 관련된 자원을 해제하는데 사용한다.
코틀린의 try 블록은 식이다. 이 식의 값은(예외가 발생하지 않은 경우) try 블록의 값이거나 예외를 처리한 catch 블록의 값이 된다.
import java.lang.NumberFormatException fun readInt(default: Int) = try{ readLine()!!.toInt() }catch (e: NumberFormatException){ default }finally { println("END") } fun main() { val a = readInt(10) // 1000 입력 println(a) // 1000 // END }
여기까지가 이번주 스터디 내용이다.
다음주에는 4장 클래스와 객체 다루기 관련 내용을 작성할 예정이다.
반응형'Study(종료) > Kotlin 22.09.13 ~ 12.18' 카테고리의 다른 글
4-2. 클래스와 객체 다루기 : 널 가능성 (1) 2022.10.01 4-1. 클래스와 객체 다루기 : 클래스 정의하기 (2) 2022.09.29 3-3. 함수 정의하기 : 루프 (1) 2022.09.26 3-2. 함수 정의하기 : 조건문 (0) 2022.09.26 3-1. 함수 정의하기 : 함수 (1) 2022.09.26