Kim-Baek 개발자 이야기

Kotlin 제어 구조 완벽 가이드 | if, when, for, while 마스터하기 본문

개발/java basic

Kotlin 제어 구조 완벽 가이드 | if, when, for, while 마스터하기

김백개발자 2025. 12. 21. 22:44
반응형

이 글을 읽으면: Java의 제어문과 완전히 다른 Kotlin의 강력한 제어 구조를 배울 수 있습니다. if를 표현식으로 사용하고, when으로 switch를 대체하며, for 루프를 더 간결하게 작성하는 방법을 실전 예제로 마스터하세요.


📌 목차

  1. 들어가며 - Java 제어문의 한계
  2. if는 표현식이다 - 값을 반환하는 if
  3. when - switch의 강력한 대안
  4. for 루프 - range와 컬렉션 순회
  5. while과 do-while
  6. break, continue, return - 라벨 활용
  7. 실전 패턴 모음
  8. 마무리 - 다음 편 예고

들어가며 - Java 제어문의 한계

Java로 간단한 등급 계산을 할 때 이런 경험 있으신가요?

// Java - if문은 statement (값 반환 불가)
String grade;
if (score >= 90) {
    grade = "A";
} else if (score >= 80) {
    grade = "B";
} else if (score >= 70) {
    grade = "C";
} else {
    grade = "F";
}

// switch문의 한계
String message;
switch (dayOfWeek) {
    case "월":
    case "화":
    case "수":
    case "목":
    case "금":
        message = "평일입니다";
        break;
    case "토":
    case "일":
        message = "주말입니다";
        break;
    default:
        message = "잘못된 입력";
        break;
}

Kotlin은 이렇게 간단합니다:

// Kotlin - if는 expression (값 반환)
val grade = if (score >= 90) "A"
    else if (score >= 80) "B"
    else if (score >= 70) "C"
    else "F"

// when - 강력하고 유연함
val message = when (dayOfWeek) {
    "월", "화", "수", "목", "금" -> "평일입니다"
    "토", "일" -> "주말입니다"
    else -> "잘못된 입력"
}

오늘은 Kotlin의 제어 구조를 완전히 마스터해보겠습니다!


if 표현식 - 값을 반환하는 if

기본 사용법

Kotlin의 if는 값을 반환할 수 있는 표현식(expression)입니다.

fun main() {
    val score = 85
    
    // if를 표현식으로 사용
    val grade = if (score >= 90) "A" else "B"
    println(grade)  // B
}

다중 조건 - if-else if-else

fun getGrade(score: Int): String {
    return if (score >= 90) "A"
    else if (score >= 80) "B"
    else if (score >= 70) "C"
    else if (score >= 60) "D"
    else "F"
}

fun main() {
    println(getGrade(85))  // B
    println(getGrade(95))  // A
    println(getGrade(55))  // F
}

블록으로 사용 - 마지막 표현식이 반환값

fun main() {
    val number = 42
    
    val result = if (number > 0) {
        println("양수입니다")
        "positive"  // 마지막 값이 반환됨
    } else {
        println("음수 또는 0입니다")
        "negative or zero"
    }
    
    println(result)  // positive
}

실전 예제 - 할인율 계산

fun calculateDiscount(price: Int, isMember: Boolean): Int {
    val discountRate = if (isMember) {
        if (price >= 100000) 0.2      // VIP 회원 20%
        else 0.1                       // 일반 회원 10%
    } else {
        if (price >= 100000) 0.1      // 비회원 대량 구매 10%
        else 0.0                       // 비회원 일반 구매 0%
    }
    
    return (price * (1 - discountRate)).toInt()
}

fun main() {
    println(calculateDiscount(150000, true))   // 120000 (20% 할인)
    println(calculateDiscount(50000, true))    // 45000 (10% 할인)
    println(calculateDiscount(150000, false))  // 135000 (10% 할인)
}

Java와 비교

// Java - 삼항 연산자로만 값 반환 가능
String grade = (score >= 90) ? "A" : 
               (score >= 80) ? "B" : 
               (score >= 70) ? "C" : "F";

// 복잡한 로직은 변수 할당 필요
String result;
if (condition) {
    result = "A";
} else {
    result = "B";
}
// Kotlin - if 자체가 표현식
val grade = if (score >= 90) "A"
    else if (score >= 80) "B"
    else if (score >= 70) "C"
    else "F"

