Android Developers codelab - Kotlin - 2

한로·2025년 2월 18일

Android-Developers

목록 보기
4/4

조건문

if/else 문을 사용하여 조건 표현

환경이 바뀌면 사람들의 행동도 바뀝니다. 예를들어 날씨가 추우면 겉옷을 입고 날씨가 따듯하면 겉옷이 필요하지 않습니다.

불리언 표현식으로 if 조거 작성

운전자가 신호등에서 취해야 할 올바흔 행동을 알려주는 프로그램을 빌드한다고 가정하겠습니다.


  • if 문의 구조

_if 문을 사용하려면 평가하려는 조건 앞에 if 키워드를 사용합니다.

  • 불리언 표현식으로 조건을 표현해야 합니다.
  • 표현식은 값과 변수, 값을 반환하는 연산자로 조합됩니다.
  • 불리언 표현식은 불리언 값을 반환합니다.

아래 코드는 할당연산자입니다.

반대로 불리언 표현식은 방정식의 양쪽에 있는 값이나 변수를 비교하는 비교 연산자로 구성됩니다.

== 비교 연산자는 값을 서로 비교합니다.

간단한 if문 작성

fun main() {
    val trafficLightColor = "Red"

    if (trafficLightColor == "Red") {
        println("Stop")
    }
}

trafficLightColor == "Red" 표현식은 true 값을 반환 하므로 stop 가 출력됩니다

else 추가

if/else문을 만들려면 else를 추가합니다.

fun main() {
    val trafficLightColor = "Red"

    if (trafficLightColor == "Red") {
        println("Stop")
    } else {
        println("Go")
    }
}
  • 구조

else if 추가

if 브랜치의 닫는 중괄호 뒤에 else if 키워드를 추가해야 합니다. else if 키워드의 괄호 안에 else if 브랜치 조건으로 불리언 표현식을 추가하고 중괄호 안에 본문을 추가해야 합니다. 본문은 조건 1이 실패했지만 조건 2가 충족되는 경우에만 실행됩니다.

fun main() {
    val trafficLightColor = "Yellow"

    if (trafficLightColor == "Red") {
        println("Stop")
    } else if (trafficLightColor == "Yellow") {
        println("Slow")
    } else {
        println("Go")
    }
}

when

trafficLightColor 프로그램은 조건이 여러 개이면 더 복잡하게 보입니다.

Kotlin에서는 여러 브랜치를 다룰 때 if/else 대신 when문을 사용할 수 있습니다.
고려할 브랜치가 3개 이상인 경우 가독성을 위해 when문을 사용하는 것이 좋습니다.

  • when 문은 매개변수를 통해 단일 값을 허용합니다.
  • 값이 각 조건을 순차적으로 평가됩니다.
  • 충족되는 첫 번째 조건의 상응하는 본문이 실행됩니다.
  • 각 조건의 본문은 (->) 로 구분됩니다.

if/else 를 when 문으로

fun main() {
    val trafficLightColor = "Yellow"

    when (trafficLightColor) {
        "Red" -> println("Stop")
        "Yellow" -> println("Slow")
        "Green" -> println("Go")
        else -> println("Invalid traffic-light color")
    }
}

여러 조건에서 쉼표(,) 사용

when 문을 작성할 때는 쉼표(,)를 사용하여 동일한 본문에 상응하는 여러 조건을 나타낼 수 있습니다.

fun main() {
    val x = 3

    when (x) {
        2, 3, 5, 7 -> println("x is a prime number between 1 and 10.")
        else -> println("x isn't a prime number between 1 and 10.")
    }
}

여러 조건에서 in 키워드 사용

여러 조건을 나타내는 쉼표(,)기호 외에도 in키워드와 when브랜치의 다양한 값도 사용할 수 있습니다.

다양한 값을 사용하려면 범위 시작을 나타내는 숫자, 공백 없이 점 두 개를 차례로 추가하고 범위 끝을 나타내는 또 다른 숫자로 종료합니다.

fun main() {
    val x = 3

    when (x) {
        2, 3, 5, 7 -> println("x is a prime number between 1 and 10.")
        in 1..10 -> println("x is a number between 1 and 10, but not a prime number.")
        else -> println("x isn't a prime number between 1 and 10.")
    }
}

