[Kotlin] 4. 프로그램의 흐름

문상훈·2022년 7월 21일
0

Kotlin

목록 보기
5/7

🛴 04. 프로그램의 흐름

  • 코틀린에는 제어문을 간략하게 사용할 수 있는 표현들이 많으므로, 기존 프로그래밍 습관을 버리고 간략화된 표현을 쓰도록 하기 !!
    📍 더 생산성이 높게 코딩할 수 있다 !!

📌 04-1 조건문

if문과 if~else문

📝 if문

val max = a
if (a < b)
	max = b
  • 수행할 문장이 한 줄 이라면 중괄호 생략가능

📝 if~else문

val max: Int
if (a > b)
	max = a
else
	max = b
val mac = if (a > b) a else b
fun main() {
    val a = 20
    val b = 7

    val max = if (a > b) {
        println("a 선택")
        a
    } else {
        println("b 선택")
        b
    }
    println(max)
}

else if문으로 조건문 중첩하기

fun main() {
    println("Enter the score : ")
    val score = readLine()!!.toDouble()
    var grade: Char = 'F'

    if (score >= 90.0) {
        grade = 'A'
    } else if (score >= 80.0 && score <= 89.9) {
        grade = 'B'
    } else if (score >= 70.0 && score <= 79.9) {
        grade = 'C'
    }
    println("Score : $score, grade : $grade")
}

출력 :

Enter the score : 
89.9
Score : 89.9, grade : B
  • readLine() : 콘솔로부터 문자열을 입력받는 함수
    • 입력받은 숫자의 자료형은 사실 문자열이라 .toDouble()을 이용해 Double형으로 변환
  • !!. : non-nul 단정 기호 - 변수에 할당된 값이 null이 아님을 단정하고 컴파일러가 null 검사를 하지 않는다.
    📍 입력된 기호가 null일 경우에는 NPE을 발생시킴 !

in 연산자와 범위 연산자로 조건식 간략하게 만들기

범위 연산자 : 왼쪽의 값부터 오른쪽의 값까지 포함하는 범위를 계산한다.

변수이름 in 시작값..마지막값

if (score >= 90.0) {
        grade = 'A'
    } else if (score in 80.0..89.9) {
        grade = 'B'
    } else if (score in 70.0..79.9) {
        grade = 'C'
    }
  • 코드가 더 간략하게 바뀌었고 읽기도 더 좋아졌다.

when문으로 다양한 조건 처리하기

  • 코틀린에서 조건이 많은 경우를 대비한 when문을 제공한다.
    -> 조건이 많은 코드를 간략하게 줄일 수 있다.
  • when문은 자바 등 다른 언어에서 쓰는 switch~case문과 비슷하지만 각 수행 문장을 멈추는 break가 필요하지 않다.

인자를 사용하는 when문

when (인자) {
인자에 일치하는 값 or 표현식 -> 수행할 문장
인자에 일치하는 범위 -> 수행할 문장
...
else -> 수행할 문장
}

  • 인자에 해당하는 조건이 여러개라면 ,를 이용하면 된다.
    📝 when문에 반환값 사용하기
when(x) {
    parseInt(s) -> print("일치")
    else -> print("불일치")
}

📝 when과 is키워드 함께 사용하기

  • is키워드를 사용하면 특정 자료형을 검사할 수 있다.
  • 검사 후 실행문의 결과를 result에 할당한다.
