kotlin/기초

kotlin 문법 기초-1

blogger903 2024. 7. 10. 01:02
728x90

kotlin 개발전 문법관련 기초내용 정리 포스트입니다

인프런 - 코틀린 문법부터 실무까지 (자바 to 코틀린 실무) 강의를 보면서 예시 코드를 다르게 하여 포스팅합니다
typescript, java 개발 경험이 있습니다

다루는 주제

  • 변수
  • when, enum
  • 반복문
  • 예외처리

변수

  • val
  • var

val은 상수
var는 변수를 저장하는데 사용합니다

템플릿 문자열

val i: Int = 123  
val j = 123  
var age = 36  

fun sum(a:Int, b:Int, c:Int) = a + b + c  

fun sum(a:Int, b:Int): Int {  
    return a + b  
}  

fun main() {  
    age = 30  
    println("1+2 = " + sum(1,2))  
    println("age is $age")  
    // expression도 가능
    println("age is ${sum(age, 3)}")
}

when, enum

// java enum
public enum JumSim {
    PyungRaeng
    HaeJangGuk
    SunDaeGuk
}

// kotlin enum
enum class JumSim {
    PyungRaeng
    HaeJangGuk
    SunDaeGuk
}

// 프로퍼티와 메서드를 갖는 enum class
enum class JumSim(val price, val size) {
    PyungRaeng(15000, 40)
    HaeJangGuk(12000, 80)
    SunDaeGuk(12000,80)

    fun getPrice() = price
}
enum class Day(private val shortName: String) {
    MONDAY("Mon"),
    TUESDAY("Tue"),
    WEDNESDAY("Wed"),
    THURSDAY("Thu"),
    FRIDAY("Fri"),
    SATURDAY("Sat"),
    SUNDAY("Sun");

    val isWeekend: Boolean
        get() = this == SATURDAY || this == SUNDAY

    fun getShortName(): String = shortName
}

println(Day.MONDAY.getShortName())  
println(Day.SATURDAY.isWeekend)     

when으로 enum 클래스 다루기

// 1:1 조건
fun getJumSim(jumSim: JumSim): String =
    when (jumSim) {
        PyungRaeng -> "PyungRaeng"
        HaeJangGuk -> "HaeJangGuk"
        SunDaeGuk -> "SunDaeGuk"
    }

// 다중 조건
fun getJumSim(jumSim: JumSim) = 
    when (jumSim) {
        PyungRaeng -> 15000
        HaeJangGuk, SunDaeGuk -> 12000
    }

enum에 값이 추가되면 when쪽에서 컴파일에러 발생.. 대박기능

인자 없는 when

fun oneuluegerda(jumSim: JumSim): Int {  
    when {  
        jumSim == JumSim.PyungRaeng -> 2  
        jumSim == JumSim.SunDaeGuk -> 1  
        jumSim == JumSim.HaeJangGuk -> 1  
        else -> throw RuntimeException()  
    }  
}

이렇게 TODO를 사용할수 있음

fun isAdult(age: Int): Boolean = age >= 35  

fun trueOrFalse(): String = when(isAdult(20)) {  
    true -> TODO()  
    false -> TODO()  
}

스마트 캐스트

타입 검사와 타입 캐스트가 동시에!
이런건 처음봄

fun printObject(obj: Any) {  
    when(obj) {  
        // smart case 덕분에 Duration 변환되어 inWholeHours 프로퍼티 접근  
        is Duration -> println(obj.inWholeHours)  
        // smart case 덕분에 JumSim 변환되어 name 프로퍼티 접근  
        is JumSim -> println(obj.name.lowercase())  
        // smart case 덕분에 LocalDateTime 변환되어 month 프로퍼티 접근  
        is LocalDateTime -> println(obj.month)  
        else -> println("Unknown")  
    }  
}

Java: 타입 검사 후, 명시적 형변환이 반드시 필요함. 이건 ts도 동일
Kotlin: 타입 검사할 때 자동으로 형변환까지 진행(smart cast)

직접 형변환도 가능

val deliciousSth = jumSim as JumSim

if문에서의 스마트 캐스트

fun printObject2(obj:Any): String = 
    if (obj is String) {
        println(obj.lowercase())
        obj.lowercase()
    } else if (obj is Duration) {
        print(obj.nano)
        obj.nano.toString()
    } else throw RuntimeException()

if, when등 실행부분이 {} 블록인경우 마지막 값이 결과값으로 취급됨

fun printObject2(obj:Any): String =
    if (obj is String) {
        obj.lowercase()
    } else if (obj is Duration) {
        print(obj.nano)
        obj.toString()
    } else throw RuntimeException()
import com.example.*
import java.time.Duration

