Kotlin Study 05

박채빈·2021년 9월 18일
0

KotlinStudy

목록 보기
6/7
post-thumbnail

IDE : Intellij
JDK : zulu11

프로그램의 흐름 제어

조건문

IfCondition.kt

fun main() {
    val a = 12
    val b = 7

    val max = if(a > b){
        println("a 선택")
        a   // 마지막 식인 a가 반환되어 max에 할당
    } else {
        println("b 선택")
        b   // 마지막 식인 b가 반환되어 max에 할당
    }

    println(max)
}

IfElseIfCondition.kt

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

    if (score >= 90)    grade = 'A'
    else if (score in 80.0..89.9)   grade = 'B'
    else if (score in 70.0..79.9)   grade = 'C'

    println("Score: $score, Grade: $grade")
}

readLine() : 콘솔로부터 문자열을 입력받는 함수

in 연산자와 범위 연산자(..)

둘 다 같은 표현
if (score in 80.0..89.9)
if (score >= 80.0 && score <= 89.9)

WhenArgs.kt

fun main() {
    print("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")
}

when문으로 가능한 것

when (x) {
	1 -> print("x == 1")
	2 -> print("x == 2")
	else -> {	// 블록 사용 가능
		print("x는 1, 2가 아닙니다.)
	}
}

when (x) {
	0, 1 -> print("x == 0 or x == 1")	// 일치되는 조건 여러개 표현 가능
	else -> print("기타")
}

when (x) {
	parseInt(s) -> print("일치함!")	// 함수 반환값 사용 가능
	else -> print("기타")    
}

WhenNoArgs.kt

fun main() {
    print("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 >= 90.0 과 같이 변수와 조건식을 when문에 직접 사용할 수 있다.

WhenAnyCase.kt

fun main() {
    cases("Hello")
    cases(1)
    cases(System.currentTimeMillis())
    cases(MyClass())
}

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")
    }
}

when문의 인자로 Any를 사용하면 다양한 자료형의 인자를 받을 수 있다.

실행결과

String: Hello
Int: 1
Long: 1631946124704
Not a String

반복문

ForSum.kt

fun main() {
    var sum = 0

    for(x in 1..10) sum += x
    println("sum : $sum")
}

Kotlin for문 기본형
1. 하행 반복

for (i in 5 downTo 1) print(i)	// downTo 키워드 사용
  1. step 지정
for (i in 5 step 2)	print(i)	// 2단계씩 증가

ForTriangle.kt

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

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

for문 응용. *로 삼각형 그리기
실행 결과

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

WhileFactorial.kt

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

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

    println("Factorial: $factorial")
}

while문 응용. 팩토리얼 계산

DoWhileLoop.kt

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

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

do-while문 응용. 콘솔로부터 입력받은 숫자를 순서대로 나열하고 한 자리씩 자리를 옮겨 가며 순환한다.


흐름의 중단과 반환

흐름 제어문

  1. return
  2. break
  3. continue

예외 처리문

  1. try{...}catch{...}
  2. try{...}catch{...}finally{...}

return으로 Unit 반환

// 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)
}

람다식에서 retrun 사용

InlineLambdaRetrun.kt

fun main() {
    retFunc()
}

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

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

inline으로 선언되지 않은 람다식에서는 return@lable 과 같이 라벨 표기와 함께 사용해야 한다.
위 예제의 경우, 3 에서 return문이 실행되며 람다식 바깥의 retFunc()함수까지 종료시킨다. (비지역 반환)
실행 결과

start of retFunc

NoInlineLambdaReturn.kt

fun main() {
    retFunc()
}

fun inlineLambda(a: Int, b: Int, out: (Int, Int)->Unit) = out(a, b) // inline 제거

fun retFunc(){
    println("start of retFunc")
    inlineLambda(13, 3) lit@{ a, b ->	// 1. 람다식 블록 시작 부분에 라벨 지정
        val result = a + b
        if(result > 10) return@lit	// 2. 라벨을 사용한 블록의 끝으로 이동
        println("result: $result")
    }	// 3. 라벨을 사용한 블록의 끝
    println("end of retFunc")
}
람다식 함수 이름 라벨 이름@{
	return@라벨 이름
}

과 같이 라벨을 정의해 return을 사용하여 비지역 반환을 방지할 수 있다.
실행 결과

