ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • 3-4. 함수 정의하기 : 예외 처리
    Study(종료)/Kotlin 22.09.13 ~ 12.18 2022. 9. 26. 12:51

    3장 정리

    3-1. 함수 정의하기 : 함수

    3-2. 함수 정의하기 : 조건문

    3-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장 클래스와 객체 다루기 관련 내용을 작성할 예정이다.

    반응형

    댓글

Designed by Tistory.