본 게시글은 부스트코스의 코틀린 기본프로그래밍을

시청한 후 학습한 정보를 기록하는 목적의 게시글입니다.

부스트코스

 

다 함께 배우고 성장하는 부스트코스

부스트코스(boostcourse)는 모두 함께 배우고 성장하는 비영리 SW 온라인 플랫폼입니다.

www.boostcourse.org

코틀린 기본프로그래밍(1/2)

 

코틀린 프로그래밍 기본1/2(함수편)

부스트코스 무료 강의

www.boostcourse.org

본 게시글은 부스트코스 서포터즈 3기 활동 게시글입니다.


#5-3. 흐름의 중단과 반환 (1)

- 들어가기 전에

프로그램의 흐름은 언제든 중단되거나 특정 조건식으로 돌아가는등 다양한 상황에 맞춰 조정해 주어야 할 필요가 있습니다. 이때 return, break, continue문을 사용하게 되는데 하나씩 자세히 살펴보겠습니다.

 

- 핵심 키워드

  • return
  • break
  • 라벨 표기 (label@)

 

1) 흐름 제어 관련 요약

흐름 제어문

- return : 함수에서 결괏값을 반환하거나 지정된 라벨로 이동

- break : for이나 while의 조건식에 상관없이 반복문을 끝냄

- continue : for이나 while의 반복문의 본문을 모두 수행하지 않고 다시 조건으로 넘어감

 

예외 처리문

- try { ... } catch { ... } : try 블록의 본문을 수행하는 도중 예외가 발생하면 catch 블록의 본문을 실행

- try { ... } catch { ... } finally { ... } : 예외가 발생해도 finally 블록 본문은 항상 실행

 

2) return의 사용

보통 return문은 함수 등에서 값을 반환하는데 사용된다.

fun add(a : Int, b: Int): Int {
     return a+b
     println("이 코드는 실행되지 않습니다.") //여기에 도달하지 않음
}
// Unit을 명시적으로 반환
fun hello(name : String): Unit {
     println(name)
     return Unit
}

// Unit 이름을 생략한 반환
fun hello(name : String): Unit {
     println(name)
     return
}

// return문 자체를 생략
fun hello(name : String): Unit {
     println(name)
     return Unit
}

하지만 코드의 흐름을 중단하고 함수등을 빠져 나가기 위해서도 return문을 사용할 수 있다.

 

3) 람다식에서의 return

fun main() {

    retFunc()
}

inline fun inlineLambda(a: Int, b: Int, out: (Int, Int) -> Unit) {
    out(a, b)
}

fun retFunc() {
    println("start of retFunc") // 1
    inlineLambda(13, 3) { a, b -> // 2
        val result = a + b
        if(result > 10) return // 3 : 10보다 크면 이 함수를 빠져 나감
        println("result: $result") // 4 : 10보다 크면 이 문장에 도달하지 못함
    }
    println("end of retFunc") // 5
}

 

4) 라벨을 사용한 리턴

인라인(inline)으로 선언되지 않은 람다식 함수에서 return을 사용할 때는 그냥 사용할 수 없다. 

return@label과 같이 라벨(label) 표기와 함께 사용해야 하는데, 

라벨이란 코드에서 특정한 위치를 임의로 표시한 것으로, @ 기호를 뒤에 붙이는 것으로 사용할 수 있다.

람다식 함수명 라벨이름@ {
    ...
    return@라벨이름
}
fun main() {

    retFunc()
}

inline fun inlineLambda(a: Int, b: Int, out: (Int, Int) -> Unit) {
    out(a, b)
}

fun retFunc() {
    println("start of retFunc") 
    inlineLambda(a: 12, b: 3) lit@{ a, b 
        val result = a + b
        if(result > 10) return@lit 
        println("result: $result") 
    }
    println("end of retFunc") 
}

 

#5-3. 흐름의 중단과 반환 (2)

- 들어가기 전에

계속 이어서 암묵적 라벨 표현방법이나 익명함수에서 반환 하는 방법과 break, continue 대해서 살펴봅니다. 

 

- 핵심 키워드

  • 암묵적 라벨
  • 익명 함수를 사용한 반환
  • break
  • continue

 

1) 암묵적 라벨

람다식 표현식 블록에 직접 라벨을 쓰는 것이 아닌

람다식 함수의 명칭을 그대로 라벨처럼 사용할 수 있는데 이를 암묵적 라벨이라고 부른다.

...
fun retFunc() {
    println("start of retFunc")
    inlineLambda(13, 3) { a, b -> 
        val result = a + b
        if(result > 10) return@inlineLambda 
        println("result: $result")
    } 
    println("end of retFunc") 
}
...

위 코드처럼 람다식 함수의 이름을 직접 라벨처럼 사용할 수 있다.

결과는 라벨을 사용한 예제와 동일하게 inlineLambda()로 빠져나간다.

 

2) 익명함수를 사용한 반환

물론 람다식 함수 표현식 대신에 익명 함수를 넣을 수도 있다.

fun retFunc() {
    println("start of retFunc")
    inlineLambda(13, 3, fun(a, b) {
        val result = a + b
        if(result > 10) return 
        println("result: $result")
    )} //inlineLambda()함수의 끝 
    println("end of retFunc") 
}