val str = "지묵"
val result = when (str) {
	is String -> "문자열입니다."
	 else -> false

📝 when문과 in 연산자를 조합해서 앞의 식을 작성

fun main() {
    println("Enter the score : ")
    val score = readLine()!!.toDouble()
    var grade: Char = 'F'

    when (score) {
        in 90.0..100.0 -> grade = 'A'
        in 80.0..89.9 -> grade = 'B'
        in 70.0..79.9 -> grade = 'C'
        !in 70.0..100.0 -> grade = 'F'
    }
    println("Score : $score, grade : $grade")
}

출력 :

Enter the score : 
85.7
Score : 85.7, grade : B

인자가 없는 when문

when{
조건 or 표현식 -> 실행할 문장
...
}

fun main() {
    println("Enter the score : ")
    val score = readLine()!!.toDouble()
    var grade: Char = 'F'

    when {
        score >= 90.0 -> grade = 'A'
        score in 80.0..89.9 -> grade = 'B'
        score in 70.0..79.9 -> grade = 'C'
        score < 70.0 -> grade = 'F'
    }
    println("Score : $score, grade : $grade")
}
  • 인자로 쓰이던 score를 when문에 직접 사용

다양한 자료형의 인자 받기

  • Any 자료형을 사용하면 다양한 자료형의 인자를 받을 수 있다.
    • Any : 자료형이 특별히 정해지지 않은 경우에 사용
      📍 무엇이든 될 수 있다 -> 묵시적 변환
fun main() {
    cases("Hello")
    cases(1)
    cases(System.currentTimeMillis()) // 현재시간을 Long형으로 반환
}

fun cases(obj: Any) {
    when (obj) {
        1 -> println("Int : $obj")
        "Hello" -> println("String : $obj")
        is Long -> println("Long : $obj")
        !is String -> println("Not a String")
        else -> println("Unknown")

    }
}

출력 :

String : Hello
Int : 1
Long : 1658370729747

📌 04-2 반복문

for문

for (요소 변수 in 컬렉션 or 범위) { 반복할 본문 }

📝 1부터 10까지 더하기

fun main() {
    var sum = 0
    for (x in 1..10) sum += x
    println("sum : $sum")
}

출력 : sum : 55

📝 하행, 상행 및 다양한 반복 방법

for (i in 5..1) print(i) // 아무것도 출력되지 않는다.

⚠️ ⬇️ 이렇게 해야 역순으로 출력 가능 ⚠️

for (i in 5 downTo 1) print(i)

출력 : 54321

or (i in 5 downTo 1 step 2) print(i)

출력 : 531

📝 for문을 활용한 삼각형 출력

fun main() {
    print("Enter the lines : ")
    val n = readLine()!!.toInt()

    for (i in 1..n) {
        for (space in 1..(n - i)) print(" ")
        for (star in 1..(2 * i - 1)) print("*")
        println()
    }
}

출력 :

Enter the lines : 5
   *
  ***
 *****
*******
*********

📝 1~100의 홀수, 짝수의 합 구하기

fun main() {
   var oddTotal = 0
   var evenTotal = 0

   for (i in 1..100 step 2) oddTotal += i
   println("Odd total : $oddTotal")

   for (i in 0..99 step 2) evenTotal += i
   println("Even total : $evenTotal")
}

출력 :

Odd total : 2500
Even total : 2450

while문

while(조건식) {
본문
...
}

  • 조건식이 true면 무한히 반복한다.
    • 조건식이 false이어야 탈출이 가능하다.

📝 while문 응용하여 팩토리얼 계산하기

fun main() {
    print("Enter the number : ")
    var number = readLine()!!.toInt()
    var factorial: Long = 1

    while (number > 0) {
        factorial *= number
        --number
    }

    println("Factorial : $factorial")
}

do~while문

  • while문과의 차이

    • while문 : 조건이 false면 한 번도 실행 ❌
    • do while : do 블록에 작성한 본문은 한 번 실행 후 조건 검사
  • do {
    본문
    } while(조건식)

fun main() {
    do {
        print("Enter an integer : ")
        val input = readLine()!!.toInt()

        for (i in 0..(input - 1)) {
            for (j in 0..(input - 1)) print((i + j) % input + 1)
            println()
        }
    } while (input != 0)
}

출력 :

Enter an integer : 5
12345
23451
34512
45123
51234
Enter an integer : 0

📌 04-3 흐름의 중단과 반환

  • 흐름 제어문
    • return : 함수에서 결괏값을 반환하거나 지정된 라벨로 이동한다.
    • break : for문이나 while문의 조건식에 상관없이 반복문을 끝낸다.
    • continue : for문이나 while문의 본문을 수행하지 않고 다시 조건식으로 넘어간다.
  • 예외 처리문
    • try {...} catch {...} : try 블록의 본문을 수행하는 도중 예외가 발생하면 catch 블록의 본문을 실행한다.
    • try {...} catch {...} finally {...} : 예외가 발생해도 finally 블록 본문은 항상 실행한다.

return문

  • return 이후의 코드는 실행되지 않는다.
    📍 return이 사용되면 코드흐름을 중단하고 함수의 역할을 끝낸다.
fun add(a: Int, b: Int): Int {
    return a + b
    println(" 여기는 실행 되지 않는다")
}

return으로 Unit 반환하기

  • return은 함수에서 값을 반환할 때 사용하는데, 값 없이 return만 사용할 경우 Unit이라는 자료형을 사용하는 것으로 본다.
    📍 3가지 표현방식이 있다.
1. Unit을 명시적으로 반환
fun hello(name: String): Unit {
    println(name)
    return Unit
}

2. Unit 이름을 생략한 반환
fun hello(name: String): Unit {
    println(name)
    return
}

3. return문 자체를 생략
fun hello(name: String) {
    println(name)
}

람다식에서 return 사용하기

fun main() {
    retFunc()
}

fun retFunc() {
    println("start retFunc")
    inlineLambda(13, 3) { a, b ->
        val result = a + b
        if (result > 10) return
        println("result : $result")
    }
	println("end of retFunc")
}

inline fun inlineLambda(a: Int, b: Int, out: (Int, Int) -> Unit) {
    out(a, b)
}

출력 : start retFunc

  • return 뒤 출력문은 실행되지 않음 -> 비지역 반환

람다식에서 라벨과 함께 return 사용하기

람다식 함수 이름 라벨이름@ {
...
return@라벨이름
}

  • 람다식에서 라벨을 정의해 return 사용하기
    📍 라벨이름@, return@라벨이름
fun main() {
    retFunc()
}

fun retFunc() {
    println("start retFunc")
    inlineLambda(13, 3) lit@ { a, b ->
        val result = a + b
        if (result > 10) return@lit
        println("result : $result")
    }
    println("end of retFunc")
}

fun inlineLambda(a: Int, b: Int, out: (Int, Int) -> Unit) {
    out(a, b)
}

출력 :

start retFunc
end of retFunc
  • 라벨을 붙인 함수의 끝으로 빠져나갈 수 있다.

암묵적 라벨

암묵적 라벨 : 람다식 표현식 블록에 직접 라벨을 쓰는 것이 아니라 람다식의 명칭을 그대로 라벨처럼 사용하는 것

fun retFunc() {
    println("start retFunc")
    inlineLambda(13, 3) { a, b ->
        val result = a + b
        if (result > 10) return@inlineLambda
        println("result : $result")
    }
    println("end of retFunc")
}
  • 위의 방법과 출력값은 같다.

익명 함수를 사용한 반환

fun retFunc() {
    println("start retFunc")
    inlineLambda(13, 3 fun(a, b) {
        val result = a + b
        if (result > 10) return@inlineLambda
        println("result : $result")
    })
    println("end of retFunc")
}
  • 가까운 익명 함수가 반환
    • 익명함수 : fun(..){..} 형태로 이름 없이 특정 함수의 인자로 넣을 수 있음
  • 람다식도 익명함수에 포함되지만 필요에 따라 쓰임이 다르다.

📝 람다식

    val getMessage = lambda@{ num: Int ->
        if (num !in 1..100) {
            return@lambda "Error"
        }
        "Sucess"
    }
  • return이 여러 개일 경우 눈에 잘 보이지 않음

📝 익명함수

    val getMessage = fun(num: Int): String {
        if (num !in 1..100) {
            return "Error"
        }
        return "Sucess"
    }
  • 익명 함수 방법을 사용하면 2개의 return이 확실하게 구별된다.

    📫 람다식 : 보통의 경우, 익명함수 : 명시적으로 반환해야 할 것이 여러 개일 경우

람다식과 익명 함수를 함수에 할당할 때 주의할 점

📝 람다식

fun greet() = { println("Hello") }
  • greet() 호출 시 아무 것도 반환되지 않음
    ➡️ greet()() greet()함수가 가지고 있는 함수를 사용하려면 이렇게 표기 해야한다.

📝 익명함수

fun greet() = fun() { println("Hello") }
  • 함수가 할당됨을 명시적으로 표현하려면 익명 함수를 써서 선언하는 것이 더 읽기 좋다.

break문과 continue문

  • break : 해당 키워드를 사용한 지점에서 for, while, do~while을 빠져 나온다.
  • continue : 이후 본문을 계속 진행하지 않고 다시 반복 조건을 살펴본다.
    📍 해당 반복문으로 다시 돌아감

📝 break

fun main() {
    for (i in 1..5) {
        if (i == 3) break
        println(i)
    }
    println()
    println("outside")
}

출력 :

1
2

outside
  • i가 3일 때 반복문을 빠져나옴

📝 continue

fun main() {
    for (i in 1..5) {
        if (i == 3) continue
        println(i)
    }
    println()
    println("outside")
}

출력 :

1
2
4
5

outside
  • i가 3일 때 반복문을 다시 돌린다.
    • println을 거치지 않고 4로 증가된 후 반복문 진행

beak와 continue에 라벨 함께 사용하기

📍 라벨을 사용하며 중단 위치 바꾸기

fun main() {
    labelBreak()
}

fun labelBreak() {
    println("labelBreak")
    for (i in 1..5) {
        second@ for (j in 1..5) {
            if (j == 3) break
            println("i : $i, j : $j")
        }
        println("after for j")
    }
    println("after for i")
}

출력 :

labelBreak
i : 1, j : 1
i : 1, j : 2
after for j
i : 2, j : 1
i : 2, j : 2
after for j
i : 3, j : 1
i : 3, j : 2
after for j
i : 4, j : 1
i : 4, j : 2
after for j
i : 5, j : 1
i : 5, j : 2
after for j
after for i
  • 흐름과 가장 가까운 반복문의 흐름을 중단 시킴 : second@ for가 중단됨
fun main() {
    labelBreak()
}

fun labelBreak() {
    println("labelBreak")
    first@ for (i in 1..5) {
        second@ for (j in 1..5) {
            if (j == 3) break@first
            println("i : $i, j : $j")
        }
        println("after for j")
    }
    println("after for i")
}

출력 :

labelBreak
i : 1, j : 1
i : 1, j : 2
after for i
  • 라벨을 붙인first@ for가 중단됨

continue도 결과가 같으니 생략~


예외처리

예외 : 해당 코드가 제대로 작동하지 못하고 중단되는 현상

  • 예외를 발생시키는 상황
    • 운영체제의 문제 잘못된 시스템 호출의 문제
    • 입력값의 문제 존재하지 않는 파일 or 숫자 입력란에 문자 입력 등
    • 받아들일 수 없는 연산 0으로 나누기
    • 메모리의 할당 실패 및 부족
    • 컴퓨터 기계 자체의 문제 전원 문제, 망가진 기억 장치 등

예외처리 : 프로그램을 실행할 때 발생할 수 있는 예외에 대비

  • 잠재적으로 예외가 발생할 수 있는 코드에 try~catch문으로 감싸두기
    📍 try블록에 예외가 발생하면 catch블록에서 잡아서 그 예외를 처리

    try {
    예외 발생 가능성이 있는 문장
    } catch (e: 예외 처리 클래스 이름) {
    예외를 처리하기 위한 문장
    } finally {
    반드시 실행되어야 하는 문장
    }

fun main() {
    val a = 6
    val b = 0
    val c: Int

    try {
        c = a / b
    } catch (e: Exception) {
        println("Exception is handled")
    } finally {
        println("finally 블록은 항상 실행")
    }
}

출력 :

Exception is handled
finally 블록은 항상 실행

특정 예외 처리

fun main() {
    val a = 6
    val b = 0
    val c: Int

    try {
        c = a / b
    } catch (e: ArithmeticException) {
        println("Exception is handled ${e.message}")
    } finally {
        println("finally 블록은 항상 실행")
    }
}

출력 :

Exception is handled / by zero
finally 블록은 항상 실행
  • ArithmeticException : 0으로 나누는 것 이외의 산술 연산에 대한 예외를 잡아 처리 함
  • e.message : 에러 원인을 출력해줌
profile
내가 왜 개발잔거지

0개의 댓글