// 복잡한 로직도 직관적
val result = if (condition) {
    // 여러 줄 로직
    "A"  // 마지막 값 반환
} else {
    "B"
}

when 표현식 - switch의 강력한 대안

기본 사용법

fun main() {
    val dayOfWeek = 3
    
    val dayName = when (dayOfWeek) {
        1 -> "월요일"
        2 -> "화요일"
        3 -> "수요일"
        4 -> "목요일"
        5 -> "금요일"
        6 -> "토요일"
        7 -> "일요일"
        else -> "잘못된 입력"
    }
    
    println(dayName)  // 수요일
}

여러 값 매칭 - 콤마로 구분

fun isWeekend(day: String): Boolean {
    return when (day) {
        "토", "일" -> true
        "월", "화", "수", "목", "금" -> false
        else -> throw IllegalArgumentException("잘못된 요일")
    }
}

fun main() {
    println(isWeekend("토"))  // true
    println(isWeekend("월"))  // false
}

범위 매칭 - in 연산자

fun getAgeGroup(age: Int): String {
    return when (age) {
        in 0..12 -> "어린이"
        in 13..19 -> "청소년"
        in 20..64 -> "성인"
        in 65..120 -> "노인"
        else -> "잘못된 나이"
    }
}

fun main() {
    println(getAgeGroup(10))   // 어린이
    println(getAgeGroup(25))   // 성인
    println(getAgeGroup(70))   // 노인
}

타입 체크 - is 연산자

fun describe(obj: Any): String {
    return when (obj) {
        is String -> "문자열, 길이: ${obj.length}"
        is Int -> "정수: $obj"
        is List<*> -> "리스트, 크기: ${obj.size}"
        is Boolean -> if (obj) "참" else "거짓"
        else -> "알 수 없는 타입"
    }
}

fun main() {
    println(describe("Kotlin"))        // 문자열, 길이: 6
    println(describe(42))              // 정수: 42
    println(describe(listOf(1, 2, 3))) // 리스트, 크기: 3
    println(describe(true))            // 참
}

조건식으로 사용 - 인자 없는 when

fun getGradeMessage(score: Int): String {
    return when {
        score >= 90 -> "훌륭합니다!"
        score >= 80 -> "잘했습니다!"
        score >= 70 -> "괜찮습니다!"
        score >= 60 -> "노력하세요!"
        else -> "더 분발하세요!"
    }
}

fun main() {
    println(getGradeMessage(95))  // 훌륭합니다!
    println(getGradeMessage(75))  // 괜찮습니다!
}

블록으로 사용

fun processPayment(amount: Int, method: String): String {
    return when (method) {
        "card" -> {
            println("카드 결제 진행 중...")
            val fee = amount * 0.03
            "결제 완료: ${amount + fee.toInt()}원 (수수료 포함)"
        }
        "cash" -> {
            println("현금 결제 진행 중...")
            "결제 완료: ${amount}원"
        }
        "point" -> {
            println("포인트 결제 진행 중...")
            val discount = amount * 0.05
            "결제 완료: ${amount - discount.toInt()}원 (할인 적용)"
        }
        else -> "지원하지 않는 결제 방법"
    }
}

fun main() {
    println(processPayment(10000, "card"))
    // 카드 결제 진행 중...
    // 결제 완료: 10300원 (수수료 포함)
}

실전 예제 - HTTP 상태 코드 처리

fun handleHttpResponse(statusCode: Int): String {
    return when (statusCode) {
        in 200..299 -> "성공"
        in 300..399 -> "리다이렉션"
        400 -> "잘못된 요청"
        401 -> "인증 필요"
        403 -> "권한 없음"
        404 -> "찾을 수 없음"
        in 400..499 -> "클라이언트 오류"
        in 500..599 -> "서버 오류"
        else -> "알 수 없는 상태"
    }
}

fun main() {
    println(handleHttpResponse(200))  // 성공
    println(handleHttpResponse(404))  // 찾을 수 없음
    println(handleHttpResponse(500))  // 서버 오류
}

Java switch와 비교

// Java - 제한적이고 장황함
String result;
switch (dayOfWeek) {
    case 1:
        result = "월요일";
        break;
    case 2:
        result = "화요일";
        break;
    // ... 반복
    default:
        result = "잘못된 입력";
        break;
}

