프로그램은 순서대로만 움직이지 않는다
앞 장에서 우리는 값을 만들고, 비교하고, 논리 연산으로 조건을 표현하는 방법을 배웠습니다.
val score = 85
val passed = score >= 60하지만 실제 프로그램은 여기서 멈추지 않습니다. passed가 true인지 false인지에 따라 다른 일을 해야 합니다. 또 같은 작업을 여러 번 반복해야 할 때도 있습니다.
흐름 제어는 프로그램의 실행 방향을 정하는 문법입니다.
조건에 따라 다른 코드 실행하기
여러 경우 중 하나 선택하기
같은 작업을 정해진 횟수만큼 반복하기
특정 조건에서 반복을 멈추거나 건너뛰기
프로그램은 결국 조건을 판단하고 반복을 제어하는 구조 위에서 움직입니다.

if로 조건에 따라 다르게 실행하기
가장 기본적인 조건문은 if입니다.
fun main() {
val score = 72
if (score >= 60) {
println("합격입니다")
}
}if 뒤의 조건식이 true이면 중괄호 안의 코드가 실행됩니다. 조건식은 반드시 Boolean 값이어야 합니다.
if (score >= 60) {
println("합격")
}여기서 score >= 60은 true 또는 false가 되는 비교식입니다.
조건이 맞지 않을 때 실행할 코드는 else에 작성합니다.
fun main() {
val score = 45
if (score >= 60) {
println("합격입니다")
} else {
println("불합격입니다")
}
}조건이 여러 개라면 else if를 사용할 수 있습니다.
fun main() {
val score = 82
if (score >= 90) {
println("A")
} else if (score >= 80) {
println("B")
} else if (score >= 70) {
println("C")
} else {
println("D")
}
}위 코드는 위에서부터 조건을 검사합니다. 먼저 맞는 조건을 만나면 그 블록만 실행하고 나머지는 건너뜁니다. 그래서 조건의 순서가 중요합니다.
예를 들어 다음 코드는 의도와 다르게 동작합니다.
val score = 95
if (score >= 60) {
println("D 이상")
} else if (score >= 90) {
println("A")
}95는 score >= 60을 먼저 만족하므로 두 번째 조건까지 가지 않습니다. 점수 등급처럼 범위가 겹치는 조건은 더 구체적인 조건을 먼저 두어야 합니다.
if를 값으로 사용하기
코틀린의 if는 단순한 문장이 아니라 값을 만들 수 있는 표현식입니다.
fun main() {
val score = 75
val result = if (score >= 60) {
"합격"
} else {
"불합격"
}
println(result)
}score >= 60이 참이면 "합격"이 result에 들어갑니다. 거짓이면 "불합격"이 들어갑니다.
이런 방식은 코틀린에서 자주 사용합니다. 변수를 먼저 만들고 나중에 값을 바꾸는 방식보다 코드가 간결하고 안전합니다.
// 덜 코틀린다운 방식
var result = ""
if (score >= 60) {
result = "합격"
} else {
result = "불합격"
}
// 더 코틀린다운 방식
val result = if (score >= 60) "합격" else "불합격"코틀린에는 자바나 자바스크립트의 삼항 연산자처럼 조건 ? 값1 : 값2 문법이 없습니다. 대신 if 자체를 값으로 사용합니다.
val message = if (age >= 19) "입장 가능" else "입장 불가"if를 값으로 사용할 때는 보통 else가 필요합니다. 조건이 거짓일 때 어떤 값을 만들지 정해야 하기 때문입니다.
val result = if (score >= 60) "합격" else "불합격"블록을 사용할 수도 있습니다. 이때 블록의 마지막 줄이 결과값이 됩니다.
fun main() {
val score = 95
val grade = if (score >= 90) {
println("우수한 점수입니다")
"A"
} else {
println("조금 더 연습해 봅시다")
"B 이하"
}
println(grade)
}if 블록 안에서 여러 작업을 할 수 있지만, 값으로 사용할 때는 마지막 줄이 무엇인지 분명해야 합니다.
when으로 여러 조건 분기하기
조건이 많아지면 if - else if - else가 길어집니다.
if (grade == "A") {
println("매우 좋음")
} else if (grade == "B") {
println("좋음")
} else if (grade == "C") {
println("보통")
} else {
println("다시 확인")
}이럴 때는 when을 사용하면 더 읽기 쉽습니다.
fun main() {
val grade = "B"
when (grade) {
"A" -> println("매우 좋음")
"B" -> println("좋음")
"C" -> println("보통")
else -> println("다시 확인")
}
}when은 괄호 안의 값과 각 조건을 비교합니다. 맞는 조건을 만나면 오른쪽 코드가 실행됩니다.
여러 값을 같은 분기로 묶을 수도 있습니다.
fun main() {
val grade = "A"
when (grade) {
"A", "B" -> println("통과")
"C" -> println("재검토")
else -> println("미통과")
}
}"A" 또는 "B"이면 같은 코드가 실행됩니다.
when에서는 범위도 사용할 수 있습니다.
fun main() {
val score = 87
when (score) {
in 90..100 -> println("A")
in 80..89 -> println("B")
in 70..79 -> println("C")
in 0..69 -> println("D")
else -> println("잘못된 점수")
}
}in 80..89는 80부터 89까지의 범위에 값이 들어 있는지 확인합니다. 앞 장에서 배운 범위 연산자가 흐름 제어에서도 자연스럽게 쓰입니다.
when을 값으로 사용하기
if처럼 when도 값을 만들 수 있습니다.
fun main() {
val score = 87
val grade = when (score / 10) {
10, 9 -> "A"
8 -> "B"
7 -> "C"
6 -> "D"
else -> "F"
}
println(grade)
}score / 10의 결과에 따라 문자열 값이 만들어지고, 그 값이 grade에 들어갑니다.
when을 값으로 사용할 때도 모든 경우가 처리되어야 합니다. 위 예제에서는 else가 나머지 모든 경우를 담당합니다.
괄호 안에 비교할 대상을 쓰지 않는 형태도 있습니다.
fun main() {
val temperature = 31
val message = when {
temperature >= 30 -> "덥습니다"
temperature >= 20 -> "쾌적합니다"
temperature >= 10 -> "선선합니다"
else -> "춥습니다"
}
println(message)
}이 형태의 when은 위에서부터 조건식을 검사합니다. if - else if를 더 읽기 좋게 바꾼 형태라고 생각하면 됩니다.
when을 선택할 때 기준은 간단합니다.
조건이 한두 개라면
if가 자연스럽습니다.하나의 값을 여러 경우와 비교한다면
when이 읽기 쉽습니다.조건식이 여러 줄로 늘어나면
when의 대상 없는 형태를 고려할 수 있습니다.
반복문이 필요한 순간
조건문이 "어떤 코드를 실행할지"를 정한다면, 반복문은 "같은 일을 얼마나 반복할지"를 정합니다.
예를 들어 1부터 5까지 출력하고 싶다고 해 봅시다.
println(1)
println(2)
println(3)
println(4)
println(5)이 코드는 동작하지만 좋은 방식은 아닙니다. 반복 횟수가 100번이 되면 같은 코드를 100줄 써야 합니다. 반복문을 사용하면 이렇게 쓸 수 있습니다.
for (number in 1..5) {
println(number)
}반복문은 다음 상황에서 자주 사용합니다.
목록의 모든 요소를 하나씩 처리할 때
정해진 횟수만큼 같은 작업을 반복할 때
조건이 만족될 때까지 계속 시도할 때
중간에 특정 값을 찾으면 멈출 때
for: 범위와 컬렉션을 순회하기
코틀린의 for문은 in과 함께 사용합니다.
for (number in 1..5) {
println(number)
}1..5는 1, 2, 3, 4, 5를 의미합니다. 끝값을 포함합니다.
끝값을 포함하지 않고 싶다면 until을 사용합니다.
for (index in 0 until 5) {
println(index)
}이 코드는 0, 1, 2, 3, 4를 출력합니다. 5는 포함하지 않습니다. 배열이나 리스트의 인덱스를 다룰 때 자주 쓰는 형태입니다.
val names = listOf("민지", "도윤", "서연")
for (index in 0 until names.size) {
println("$index: ${names[index]}")
}하지만 인덱스와 값을 함께 다룰 때는 indices나 withIndex()가 더 자연스러울 수 있습니다.
for (index in names.indices) {
println("$index: ${names[index]}")
}for ((index, name) in names.withIndex()) {
println("$index: $name")
}목록의 값만 필요하다면 더 단순하게 씁니다.
for (name in names) {
println(name)
}for문은 숫자 범위뿐 아니라 컬렉션과도 잘 어울립니다. 리스트, 집합, 맵처럼 여러 값을 가진 자료를 하나씩 처리할 때 기본적으로 떠올릴 수 있는 반복문입니다.
step과 downTo로 반복 방향 조절하기
숫자 반복에서는 간격과 방향을 조절할 수 있습니다.
step은 몇 칸씩 건너뛸지 정합니다.
for (number in 0..10 step 2) {
println(number)
}출력은 0, 2, 4, 6, 8, 10입니다.
큰 수에서 작은 수로 내려가려면 downTo를 사용합니다.
for (number in 5 downTo 1) {
println(number)
}출력은 5, 4, 3, 2, 1입니다.
downTo와 step을 함께 쓸 수도 있습니다.
for (number in 10 downTo 0 step 2) {
println(number)
}출력은 10, 8, 6, 4, 2, 0입니다.
숫자 반복은 다음처럼 읽으면 됩니다.
1..5: 1부터 5까지0 until 5: 0부터 5 전까지5 downTo 1: 5부터 1까지 내려가며0..10 step 2: 0부터 10까지 2씩 증가하며
while: 조건이 참인 동안 반복하기
for는 반복 범위나 컬렉션이 분명할 때 좋습니다. 반면 반복 횟수를 미리 알기 어렵고, 어떤 조건이 참인 동안 계속해야 한다면 while을 사용합니다.
fun main() {
var count = 3
while (count > 0) {
println("count = $count")
count--
}
println("끝")
}while은 조건을 먼저 검사합니다. 조건이 처음부터 거짓이면 블록은 한 번도 실행되지 않습니다.
var number = 0
while (number > 0) {
println(number)
}위 코드는 아무것도 출력하지 않습니다. number > 0이 처음부터 거짓이기 때문입니다.
while을 사용할 때는 조건이 언젠가 거짓이 되도록 만들어야 합니다. 그렇지 않으면 무한 반복이 됩니다.
var count = 1
while (count <= 5) {
println(count)
count++ // 이 줄이 없으면 반복이 끝나지 않는다
}do-while: 적어도 한 번은 실행하기
do-while은 조건을 나중에 검사합니다. 그래서 블록이 적어도 한 번은 실행됩니다.
fun main() {
var input: String
do {
print("명령을 입력하세요: ")
input = readln()
} while (input != "quit")
}사용자 입력처럼 "일단 한 번 실행한 뒤 계속할지 결정하는" 흐름에 어울립니다.
while과 do-while의 차이는 검사 시점입니다.
while: 조건을 먼저 검사한다.do-while: 블록을 먼저 실행하고 조건을 검사한다.
처음에는 for와 while을 가장 많이 사용하게 됩니다. do-while은 "최소 한 번 실행"이 자연스러운 상황에서 선택하면 됩니다.
break: 반복을 즉시 끝내기
반복문 안에서 더 이상 반복할 필요가 없을 때는 break를 사용합니다.
fun main() {
val numbers = listOf(3, 7, 10, 15, 20)
for (number in numbers) {
if (number % 2 == 0) {
println("첫 번째 짝수: $number")
break
}
}
}이 코드는 첫 번째 짝수를 찾으면 반복을 끝냅니다. 10을 찾은 뒤에는 15, 20을 더 확인하지 않습니다.
break는 반복 전체를 빠져나갑니다. 필요한 값을 찾았거나, 더 이상 진행하면 안 되는 조건을 만났을 때 사용합니다.
continue: 이번 반복만 건너뛰기
continue는 반복문을 끝내지는 않습니다. 대신 현재 차례의 나머지 코드를 건너뛰고 다음 반복으로 넘어갑니다.
fun main() {
val numbers = listOf(1, 2, 3, 4, 5)
for (number in numbers) {
if (number % 2 == 0) {
continue
}
println(number)
}
}이 코드는 홀수만 출력합니다. 짝수를 만나면 println(number)까지 가지 않고 다음 숫자로 넘어갑니다.
continue는 "이 값은 처리하지 않고 넘어간다"는 뜻을 표현할 때 유용합니다.
val names = listOf("민지", "", "도윤", " ", "서연")
for (name in names) {
if (name.isBlank()) continue
println("이름: $name")
}빈 문자열은 건너뛰고, 실제 이름만 출력합니다.
label로 중첩 반복문 제어하기
반복문이 중첩되어 있을 때 break와 continue는 기본적으로 가장 가까운 반복문에만 영향을 줍니다.
for (row in 1..3) {
for (col in 1..3) {
if (row == 2 && col == 2) {
break
}
println("row=$row, col=$col")
}
}위 코드의 break는 안쪽 for만 끝냅니다. 바깥쪽 for는 계속됩니다.
바깥 반복문까지 한 번에 끝내고 싶다면 라벨을 사용할 수 있습니다.
outer@ for (row in 1..3) {
for (col in 1..3) {
if (row == 2 && col == 2) {
break@outer
}
println("row=$row, col=$col")
}
}outer@는 바깥 반복문에 붙인 이름입니다. break@outer는 그 이름이 붙은 반복문을 끝냅니다.
continue에도 라벨을 사용할 수 있습니다.
outer@ for (row in 1..3) {
for (col in 1..3) {
if (col == 2) {
continue@outer
}
println("row=$row, col=$col")
}
}이 코드는 col == 2를 만나면 안쪽 반복의 다음 차례가 아니라 바깥 반복의 다음 row로 넘어갑니다.
라벨은 강력하지만 자주 쓰면 흐름을 따라가기 어려워질 수 있습니다. 중첩 반복이 복잡해진다면 별도 함수로 분리하고 return을 사용하는 편이 더 읽기 좋을 때도 많습니다.
조건문과 반복문을 함께 사용하기
실제 코드는 조건문과 반복문을 함께 사용합니다. 예를 들어 점수 목록에서 유효한 점수만 골라 평균을 구해 봅시다.
fun main() {
val scores = listOf(90, 85, -1, 100, 120, 70)
var total = 0
var count = 0
for (score in scores) {
if (score !in 0..100) {
continue
}
total += score
count++
}
val average = if (count == 0) {
0.0
} else {
total.toDouble() / count
}
println("유효한 점수 개수: $count")
println("평균: $average")
}이 예제에는 여러 흐름 제어가 함께 들어 있습니다.
for로 점수 목록을 하나씩 봅니다.if로 유효하지 않은 점수를 판단합니다.continue로 잘못된 점수는 건너뜁니다.마지막에
if표현식으로 평균을 계산합니다.
나중에 컬렉션 함수를 배우면 이 코드를 더 짧게 쓸 수 있습니다. 하지만 먼저 반복문과 조건문의 기본 흐름을 이해해야 합니다. 그래야 더 간결한 문법을 보더라도 내부에서 어떤 일이 일어나는지 이해할 수 있습니다.
자주 하는 실수
if 조건에 Boolean이 아닌 값을 넣는다
val count = 3
// if (count) { } // 오류코틀린의 if 조건은 반드시 Boolean이어야 합니다. 숫자 0을 거짓처럼 취급하지 않습니다.
if (count > 0) {
println("값이 있습니다")
}if 표현식에서 else를 빠뜨린다
val score = 80
// val result = if (score >= 60) "합격" // 오류가 될 수 있음값을 만들어 변수에 넣으려면 조건이 거짓일 때의 값도 필요합니다.
val result = if (score >= 60) "합격" else "불합격"조건 순서를 잘못 둔다
val score = 95
val grade = if (score >= 60) {
"D"
} else if (score >= 90) {
"A"
} else {
"F"
}이 코드는 95에도 "D"를 반환합니다. 더 구체적인 조건을 먼저 검사해야 합니다.
val grade = if (score >= 90) {
"A"
} else if (score >= 60) {
"D"
} else {
"F"
}while 반복 조건을 바꾸지 않는다
var count = 1
while (count <= 5) {
println(count)
// count++가 없으면 끝나지 않는다
}while을 사용할 때는 반복이 끝날 수 있는 조건을 반드시 확인해야 합니다.
break와 continue의 차이를 헷갈린다
break: 반복문을 끝냅니다.continue: 이번 차례만 건너뛰고 다음 반복으로 갑니다.
둘 다 흐름을 바꾸는 문법이므로 남용하지 않는 편이 좋습니다. 조건을 반대로 정리하거나 함수를 분리하면 더 읽기 쉬운 코드가 될 때도 많습니다.
연습 문제
다음 문제를 직접 입력해 보세요. 흐름 제어는 눈으로 읽는 것보다 직접 실행하며 결과를 확인할 때 훨씬 빨리 익숙해집니다.
문제 1
점수 하나를 변수로 선언하고 다음 규칙에 따라 등급을 출력해 보세요.
90 이상: A
80 이상 90 미만: B
70 이상 80 미만: C
그 외: D
if 표현식과 when 표현식 두 가지 방식으로 작성해 보세요.
문제 2
1부터 100까지의 숫자 중 짝수만 출력해 보세요.
힌트: for, 범위 연산자, % 연산자를 사용하세요.
문제 3
1부터 10까지의 합계를 구해 출력해 보세요.
합계: 55문제 4
다음 리스트에서 빈 문자열을 제외하고 이름만 출력해 보세요.
val names = listOf("민지", "", "도윤", " ", "서연")힌트: isBlank()와 continue를 사용해 보세요.
문제 5
숫자 리스트에서 첫 번째로 10보다 큰 값을 찾아 출력하고, 찾으면 반복을 멈추세요.
val numbers = listOf(3, 8, 12, 5, 20)예상 출력은 다음과 같습니다.
첫 번째 큰 값: 12정리
이번 장에서는 프로그램의 실행 흐름을 제어하는 방법을 배웠습니다.
if는 조건이 참일 때 코드를 실행합니다.if는 값을 만드는 표현식으로도 사용할 수 있습니다.코틀린에는 삼항 연산자가 없고, 대신
if표현식을 사용합니다.when은 여러 경우를 분기할 때 읽기 좋은 문법입니다.when도 값을 만드는 표현식으로 사용할 수 있으며, 모든 경우를 처리해야 합니다.for는 범위나 컬렉션을 순회할 때 사용합니다.while은 조건이 참인 동안 반복합니다.do-while은 블록을 최소 한 번 실행한 뒤 조건을 검사합니다...,until,downTo,step으로 숫자 반복 범위와 방향을 조절할 수 있습니다.break는 반복을 끝내고,continue는 현재 차례만 건너뜁니다.중첩 반복문에서는 라벨을 사용해 바깥 반복문을 제어할 수 있지만, 복잡해지면 함수 분리를 먼저 고려하는 편이 좋습니다.
값을 만들고 계산하는 방법에 조건과 반복이 더해지면, 프로그램은 상황에 따라 다르게 움직일 수 있습니다. 다음 장에서는 이런 코드 조각에 이름을 붙이고 재사용할 수 있도록 함수 문법을 배웁니다.
이 노트는 보도·비평·교육·연구 목적으로 작성되었습니다. 저작권 문의가 있으시면 에서 알려주세요.