이때는 익명함수 내부에서 라벨을 사용하지 않고 단순히 return만 사용하더라도

비지역 반환이 일어나지 않기에 일반 함수의 반환처럼 편하게 사용할 수 있다. 

 

3) 람다식 함수 vs 익명 함수

- 람다식 방법

...
    val getMessage = lambda@ { num: Int ->
        if(num !in 1..100){
            return@lambda "Error" // 레이블을 통한 반환
        }
        "Sucess" //마지막 식이 반환
    }
...

- 익명함수 방법

...
    val getMessage = fun(num:Int): String{
        if(num !in 1..100){
            return "Error" 
        }
        return "Sucess" 
    }
...

val result = getMessage(99)

 

4) break와 continue

https://www.boostcourse.org/mo132/lecture/59984

 

fun maun() {
    for(i in 1..5) {
        if ( i == 3 ) break
        print(i)
    }
    println() //개행 문자
    println("outside")
}
12
outside
fun maun() {
    for(i in 1..5) {
        if ( i == 3 ) continue
        print(i)
    }
    println() //개행 문자
    println("outside")
}
1245
outside

 

5) break와 라벨 함께 사용하기

break와 함께 라벨을 사용하여 중단되는 위치를 바꿀 수 있다.

fun labelBreak() {
    println("labelBreak")
    for(i in 1..5) {
        second@ for (j in 1..5) {
            if (j == 3) break
            println("i:$i, j:$j")
        }
        println("after for j")
    }
    println("after for i")
} 

단순히 break를 사용한 경우 중첩되어 있는 두 번째 for문이 중단되어 첫 번째 for문의 조건으로 돌아간다.

fun labelBreak() {
    println("labelBreak")
    first@ for(i in 1..5) {
        second@ for (j in 1..5) {
            if (j == 3) break@first
            println("i:$i, j:$j")
        }
        println("after for j")
    }
    println("after for i")
} 

break@first와 같이 라벨을 사용할 때는 첫 번째 for문 first@ for의 블록 자체를 빠져나가게 된다.

 

#5-4. 예외가 발생했어요!

- 들어가기 전에

예외란 프로그램에서 코드가 제대로 작동하지 못하고 중단되는 경우를 말합니다. 이것을 처리하기 위해서는 예외 처리 블록을 구성해야 합니다. 한번 알아봅시다.

 

- 핵심 키워드

  • try~catch
  • finally
  • Exception
  • throw Exception

 

1) 예외란

프로그램 코드를 작성하다 보면 해당 코드가 제대로 작동하지 못하고 중단되는 현상이 발생할 수 있다.

이것을 예외라 하며, 대부분의 에러는 코드를 작성하는 도중 컴파일러가 캐치할 수 있다.

하지만 메모리 부족이나 파일이 손상되는 등 실행 도중의 잠재적인 오류까지 검사할 수 없기 때문에

비정상적으로 프로그램이 종료될 수 있다.

  • 운영체제의 문제 (잘못된 시스템 호출의 문제)
  • 입력값의 문제 (존재하지 않는 파일, 숫자 입력란에 문자 입력 등)
  • 받아들일 수 있는 연산 (0으로 나누기 등)
  • 메모리의 할당 실패 및 부족
  • 컴퓨터 기계 자체의 문제 (전원 문제, 망가진 기억 장치 등)

 

2) 예외구문 사용법

try {
    예외 발생 가능성 있는 문장
} catch (e: 예외처리 클래스명) {
    예외를 처리하기 위한 문장
} finally {
   반드시 실행되어야 하는 문장
}
보통 try블록 내에

보통 try블록 내에 예외를 발생할 수 있는 코드를 작성하고 catch 블록에서 인자는 예외를 위한 클래스를 작성한다다.

만일 일치하는 catch 예외가 없어 처리할 수 없으면 프로그램이 중단된다.

finally 블록은 try블록의 예외 발생 여부에 상관없이 반드시 처리되어야 하는 문장을 작성한다.

 fun main() {
     val a = 6
     val b = 0
     va c: Int
     
     try {
         c = a / b
     } catch (e: Exception) {
         println("Exception")
     } finally {
         println("Finally")
     }
}
Exception
Finally

 

3) 특정 예외처리

 산술 연산에 대한 예외를 따로 특정해서 잡을때

...
} catch (e: ArithemeticException){
    println("Exception in handled. ${e.message}")
}

Exception in handled. / by zero

! finally 블록은 반드시 항상 실행됨

스택의 추적

...
} catch (e: Exception){
    e.printStackTrace()
}
...

 

4) 예외 발생시키기

예외를 의도적으로 발생 시키기 위해서 throw 키워드를 사용할 수 있다.

throw Exception(message: String)
fun main() {

    val amount = 600
    
    try{
        amout -= 100
        checkAmount(amount)
    } catch(e : Exception) {
        println(e.message)
    }
    println("amount: $amount")
}

fun checkAmount(amount: Int){
    if(amount < 1000)
        thorw Exception("잔고가 $amount 으로 1000 이하입니다.")

}
  • 네이버 블러그 공유하기
  • 네이버 밴드에 공유하기
  • 페이스북 공유하기
  • 카카오스토리 공유하기