start of retFunc
end of retFunc

암묵적 라벨

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

익명 함수는 일반 함수처럼 작동하기 때문에 return도 일반 함수에서 반환되는 것과 같이 사용할 수 있다.

  1. 람다식 방법
val getMessage = lambda@ { num: Int ->
	if(num !in 1..100) {
		return@lambda "Error"	// 라벨을 통한 반환
	}
	"Success"	// 마지막 식 반환
}
  1. 익명 함수 방법
val getMessage = fun(num: Int): String {
	if(num !in 1..100) {
		return "Error"	// 라벨을 통한 반환
	}
	return "Success"	// 마지막 식 반환
}

return을 사용하여 명시적으로 반환해야 할 것이 여러 개라면 익명 함수를 쓰는 것이 좋다.

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

fun greet() = {println("Hello")}

fun main(){
	greet()	// 아무것도 출력되지 않음
	greet()() // Hello 출력
}

할당 연산자에 의해 람다식 {println("Hello")} 자체가 greet() 함수에 할당된 것 뿐이기 때문에 greet()()를 사용해야 greet() 함수가 가진 함수를 사용할 수 있다.

fun greet() = func() {println("Hello")}	// 익명 함수를 사용하여 
					// 함수가 할당됨을 명시적으로 표현
fun greet() = run {println("Hello")}
fun greet() = println("Hello")

break, continue

NormalBreakContinue.kt

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

break문을 사용하여 반복문을 빠져나갈 수 있다.

실행 결과

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

continue문을 사용하여 for문의 시작 지점으로 돌아갈 수 있다.

실행 결과

1245
outside

break, continue에 라벨 사용

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")
}

break문이 가장 가까운 second@ 블록을 탈출한다.

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")
}

break문이 first@ 블록을 탈출한다.

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

continue문이 first@ 블록으로 돌아간다.


예외처리

  • 예외 : 코드가 제대로 작동하지 못하고 중단되는 현상
    • 운영체제의 문제
    • 입력값의 문제
    • 받아들일 수 없는 연산 (Divide By 0)
    • 메모리의 할당 실패 및 부족
    • 컴퓨터 기계 자체 문제

TryCatch.kt

fun main() {
    val a = 6
    val b = 0
    val c: Int
    
    try {
        c = a / b
    } catch (e: ArithmeticException) {
        println("Exception is handled. ${e.message}")
//        e.printStackTrace()
    } finally {
        println("finally 블록은 반드시 실행됨")
    }
}

try 블록에서 예외가 발생하고 catch 블록 구문이 출력된다.

실행 결과

Exception is handled. / by zero
finally 블록은 반드시 실행됨

catch 구문을 e.printStacTrace()로 수정하여 스택을 추적할 수 있다.

실행 결과

finally 블록은 반드시 실행됨
java.lang.ArithmeticException: / by zero
	at ch04.section3.TryCatchKt.main(TryCatch.kt:12)
	at ch04.section3.TryCatchKt.main(TryCatch.kt)

ThrowException

fun main() {
    var amount = 600

    try {
        amount -= 100
        checkAmount(amount)
    } catch (e: Exception) {
        println(e.message)
    }
    println("amount: $amount")
}

fun checkAmount(amount: Int){
    if(amount < 1000)   throw Exception("잔고가 $amount 으로 1000 이하입니다.")
}

throw 키워드로 의도적으로 예외를 발생할 수 있다.
amount가 1,000 이하일 때 throw로 예외를 발생시키고 main() 함수의 catch가 잡아 처리한다.

실행 결과

잔고가 500 으로 1000 이하입니다.
amount: 500

CustomExceptionTest.kt

// 사용자 예외 클래스
class InvalidNameException(message: String): Exception(message)

fun main() {
    val name = "Kildong123"

    try {
        validateName(name)
    } catch (e: InvalidNameException) {
        println(e.message)
    } catch (e: Exception) {
        println(e.message)
    }
}

fun validateName(name: String){
    if(name.matches(Regex(".*\\d+.*"))) // name에 숫자가 포함되어 있을 경우
        throw InvalidNameException("Your name : $name : contains numerals.")
}

Exception 클래스의 하위 클래스인 InvalidNameException을 만들어 사용할 수 있다.

profile
안드로이드 개발자

0개의 댓글