[Kotlin] 4. 프로그램의 흐름 제어
※ “Do it! 코틀린 프로그래밍” 을 참고하여 작성하였습니다.
04-1 조건문
조건문을 한 줄로 구성하기
1
val max= if (a>b) a else b
조건문 블록의 표현식이 길어지면 → 중괄호로 감싸야 함
- 블록의 마지막 표현식이 변수로 return
1 2 3 4 5 6 7 8
val max= if (a>b) { println("a 선택") a } else{ println("b 선택") b }
else if 와 in 연산자의 활용 예
- else if: 조건문을 중첩하는데 사용
- in: 변수의 범위 조건을 설정
1 2 3 4 5 6 7
if (score>=90){ grade= 'A' } else if (score in 80.0..89.9){ grade= 'B' } else if (score in 70.0..79.9){ grade= 'C' }
when문으로 다양한 조건 처리하기
- switch-case문과 비슷하다.
[형식]
when(인자){
인자에 일치하는 값 또는 표현식 -> 수행할 문장
…
else ->{
수행할 문장
}
}
when + 조건식
case 1: 조건식에 인자가 활용되지 않는 경우
1 2 3 4
when(x){ parseInt(s) -> print("일치함!") else -> print("기타") }
case 2: 조건식에 in, 범위(…) 연산자가 활용되는 경우
1 2 3 4 5
when(x){ in 1..10 -> print("x는 1 이상 10 이하입니다") !in 10..20 -> print("x는 10 이상 20 이하의 범위에 포함되지 않습니다") else -> print("x는 어떤 범위에도 없습니다.") }
case 3: 조건식에 is 활용
1 2 3 4 5
val str= "안녕하세요" val result= when(str){ is String -> "문자열입니다." else -> false }
case 4: 인자의 자료형이 Any형인 경우
1 2 3 4 5 6 7
when(obj){ // obj: Any형 1 -> println("Int: $obj") "Hello" -> println("String: $obj") is Long -> println("Long: $obj") !is String -> println("Not a String") else -> println("Unknown") }
04-2 반복문
for 문: in과 범위 지정을 활용한 반복
1 2 3 4
for (x in 1..5){ println(x) // 1, 2, 3, 4, 5 } for (x in 1..5) println(x) // 한 줄로 표현 가능: 1, 2, 3, 4, 5
- 다양한 반복 방법
1 2 3 4 5 6
// 하행(no step) for (i in 5 downTo 1) print(i) // 5, 4, 3, 2, 1 // step 만큼 증감 for (i in 1..5 step 2) print(i) // 1, 3, 5 for (i in 5 downTo 1 step 2) print(i) // 5, 3, 1
wihle 문: 조건을 만족하지 않을 때까지 while 문 블록 수행
[형식]
while (조건식){
본문
…
}
do-while 문: 먼저 do 블록을 실행한 다음, while문의 조건을 검사해서 반복할지를 결정
[형식]
do{
본문
} while(조건식)
04-3 흐름의 중단과 반환
흐름 제어문과 예외 처리문
- 흐름 제어문
- return: 함수에서 결과값을 반환하거나 지정된 라벨로 이동
- break: for문이나 while문의 조건식에 상관없이 반복문을 끝냄
- continue: for 문이나 while문의 본문을 모두 수행하지 않고 다시 조건식으로 넘어감
- 예외 처리문
- try {…} catch {…}: try 블록의 본문을 수행하는 도중 예외가 발생하면 catch 블록의 본문을 실행
- try {…} catch {…} finally {…}: 예외가 발생해도 finally 블록 본문은 항상 실행
- 흐름 제어문
return 문
return으로 Unit 반환
- 반환하는 값: Unit 자료형- 반환 값이 없는 것은 아님
람다식에서 return 사용하기
인라인 함수의 매개변수로 람다식을 사용하면, 람다식에서 return을 사용할 수 있음
→ 이 때, 비지역 반환이 일어날 수 있음
람다식에서 라벨 + return: 비지역 반환 방지
[형식]
함수 이름 라벨 이름@{
…
return @라벨이름
…
}
… « 여기 부분으로 빠져나감
1 2 3 4 5 6 7 8 9 10 11 12 13
fun inlineLambda(a: Int, b: Int, out (Int, Int) -> Unit) { out(a, b) } // inline 키워드가 붙지 않음 fun retFunc(){ println("start of retFunc") inlineLambda(13, 3) lib@{ a, b -> val result= a+b if (result>10) reeturn@lit println("result: $result") // 실행되지 않음 } println("end of retFunc") // 비지역 반환이 방지되므로 해당 출력문 실행 }
암묵적 라벨: 람다식 명칭 그대로 라벨로 사용
1 2 3 4 5 6 7 8 9
fun retFunc(){ println("start of retFunc") inlineLambda(13, 3) { a, b -> val result= a+b if (result>10) reeturn@inlineLambda println("result: $result") // 실행되지 않음 } println("end of retFunc") // 비지역 반환이 방지되므로 해당 출력문 실행 }
익명 함수를 사용한 반환
default: 함수에 람다식 대신, 익명 함수를 사용하여 라벨을 사용하지 않고 동일한 결과를 반환
1 2 3 4 5 6 7 8 9
fun retFunc(){ println("start of retFunc") inlineLambda(13, 3, fun (a, b){ val result= a+b if (result>10) return println("result: $result") }) println("end of retFunc") }
람다식, 익명 함수 방법으로 변수 할당
→ 람다식은 라벨을 사용해야 하고, 마지막 값에 return 키워드를 쓰지 않지만
→ 익명 함수는 라벨을 사용할 필요가 없음
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
// 람다식 방법 var num = 10 var getMessage = lambda@ { num: Int -> if (num !in 1..100) { return@lambda "Error" } "Success" } val message = getMessage(num) println("getMessage 10: $message") // 익명 함수 방법 getMessage= fun(num: Int): String{ if (num !in 1..100){ return "Error" } return "Success" } print("getMessage 1000: ") println(getMessage(1000))
람다식, 익명 함수로 함수를 정의하고, 함수를 호출할 때는 ()()를 두 번 써야 함
break, continue 문
- break + 라벨: for문 앞에 라벨을 붙이면 break했을 때, 라벨의 범위 밖으로 벗어남
- continue + 라벨: for문 앞에 라벨을 붙이면 continue했을 때, 라벨의 범위로 다시 돌아감
예외 처리
예외: 정상적으로 실행되다가 비정상적으로 프로그램이 종료되는 경우
- OS의 문제
- 입력 값의 문제
- 받아들일 수 없는 연산
- 메모리의 할당 실패 및 부족
- 컴퓨터 기계 자체의 문제
형식
try{
예외 발생 가능성 있는 문장
} catch(e: 예외 처리 클래스 이름) {
예외를 처리하기 위한 문장
} finally{
반드시 실행되어야 하는 문장
}
특정 예외 처리: e → 특정 행위에 대한 예외 클래스 설정 가능
산술 연산의 예외
1 2 3 4 5
... } catch(e: ArithmeticException){ println("Exception is handled. ${e.message}") } ...
스택의 추적: 임시 메모리 영역인 스택을 추적
1 2 3 4 5
... } catch(e: Exception){ e.printStackTrace() } ...
예외 발생시키기: 사용자가 특정 조건을 설정하여, 그 조건을 만족하면 예외를 발생시킬 수 있음
[형식] throw Exception(message: String)
1 2 3 4 5 6 7 8 9 10 11 12 13 14
... try{ ... checkAmount(100) } catch (e: Exception){ println(e.message) } ... fun checkAmount(amount: Int){ if (amount<1000){ throw Exception("잔고가 $amount 으로 1000 이하입니다.") } }
사용자 정의 예외
[형식] class <사용자 예외="" 클래스="" 이름=""> (message: String): Exception(message)사용자>
- catch(e: 사용자 예외 클래스) { e.message }
- throw 사용자 예외 클래스(message)