// Java 14+ enhanced switch (값 반환)
String result = switch (dayOfWeek) {
    case 1 -> "월요일";
    case 2 -> "화요일";
    default -> "잘못된 입력";
};
// Kotlin - 간결하고 강력함
val result = when (dayOfWeek) {
    1 -> "월요일"
    2 -> "화요일"
    else -> "잘못된 입력"
}

// 범위, 타입, 조건 모두 가능
val result = when {
    score >= 90 -> "A"
    age in 20..30 -> "20대"
    obj is String -> "문자열"
    else -> "기타"
}

for 루프 - range와 컬렉션 순회

기본 range 순회

fun main() {
    // 1부터 5까지
    for (i in 1..5) {
        println(i)  // 1, 2, 3, 4, 5
    }
    
    // 1부터 4까지 (5 미포함)
    for (i in 1 until 5) {
        println(i)  // 1, 2, 3, 4
    }
    
    // 역순
    for (i in 5 downTo 1) {
        println(i)  // 5, 4, 3, 2, 1
    }
    
    // 2씩 증가
    for (i in 1..10 step 2) {
        println(i)  // 1, 3, 5, 7, 9
    }
}

리스트 순회

fun main() {
    val fruits = listOf("사과", "바나나", "오렌지")
    
    // 값만 순회
    for (fruit in fruits) {
        println(fruit)
    }
    
    // 인덱스와 함께 순회
    for ((index, fruit) in fruits.withIndex()) {
        println("$index: $fruit")
    }
    // 0: 사과
    // 1: 바나나
    // 2: 오렌지
}

맵(Map) 순회

fun main() {
    val scores = mapOf(
        "국어" to 90,
        "영어" to 85,
        "수학" to 95
    )
    
    for ((subject, score) in scores) {
        println("$subject: $score점")
    }
    // 국어: 90점
    // 영어: 85점
    // 수학: 95점
}

실전 예제 - 구구단

fun printMultiplicationTable() {
    for (i in 2..9) {
        println("=== ${i}단 ===")
        for (j in 1..9) {
            println("$i × $j = ${i * j}")
        }
        println()
    }
}

fun main() {
    printMultiplicationTable()
}

실전 예제 - 별 찍기

fun printTriangle(height: Int) {
    for (i in 1..height) {
        for (j in 1..i) {
            print("*")
        }
        println()
    }
}

fun main() {
    printTriangle(5)
    // *
    // **
    // ***
    // ****
    // *****
}

Java와 비교

// Java - 전통적인 for문
for (int i = 0; i < 5; i++) {
    System.out.println(i);
}

// Java - enhanced for
List<String> fruits = Arrays.asList("사과", "바나나");
for (String fruit : fruits) {
    System.out.println(fruit);
}

// 인덱스 필요하면 수동으로
for (int i = 0; i < fruits.size(); i++) {
    System.out.println(i + ": " + fruits.get(i));
}
// Kotlin - range 기반
for (i in 0..4) {
    println(i)
}

// 컬렉션 순회
val fruits = listOf("사과", "바나나")
for (fruit in fruits) {
    println(fruit)
}

// 인덱스와 함께
for ((i, fruit) in fruits.withIndex()) {
    println("$i: $fruit")
}

while 루프

while

fun main() {
    var count = 1
    
    while (count <= 5) {
        println("Count: $count")
        count++
    }
    // Count: 1
    // Count: 2
    // Count: 3
    // Count: 4
    // Count: 5
}

do-while

fun main() {
    var input: String
    
    do {
        println("숫자를 입력하세요 (종료: q): ")
        input = readLine() ?: "q"
        
        if (input != "q") {
            val number = input.toIntOrNull()
            if (number != null) {
                println("입력값: $number")
            } else {
                println("올바른 숫자를 입력하세요")
            }
        }
    } while (input != "q")
    
    println("프로그램 종료")
}

실전 예제 - 사용자 입력 검증

fun readValidAge(): Int {
    var age: Int? = null
    
    while (age == null || age !in 0..150) {
        println("나이를 입력하세요 (0-150): ")
        age = readLine()?.toIntOrNull()
        
        if (age == null) {
            println("숫자를 입력해주세요!")
        } else if (age !in 0..150) {
            println("올바른 나이를 입력해주세요!")
        }
    }
    
    return age
}

흐름 제어 - break, continue, return

break - 루프 종료

