본문 바로가기
  • 개발하는 곰돌이
Programming Language/Kotlin & Java

Kotlin 기본 문법 4 : 조건문과 반복문

by 개발하는 곰돌이 2022. 11. 23.

목차

    개요

    Kotlin에서도 Java와 비슷하게 조건문과 반복문을 사용할 수 있다. 다만 세부적인 사용법에서 차이가 있고, 조건문의 경우에는 Java에서는 불가능하지만 Kotlin에서는 가능한 사용법이 있으므로 이에 대해 정리하고자 한다.


    조건문

    조건문은 주어진 조건식의 결과에 따라 이후에 따라오는 코드 블럭의 실행 여부를 결정하는 구문을 의미한다. Kotlin의 조건문에는 아래의 두 가지가 있다.


    if ... else

    if ... else는 여러 프로그래밍 언어에서 볼 수 있는 전통적인 조건문이다. 주어진 조건 식의 결과에 따라 if 또는 else 이후의 코드 블럭이 실행된다.

    여러 조건을 걸어서 조건문을 사용하고 싶다면 else if를 사용하면 된다. 이 경우에는 이전 조건식을 먼저 검사하고 그 결과가 거짓일 경우 else if의 조건을 검사한다. Java와 사용법이 완전히 동일하다.

    if (조건식1) {
        // 조건식1이 참일 경우
    } else if (조건식2) {
        // 조건식1은 거짓이지만 조건식2가 참일 경우
    } else if (조건식3) {
        // 조건식1,2는 거짓이지만 조건식3이 참일 경우
    } else {
        // 조건식1,2,3이 모두 거짓일 경우
    }

    when

    when은 기존의 switch-case를 대체하는 Kotlin의 조건문이다. when은 2가지 사용법이 있다. 첫 번째는 어떠한 값이 주어졌을 때 그 값에 따라 문장을 실행하는 경우이다. 이 경우는 전통적인 switch-case와 비슷하게 동작하지만 약간의 차이가 있다. 아래의 예시를 보자.

    when (n) {
        in 1..9 -> println("n은 한자리 수입니다.")
        in 10..100 step 10 -> println("n은 100 이하인 10의 배수입니다.")
        200, 300 -> println("n은 20 또는 30입니다.")
        10000 -> {
            n /= 50
            println("n을 50으로 나눈 값은 ${n}입니다.
        }
        else -> println("n은 어디에도 속하지 않습니다.")
    }

    when에서는 전통적인 프로그래밍 언어들의 switch-case와는 달리 case 없이 비교할 값만 입력하고 ->를 이용하여 실행할 문장을 작성한다. 만약 실행할 문장이 두 줄 이상인 경우에는 중괄호를 이용하여 감싸줄 수 있다.

     

    whenswitch-case와 갖는 큰 차이점 중 하나는 break를 사용하지 않아도 된다는 점이다. 기존 언어들의 switch-case에서는 break를 사용하지 않으면 이후 조건의 문장들도 모두 실행되는 문제가 있었으나, Kotlin의 when에서는 break를 사용하지 않아도 조건에 맞는 경우의 문장만 실행하므로 코드가 짧아진다는 장점이 있다.

     

    두번째 차이점은 값의 조건에 범위를 지정할 수 있다는 점이다. 값의 조건에 범위를 지정하는 경우에는 range를 사용할 수 있다. in은 주어진 값이 해당 범위에 속하는지 확인하는 예약어이고, 1..9의 경우에는 1 이상 9 이하를 의미한다. n in 1..9를 기존의 방식대로 표현하면 n >= 1 && n <= 9가 된다.

     

    그 외에도 elseswitch-casedefault를 대체한다는 점이나 간단하게 콤마(,)만으로 줄 수 있다는 점도 다르다. 콤마로 구분한 조건은 두 조건 중 하나만 만족하면 실행되는 or 조건이 된다.

     

    when을 사용하는 두번째 방법은 주어지는 값 없이 조건만 검사하는 경우이다. 이 경우에는 if ... else문을 좀 더 간결하게 사용할 수 있다.

    when {
        a <= 10 -> println("a는 10 이하입니다.")
        b > 200 -> println("b는 200보다 큽니다.")
        a >= 100 && b >= 100 -> println("a, b 모두 100 이상입니다.")
        else -> println("일치하는 조건이 없습니다.")
    }

    위 코드는 a와 b의 값을 검사해서 문장을 출력하는 코드이다. 이와 같이 주어지는 값 없이 when을 사용하는 경우에는 기준이 되는 값이 없기 때문에 반드시 조건식을 입력해야 하며, 이로 인해 if ... else대신 사용하여 코드를 좀 더 간결하게 작성할 수 있다.


    표현식으로 사용할 수 있는 조건식

    Kotlin에서는 조건문을 표현식으로도 사용할 수 있다. 변수에 값을 저장하거나 함수의 파라미터로 값을 전달할 때 조건문의 결과에 변수에 저장할 값이나 함수의 파라미터로 전달할 값을 지정할 수 있다. 이러한 특징 때문에 Kotlin에서는 삼항 연산자를 지원하지 않는다. when 또한 같은 방법으로 사용할 수 있다.

    • if
    if (b == 0) {
        println("0으로 나눌 수 없습니다.")
    } else {
        println(a / b)
    }
    println(if (b == 0) "0으로 나눌 수 없습니다." else a / b)
    • when
    when {
        a <= 10 -> println("a는 10 이하입니다.")
        b > 200 -> println("b는 200보다 큽니다.")
        a >= 100 && b >= 100 -> println("a, b 모두 100 이상입니다.")
        else -> println("일치하는 조건이 없습니다.")
    }
    println(
        when {
            a <= 10 -> "a는 10 이하입니다."
            b > 200 -> "b는 200보다 큽니다."
            a >= 100 && b >= 100 -> "a, b 모두 100 이상입니다."
            else -> "일치하는 조건이 없습니다."
        }
    )

    각 쌍의 코드는 같은 결과를 출력한다.


    반복문

    반복문은 주어진 조건식을 만족할 경우 이후에 따라오는 코드 블럭을 반복하여 실행하는 구문이다. Kotlin의 반복문은 전통적인 for, while, do-while외에도 repeat이 추가되었다.


    for

    Kotlin의 for는 작동 방식이 다른 언어들과 동일하지만 작성 방법이 다르다. C/C++과 Java 등의 언어에서는 for문을 작성할 때 반복문에서 사용할 변수의 이름 및 초기값, 변수의 조건, 변수의 증가 또는 감소량을 모두 작성해야 했지만, Kotlin에서는 변수의 이름과 in, range만 작성하는 것으로 손쉽게 for문을 작성할 수 있다.

    // Java
    int sum = 0;
    
    for (int i = 1; i <= 10; i++) {
        sum += i;
    }
    
    System.out.println(sum);
    
    for (int i = 5; i >= 1; i--) {
        System.out.println(i);
    }
    
    /*
    55
    5
    4
    3
    2
    1
    */
    // Kotlin
    var sum = 0
    for (i in 1..10) {
        sum += i
    }
    
    println(sum)
    
    for (i in 5 downTo 1) {
        println(i)
    }
    
    /*
    55
    5
    4
    3
    2
    1
    */

    이렇게 Kotlin에서는 Java에 비해 훨씬 간단하게 for문을 작성할 수 있다.

    range

    Kotlin 공식 가이드 상 정의에 따르면 range는 두 끝점이 모두 범위 내에 포함되는 것으로 정의된다. 즉, 시작점부터 끝점까지의 범위라고 정의할 수 있다. range는 rangeTo() 함수 또는 .., until, downTo 등의 연산자로 정의할 수 있고 step 연산자로 간격을 지정할 수 있으며, 주로 in이나 !in과 함께 사용된다. 
    ..은 끝값을 포함하지만(<=) until은 끝값을 포함하지 않는다(<)는 차이가 있으며, downTo는 시작값에서 끝값까지 감소하는 범위를 정의한다.
    in은 해당 range에 포함된다는 것을, !in은 해당 range에 포함되지 않는다는 것을 뜻한다.
    배열, 리스트, 문자열의 경우에는 식별자.indices를 사용하여 range를 정의할 수 있는데 이는 0 until 식별자의 크기를 의미한다.

    1부터 10까지의 홀수만 출력하는 경우를 각각 Java와 Kotlin으로 작성했을 때는 아래와 같이 작성할 수 있다.

    // Java
    for (int i = 1; i <= 10; i += 2) {
        System.out.println(i);
    }
    
    /*
    1
    3
    5
    7
    9
    */
    // Kotlin
    for (i in 1..10 step 2) {
        println(i)
    }
    
    /*
    1
    3
    5
    7
    9
    */

    IntelliJ에서는 기본적으로 Kotlin의 for문을 사용할 때 아래와 같이 부등호로 범위를 표시해 주므로 좀 더 수월하게 사용할 수 있다.

    IntelliJ에서는 Kotlin for문의 범위를 표시해준다.


    Kotlin에서도 Java와 마찬가지로 향상된 for문을 사용할 수 있다. 이 경우에는 식별자 명과 배열, 리스트, 문자열의 이름 사이에 in만 넣어주면 간단하게 작성할 수 있다.

    val arr = arrayOf("Apple", "Pear", "Grape", "Orange")
    
    for (fruit in arr) {
        println(fruit)
    }
    
    /*
    Apple
    Pear
    Grape
    Orange
    */

    위 코드는 아래의 Java 코드와 동일하다.

    String[] arr = new String[]{"Apple", "Pear", "Grape", "Orange"};
    
    for (String fruit : arr) {
        System.out.println(fruit);
    }
    
    /*
    Apple
    Pear
    Grape
    Orange
    */

    이 향상된 for문은 컬렉션 객체와 문자열의 forEach 메소드로도 작성할 수 있다.

    val arr = arrayOf("Apple", "Pear", "Grape", "Orange")
    
    arr.forEach {
        println(it)
    }
    
    /*
    Apple
    Pear
    Grape
    Orange
    */

    Kotlin의 향상된 for문을 사용할 때 배열, 리스트, 문자열에 withIndex()를 사용하여 인덱스와 그 인덱스에 해당하는 값을 가져올 수도 있다.

    val str = "Hello"
    
    for ((i, c) in str.withIndex()) {
        println("${i}번 문자 : $c")
    }
    
    /*
    0번 문자 : H
    1번 문자 : e
    2번 문자 : l
    3번 문자 : l
    4번 문자 : o
    */

    while, do-while

    while문은 주어진 조건에 만족하는 동안 코드 블럭을 반복적으로 실행하는 반복문이다. 전통적인 프로그래밍 언어와 같은 방법으로 사용하면 된다. whiledo-while의 차이 역시 동일하게 최초 1회 실행여부의 차이만 있을 뿐이다.

    // 처음에 x가 음수면 실행하지 않음
    while (x >= 0) {
        x--
    }
    // 처음에 x가 음수여도 1번은 실행
    do {
        x--
    } while (x >= 0)

    repeat

    repeat은 사실 Kotlin의 문법이 아니라 내부적으로 정의되어 있는 함수 중 하나이다. 파라미터로 반복할 횟수를 전달하면 코드 블럭의 내용을 파라미터로 전달된 횟수만큼 반복하게 된다. 내부적으로는 for문을 호출하는 것으로 구현되어 있다.

    Standard.kt에 정의되어 있는 repeat() 함수.

    // it 키워드를 사용하면 현재 반복중인 횟수를 얻을 수 있음
    repeat(3) {
        println("${it}번 반복중...")
    }
    
    /*
    0번 반복중...
    1번 반복중...
    2번 반복중...
    */

    반복문의 흐름제어

    Kotlin 역시 전통적인 프로그래밍 언어와 마찬가지로 breakcontinue를 사용하여 반복문의 흐름을 제어할 수 있다. 이 두 키워드의 역할은 다른 언어들과 똑같이 break는 반복문 즉시 종료, continue는 이후 구문을 무시하고 다음 반복단계로 이동하는 역할을 한다. 기본적으로 흐름제어문은 키워드가 작성된 블럭의 반복문에만 영향을 끼치지만, Kotlin에서는 반복문에 @을 이용하여 label을 붙이고 이를 흐름제어문에 붙이는 것으로 해당 이름을 가진 반복문의 흐름을 제어할 수 있다.

    loop@ for (i in 0 until 10) {
        ...
        for (j in 0 until 10) {
            ...
            break@loop
        }
    }

    이러한 유형의 이중 반복문이 있을 경우 내부에 있는 반복문의 break가 호출되면 loop라는 label이 달린 외부의 반복문이 종료된다.


    repeat()의 경우에는 내부적으로 반복문을 호출하긴 하지만 그 자체가 반복문이 아니기 때문에 breakcontinue를 사용한 흐름 제어가 불가능하다. 대신 return을 사용하여 흐름을 제어할 수 있는데 그 방법은 아래와 같다.

    fun main() {
        run {
            repeat(10) {
                if (it == 5) return@repeat	// continue
                if (it == 8) return@run	// break
                println(it)
            }
        }
    }
    
    /*
    0
    1
    2
    3
    4
    6
    7
    */

    return@repeatcontinue와 동일하게 바로 다음 반복단계로 넘어가고, return@runbreak와 동일하게 반복을 완전히 종료시킨다. 이 때 return@run을 사용하기 위해선 반드시 repeat() 구문을 run으로 감싸주어야 한다.


    마무리

    이번 포스트에서는 Kotlin의 조건문과 반복문에 대해 정리해보았다. Kotlin의 조건문은 표현식으로도 사용할 수 있다는 특징이 있어 반복되는 구문의 작성을 방지할 수 있다. 반복문은 Java에 비해 훨씬 간단하게 작성할 수 있으며 label을 이용하여 수월하게 흐름제어를 할 수 있다.

     

    다음 포스트에서는 Kotlin의 배열에 대해 정리해보고자 한다.

     

    댓글 피드백은 언제나 환영합니다.

     

     

    댓글