is 키워드를 사용하여 데이터 유형 확인

  • is 키워드를 조건으로 사용하여 평가된 값의 데이터 유형을 확인할 수 있습니다.
fun main() {
    val x: Any = 20

    when (x) {
        2, 3, 5, 7 -> println("x is a prime number between 1 and 10.")
        in 1..10 -> println("x is a number between 1 and 10, but not a prime number.")
        is Int -> println("x is an integer number, but not between 1 and 10.")
        else -> println("x isn't an integer number.")
    }
}


if/else 및 when을 표현식으로 사용

  • 조건문을 표현식으로 사용하여 조건을 각 브랜치에 다른 값을 반환할 수도 있습니다.
    각 브랜치의 본문에 비슷하게 표시되면 조건식을 사용하여 조건문에 비해 코드 가독성을 개선할 수 있습니다.

  • 표현식으로의 조건문 문법은 문과 비슷하지만 각 브랜치의 본문 마지막 줄은 값 또는 표현식을 반환해야 하고 조건문은 변수에 할당 됩니다.

본문에 반환 값 또는 표현식만 포함되어 있는 경우 중괄호를 삭제하여 코드를 간결하게 작성할 수 있습니다

if 문을 표현식으로 변환

  • println()이 많이 반복되는 코드
fun main() {
    val trafficLightColor = "Black"

    if (trafficLightColor == "Red") {
        println("Stop")
    } else if (trafficLightColor == "Yellow") {
        println("Slow")
    } else if (trafficLightColor == "Green") {
        println("Go")
    } else {
        println("Invalid traffic-light color")
    }

}
  • when/표현식을 사용한 코드
fun main() {
    val trafficLightColor = "Black"

    val message =
      if (trafficLightColor == "Red") "Stop"
      else if (trafficLightColor == "Yellow") "Slow"
      else if (trafficLightColor == "Green") "Go"
      else "Invalid traffic-light color"

    println(message)
}

null

  • null 허용 여부는 많은 프로그래밍 언어에서 일반적으로 사용되는 개념으로, 변수에 값이 업어도 된다는 것을 의미합니다.
    kotlin에서 null 안전을 보장하기 위해 null 허용 여부를 의도적으로 처리합니다.

null을 허용하는 변수 사용

null의 정의

예를들어 favoriteActor 변수를 선언할 때 즉 시 "Sandra Oh" 문자열을 값을 할당할 수 있습니다

val favoriteActor = "Sandra Oh"

하지만 좋아하는 배우가 없다면 "Nobody"또는 "None" 값을 할당할 수도 있습니다.
이런 접근 방식은 프로그램에서 favoriteActor 변수에 아에 값이 없다고 해석하지 않고 값 자체를 "Nobody" 또는 "None" 으로 해석할 수 있기 때문입니다.
Kotlin에서는 null을 사용하여 변수와 연결된 값이 없음을 나타낼 수 있습니다

null을 허용하지 않는 변수와 null을 허용하는 변수 이해하기

favoriteActor 에 null을 할당하려 하면 에러가 표시됩니다.

Kotlin에서 null을 허용하는 유형과 null을 허용하지 않는 유형 간에는 차이가 있습니다.

kotlin에서 null을 허용하는 변수를 선언하려면 유형 끝에 ? 연산자를 추가해야합니다.
예를 들어 String? 유형은 문자열이나 null을 보유할 수 있는 반면 String 유형은 문자열만 보유할 수 있습니다.

fun main() {
    var favoriteActor: String? = "Sandra Oh"
    println(favoriteActor)

    favoriteActor = null
    println(favoriteActor)
}

null 허용하는 변수 속성에 액세스

fun main() {
    var favoriteActor: String? = "Sandra Oh"
    println(favoriteActor.length)
}
  • 해당 코드를 실행하면 오류를 확인할 수 있습니다.

컴파일 오류입니다.
Kotlin은 null 안정성을 얻을 수 있게 의도적으로 문법 규칙을 적용합니다.
이는 잠재적으로 null 변수에서 실수로 호출이 발생하지 않도록 보장한다는 의미입니다.

