본 게시글은 부스트코스의 코틀린 기본프로그래밍을
시청한 후 학습한 정보를 기록하는 목적의 게시글입니다.
본 게시글은 부스트코스 서포터즈 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
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 이하입니다.")
}
'오픈튜토리얼스 > 코틀린 프로그래밍 기본' 카테고리의 다른 글
[부스트코스|코틀린] 3단원 5장. 프로그램의 흐름을 제어해 보자 (1) (0) | 2021.02.18 |
---|---|
[부스트코스|코틀린] 2단원 4장. 요술상자, 함수 가지고 놀기 (2) (0) | 2021.02.16 |
[부스트코스|코틀린] 2단원 4장. 요술상자, 함수 가지고 놀기 (1) (0) | 2021.02.11 |
[부스트코스|코틀린] 2단원 3장. 마법의 요술상자, 함수의 기본 (2) (0) | 2021.02.10 |
[부스트코스|코틀린] 2단원 3장. 마법의 요술상자, 함수의 기본 (1) (0) | 2021.02.07 |
최근댓글