fun main() {
    for (i in 1..10) {
        if (i == 5) break
        println(i)  // 1, 2, 3, 4
    }
}

continue - 다음 반복으로

fun main() {
    for (i in 1..10) {
        if (i % 2 == 0) continue  // 짝수는 건너뛰기
        println(i)  // 1, 3, 5, 7, 9
    }
}

라벨을 사용한 break/continue

fun main() {
    outer@ for (i in 1..3) {
        for (j in 1..3) {
            if (i == 2 && j == 2) break@outer  // 외부 루프 종료
            println("i=$i, j=$j")
        }
    }
    // i=1, j=1
    // i=1, j=2
    // i=1, j=3
    // i=2, j=1
}

라벨로 특정 루프만 continue

fun main() {
    outer@ for (i in 1..3) {
        for (j in 1..3) {
            if (j == 2) continue@outer  // 외부 루프의 다음 반복으로
            println("i=$i, j=$j")
        }
    }
    // i=1, j=1
    // i=2, j=1
    // i=3, j=1
}

실전 패턴 모음

패턴 1: 조건에 따른 값 선택

fun getShippingCost(weight: Double): Int {
    return when {
        weight <= 0 -> 0
        weight <= 1.0 -> 3000
        weight <= 5.0 -> 5000
        weight <= 10.0 -> 8000
        else -> 8000 + ((weight - 10) * 1000).toInt()
    }
}

패턴 2: 여러 조건 조합

fun canVote(age: Int, isCitizen: Boolean, hasId: Boolean): Boolean {
    return when {
        !isCitizen -> false
        !hasId -> false
        age < 18 -> false
        else -> true
    }
}

패턴 3: Sealed Class와 when

sealed class Result {
    data class Success(val data: String) : Result()
    data class Error(val message: String) : Result()
    object Loading : Result()
}

fun handleResult(result: Result): String {
    return when (result) {
        is Result.Success -> "데이터: ${result.data}"
        is Result.Error -> "오류: ${result.message}"
        Result.Loading -> "로딩 중..."
    }  // else 불필요! (sealed class는 모든 경우 체크)
}

패턴 4: 컬렉션 필터링

fun main() {
    val numbers = listOf(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)
    
    // 짝수만
    val evens = numbers.filter { it % 2 == 0 }
    println(evens)  // [2, 4, 6, 8, 10]
    
    // 5보다 큰 수만
    val greaterThan5 = numbers.filter { it > 5 }
    println(greaterThan5)  // [6, 7, 8, 9, 10]
}

마무리 - 다음 편 예고

오늘 배운 것 ✅

  • if를 표현식으로 사용해 값 반환
  • when으로 다양한 패턴 매칭
  • for로 range와 컬렉션 순회
  • while, do-while 루프
  • break, continue, 라벨 활용

다음 편에서 배울 것 📚

5편: 클래스와 객체 완벽 가이드 | OOP의 Kotlin 스타일

  • 클래스 선언과 생성자
  • 프로퍼티 (getter/setter 자동 생성)
  • data class 완벽 활용
  • companion object - static의 대안
  • object 키워드로 싱글톤 만들기

실습 과제 💪

// 1. when으로 계산기 만들기
// - 연산자(+, -, *, /)와 두 숫자를 받아 계산

// 2. for로 피보나치 수열 출력
// - 1부터 n번째까지

// 3. 입력값 검증 함수 만들기
// - 이메일 형식 체크 (when 사용)
// - 비밀번호 강도 체크 (if 표현식 사용)

자주 묻는 질문 (FAQ)

Q: if와 when 중 뭘 써야 하나요?
A: 2-3개 조건이면 if, 그 이상이거나 패턴 매칭이면 when이 좋습니다.

Q: for문에서 인덱스가 꼭 필요한가요?
A: 대부분은 forEach, map 같은 함수형 방식이 더 간결합니다. 다음 편에서 배웁니다!

Q: break/continue 라벨은 언제 쓰나요?
A: 중첩 루프에서만 씁니다. 가능하면 함수로 분리하는 게 더 깔끔합니다.

Q: range는 성능이 괜찮나요?
A: 네! 컴파일러가 최적화하므로 전통적인 for문과 거의 동일합니다.


관련 글


💬 댓글로 알려주세요!

  • when을 사용해본 경험이 있나요?
  • 어떤 제어 구조가 가장 유용했나요?
  • 이 글이 도움이 되셨나요?
반응형
Comments