Kotlin의 null 안전성 특성 덕분에 Kotlin 컴파일러가 null을 허용하는 유형에 관해 null검사를 강제하므로 이러한 런타임 오류가 방지됩니다.

null 검사는 변수에 액세스하여 null을 허용하지 않는 유형으로 처리하기 전에 변수가 null인지 확인하는 프로세스 입니다.

null을 허용하는 값을 null을 허용하지 않는 유형으로 사용하려면 null 검사를 명시적으로 실행해야합니다.

?. 안전 호출 연산자 사용

  • ?. 안전 호출 연산자를 사용하여 null을 허용하는 변수의 메서드나 속성에 액세스 할 수 있습니다.

?. 안전 호출 연산자를 사용하여 메서드나 속성에 액세스하려면 변수 이름 뒤에 ? 기로흫 추가하고 . 표기법으로 메스드나 속성에 액세스 합니다.

fun main() {
    var favoriteActor: String? = "Sandra Oh"
    println(favoriteActor?.length)
}

참고: null을 허용하지 않는 변수에서 ?. 안전 호출 연산자를 사용하여 메서드나 속성에 액세스할 수도 있습니다. 이 경우 Kotlin 컴파일러에서 오류가 발생하지는 않지만 필요하지 않습니다. null을 허용하지 않는 변수의 메서드나 속성에 관한 액세스는 항상 안전하기 때문입니다.

null이 아닌 어션셜 연산자 !! 사용

또한 null이 아닌 !! 어설션 연산자를 사용하여 null을 허용하는 변수의 메서드나 속성에 액세스할 수 있습니다.

null을 허용하는 변수 뒤에 null 이 아닌 !! 어설션 연산자를 추가하여 그 뒤에 . 연산자, 메서드나 속성을 차례로 공백없이 추가합니다.

null 이 아닌 !! 어설션은 변수의 값이 null이 아님(실제 여부에 관계없이)을 나타냅니다.

?. 안전 호출 연산자와 달리 null이 아닌 !! 연산자를 사용하면 null을 허용하는 변수가 실제로 null 일 때 NullPointerException 오류가 발생할 수 있습니다. 따라서, 변수가 항상 null 비허용 변수이거나 적절한 예외처리가 설정된 경우에만 실행해야 합니다.

fun main() {
    var favoriteActor: String? = "Sandra Oh"
    println(favoriteActor!!.length)
}
  • 에러
fun main() {
    var favoriteActor: String? = null
    println(favoriteActor!!.length)
}

참고: null 안전 속성이 포함되지 않은 다른 프로그래밍 언어에서는 앱 비정상 종료의 원인이 NullPointerException 오류인 경우가 많습니다. 따라서 Kotlin은 언어에 null 안전이 포함되므로 프로그램 비정상 종료의 커다란 원인을 제거합니다.

?: Elvis 연산자 사용

?: Elvis 연산자는 ?. 안전 호출 연산자와 함께 사용할 수 있는 연산자입니다.

?: 연산자를 사용하려면 ?. 안전 호출 연산자가 null을 반환할 떄 기본값을 추가할 수 있습니다.

변수가 null이 아닌 경우에은 ?: Elvis 연산자 앞의 표현식이 실행됩니다.
변수가 null이면 ?: Elvis 연산자 뒤의 표현식이 실행됩니다.

fun main() {
    val favoriteActor: String? = "Sandra Oh"

    val lengthOfName = favoriteActor?.length ?: 0

    println("The number of characters in your favorite actor's name is $lengthOfName.")
}

참고: ?: Elvis 연산자는 록스타 엘비스 프레슬리의 이름을 따서 지었습니다. 옆에서 봤을 때 엘비스의 앞머리를 나타내는 이모티콘과 비슷하기 때문입니다.
https://en.wikipedia.org/wiki/Quiff

함수 유형 및 람다표현식

  • 변수에 함수를 저장하고 저장된 함수를 다른 함수에 전달하고 그것을 함수에서 반환할 수 있습니다.

  • 에러 확인

코드를 실행하면 Kotlin 컴파일에서 trick를 trick()함수의 이름으로 인식하지만 변수에 함수가 할당되는 대신 함수가 호출될 것으로 예상하기 때문에 오류가 발생합니다.