fun main() {

    println(printObject2("Hello"))
    println(printObject2(Duration.ZERO))
    println(printObject2(1))
}
hello
0PT0S
Exception in thread "main" java.lang.RuntimeException
    at com.example.JumSimKt.printObject2(JumSim.kt:50)
    at MainKt.main(Main.kt:8)
    at MainKt.main(Main.kt)

반복문

fun evenOrOdd(n: Int) = when {
    n % 2 == 0 -> "Even"
    else -> "Odd"
}

fun arrIndices() {
    val arr = intArrayOf(1, 2, 3, 4, 5)

    val result = arr.indices
        .map {
            println("map: $it")
            it
        }
        .map { arr[it] * 2 }
        .filter { it > 5 }
        .toList()

    println(result)
}

fun main() {
    for ( i in 1..100){
        println(evenOrOdd(i))
    }

    println("=====================================")

    // until은 마지막 숫자를 포함하지 않는다.
    for (i in 1 until 100){
        println(evenOrOdd(i))
    }

    println("=====================================")

    // downTo는 역순으로 순회한다.
    for (i in 100 downTo 1){
        println(evenOrOdd(i))
    }

    println("=====================================")

    // step은 순회하는 간격을 지정한다.
    for (i in 100 downTo 1 step 2){
        println(evenOrOdd(i))
    }

    println("=====================================")

	// index 범위만큼 순회한다.
	arrIndices()
}

in을 이용한 범위검사

fun isLetter(c: Char) = c in 'a'..'z' || c in 'A'..'Z'

fun isDigit(c: Char) = c in '0'..'9'

fun isNotDigit(c: Char) = c !in '0'..'9'

fun recognize(c: Char) = when (c) {
    in '0'..'9' -> "It's a digit!"
    in 'a'..'z', in 'A'..'Z' -> "It's a letter!"
    else -> "I don't know..."
}

// a in start..end: start<=a && a<=end 로 변환됩니다
// a !in start..end: !(start<=a && a<=end)로 변환됩니다
// a in end downTo start: start<=a && a<=end로 변환됩니다
// a in start until end: start<=a && a<end로 변환됩니다
// a !in start until end: !(start<=a && a<end)로 변환됩니다

map을 이용한 반복문

val map = mapOf(
    "a" to 1,
    "b" to 2,
    "c" to 3
)

val map2 = mutableMapOf<String, Int>().apply {
    this["a"] = 1
    this["b"] = 2
    this["c"] = 3
}

// listOf, mapOf, setOf 등의 컬렉션은 Iterable 인터페이스를 구현하고 있다.

fun main() {


    val map3 = mutableMapOf<String, Int>()
    map3["a"] = 1
    map3["b"] = 2
    map3["c"] = 3


    // map의 key, value를 출력
    for ((key, value) in map) {
        println("key: $key, value: $value")
    }

    // map의 key만 출력
    for (key in map.keys) {
        println("key: $key")
    }

    // map의 value만 출력
    for (value in map.values) {
        println("value: $value")
    }

    // map의 key, value를 출력
    map.forEach { (key, value) ->
        println("key: $key, value: $value")
    }

    // map의 key만 출력
    map.keys.forEach { key ->
        println("key: $key")
    }

    // map의 value만 출력
    map.values.forEach { value ->
        println("value: $value")
    }

    // map의 key, value를 출력
    map2.forEach { (key, value) ->
        println("key: $key, value: $value")
    }

    // map의 key만 출력
    map2.keys.forEach { key ->
        println("key: $key")
    }

    // map의 value만 출력
    map2.values.forEach { value ->
        println("value: $value")
    }
}

예외처리

import java.io.IOException
import java.lang.RuntimeException

fun main() {
    try {
        Integer.parseInt("123")
        throw IOException("Error parsing string to int")
    } catch (e: IOException) {
        throw RuntimeException("Error parsing string to int", e)
    } finally {
        println("Finally block")
    }
}

Checked Exception이라고 해도 함수 시그니처에 throws IOException을 붙이지 않아도 됩니다

spring에서 @Transactional에서는 어떻게 적용되나?

CheckedException은 롤백이 되지 않습니다
코틀린은 컴파일러가 알려주지 않기 때문에 CheckedException이 발생할 위치에 try catch를 걸어줘야 합니다

SQLException도 CheckedException인데?

SQLException도 CheckedException인데 SQLException있을때 어떻게 spring에서 트랜잭션 롤백이 발생하나?

Spring 프레임워크에서는 SQLException과 같이 Checked Exception의 남용으로 인한 페해를 줄이고자 DataAccessException과 같은 Runtime Exception으로 포장해서 API를 제공하고 있습니다.

참고: https://www.slipp.net/questions/282

'kotlin > 기초' 카테고리의 다른 글

kotlin 코루틴 정리 - 1  (0) 2024.08.25
kotlin 문법 기초 - 4  (0) 2024.07.23
kotlin 문법 기초 - 3  (0) 2024.07.17
kotlin 문법 기초 - 2  (1) 2024.07.14