trickFunction 변수에 trick 을 저장하려고 했습니다.
그러나 함수를 값으로 참조하려면 함수 참조 연산자 (::) 를 사용해야합니다.

fun main() {
    val trickFunction = ::trick
}

fun trick() {
    println("No treats!")
}
  • 함수를 값으로 참조하려면 trickFunction을 ::trick에 재할당합니다.

람다 표현식을 사용하여 함수 재정의

람다 표현식은 fun키워드 없이 함수를 정의할 수 있는 간결한 문법입니다.

람다 표현식은 다른 함수에 관한 함수참조 없이 변수에 직접 저장할 수 있습니다.

할당연산자(=)앞에 val 또는 var 키워드를 추가하고 그 뒤에 함수를 호출할 때 사용하는 변수 이름을 추가합니다.
할당 연산자(=) 다음에 람다 표현식이 옵니다.
이때 람다 표현식은 함수 본문을 구성하는 한 쌍의 중괄호로 구성됩니다.

람다 표현식을 사용하여 함수를 정의할 경우 그 함수를 참조하는 변수를 갖게 됩니다.
다른 유형처럼 그 값을 다른 변수에 할당하고 새 변수의 이름으로 함수를 호출할 수도 있습니다.

fun main() {
    val trickFunction = trick
    trick()
    trickFunction()
}

val trick = {
    println("No treats!")
}

함수를 데이터 유형으로 사용

Kotlin에 유형추론이 있습니다.
변수를 선언할 때 유형을 명시적으로 지정하지 않다도 되는 경우가 많습니다.

위의 예에서는 Kotlin 컴파일러가 trick 의 값이 함수임을 추론할 수 있었습니다.
그러나 함수가 매개변수의 유형이나 반환 유형을 지정하려면 함수 유형을 표현하기 위한 문법이 필요합니다.

함수 유형은 선택적 매개변수 목록, -> 기호, 반환 유형이 포함된 괄호 쌍으로 구성됩니다.

위 코드에서 trick 변수의 데이터 유형은 () -> Unit 입니다.
함수에 매개변수가 없으므로 괄호가 비어있습니다.
그리고 함수에서 아무것도 반환하지 않으므로 반환 유형은 Unit 입니다.
두 개의 Int 매개변수를 사용하고 Int를 반환하는 함수라면 데이터 유형은 (Int, Int) -> Int 입니다.

fun main() {
    val trickFunction = trick
    trick()
    trickFunction()
    treat()
}
val treat: () -> Unit = {
    println("Have a treat!")
}
val trick = {
    println("No treats!")
}

함수를 반환 유형으로 사용

  • 함수가 데이터 유형이므로 다른 데이터 유형처럼 함수를 사용할 수 있습니다.
    다른 함수에서 함수도 반환할 수 있습니다.
fun main() {
    val treatFunction = trickOrTreat(false)
    val trickFunction = trickOrTreat(true)
    
    treatFunction()
    trickFunction()
}


fun trickOrTreat(isTrick:Boolean): () -> Unit = {
    if(isTrick) {
     trick()   
    }else {
        treat()
    }
}

val trick = {
    println("No treats!")
}

val treat = {
    println("Have a treat!")
}

함수를 다른 함수에 인수로 전달

매개변수를취하는 함수에 관한 람다 표현식을 작성할 때 매개변수에 매개변수의 발생 순서대로 이름이 지정됩니다.
매개변수 이름은 여는 중괄호 다음에 나열되고 각 이름은 쉼표로 구분됩니다.
화살표(->)는 함수 본문에서 매개변수 이름을 구분합니다.

fun main() {
    val coins: (Int) -> String = { quantity ->
        "$quantity quarters"
    }

    val cupcake: (Int) -> String = {
        "Have a cupcake!"
    }

    val treatFunction = trickOrTreat(false, coins)
    val trickFunction = trickOrTreat(true, cupcake)
    treatFunction()
    trickFunction()
}

null을 허용하는 함수 유형

다른 데이터 유형과 마찬가지로 함수 유형도 null을 허용하는 것으로 선언할 수 있습니다.
이러한 경우 변수가 함수를 포함하거나 null일 수 있습니다.

함수를 null을 허용하는 것으로 선언하려면 함수 유형을 괄호로 묶은 다음 닫는 괄호 밖에 ? 기호를 추가합니다.

예를들어 () -> String 유형을 null을 허용하게 하려면 이를 (()) -> String)? 유형으로 선언하면 됩니다.

fun main() {
    val coins: (Int) -> String = { quantity ->
        "$quantity quarters"
    }

    val treatFunction = trickOrTreat(false, coins)
    val trickFunction = trickOrTreat(true, null)
    treatFunction()
    trickFunction()
}

fun trickOrTreat(isTrick:Boolean, extraTreat:((Int)->String)?): () -> Unit {
    if(isTrick) {
     return trick   
    }else {
        if(extraTreat != null) {
            println(extraTreat(5))
        }
        return treat
    }
}

val trick = {
    println("No treats!")
}

val treat = {
    println("Have a treat!")
}

약식 문법으로 람다 표현식 작성

  • 매개변수 이름 생략
    coins() 함수 이름을 작성할 때 함수의 Int 매개변수에 이름 quantity를 명시적으로 선언했습니다.
    그러나 cupcake()함수에서처럼 매개변수 이름을 완전히 생략할 수 있습니다.

함수에 매개변수가 한 개 있고 이름을 지정하지 않는 경우 Kotlin은 암시적으로 매개변수에 it 이름을 할당합니다.
그러나 매개변수 이름과 -> 기호를 생략할 수 있고 그러면 람다 표현식이 더 간결해집니다.

 val coins: (Int) -> String = { 
        "$it quarters"
    }

람다 표현식을 함수에 직접 전달

coins() 함수는 현재 한 곳에만 사용됩니다.
처음에 변수를 만들지 않고도 람다 표현식을 trickOrTreat() 함수에 직접 전달할 수도 있습니다.

람다 표현식은 함수 리터럴일 뿐입니다.
예를 들어 0은 정수 리터럴이고 "Hello"는 문자열 리터럴입니다.
람다 표현식을 함수 호출에 직접 전달할 수 있습니다.

  • coins는 사용하지 않으니 삭제합니다
fun main() {
  
    val treatFunction = trickOrTreat(false, { "$it quarters"})
    val trickFunction = trickOrTreat(true, null)
    treatFunction()
    trickFunction()
}

후행 람다 문법 사용

함수 유형이 마지막 매개변수인 경우 다른 축약 옵션을 사용하여 람다를 작성할 수 있습니다.
이 경우 닫는 괄호 다음에 람다 표현식을 배치하여 함수를 호출할 수 있습니다.

이렇게 하면 람다 표현식이 다른 매개변수와 구분되므로 코드를 읽기 쉬우며 코드 기능은 변경되지 않습니다.

val treatFunction = trickOrTreat(false) { "$it quarters" }

repeat()

함수가 함수를 반환하거나 또는 함수를 인수로 취하는 경우 이를 고차함수라고 합니다.
trickOrTreat() 함수가 ((Int) -> String)? 유형의 함수를 매개변수로 취하고 () -> Unit 유형의 함수를 반환하므로 고차함수의 예입니다.

repeat() 함수는 이러한 고차 함수 중 하나입니다.
repeat() 함수는 함수로 for 루프를 표현할 수 있는 간결한 방법입니다.

repeat(times: Int, action: (Int) -> Unit)

times 매개변수는 동작이 발생해야 하는 횟수입니다.
action 매개변수는 단일 Int 매개변수를 사용하고 Unit 유형을 반환하는 함수입니다.
action 함수의 Int 매개변수는 동작이 지금까지 실행된 횟수입니다.
(예: 첫번째 반복에서는 0 인수, 두 번째 반복에서는 1인수)
repeat()함수를 사용하면 for 루프와 유사하게 지정된 횟수만큼 코드를 반복할 수 있습니다.

trickFunction() 함수를 한 번만 호출하는 대신 repeat() 함수를 하용하여 여러 번 호출할 수 있습니다.

val treatFunction = trickOrTreat(false) { "$it quarters" }
    val trickFunction = trickOrTreat(true, null)
    
    repeat(4) {
        treatFunction()
    }
    trickFunction()
    
}
profile
"Hello World"

0개의 댓글