Lewis's Tech Keep

[Kotlin] 코틀린 적응기 - 변수, 타입, 연산자 본문

Kotlin/Kotlin 적응기

[Kotlin] 코틀린 적응기 - 변수, 타입, 연산자

Lewis Seo 2024. 9. 29. 01:45

시작

이번에 코틀린을 쓰게 될 기회가 생길 것 같아서 코틀린 입문 강의를 하나 구입하였다.

아직 section2 중반까지만 들었는데 재밌어서 정리를 남겨보려고 한다.
쉽고 재밌고 예제도 다양해서 즐겁게 하고 있다.

 

배우고 있는 것

https://www.inflearn.com/course/java-to-kotlin

 

자바 개발자를 위한 코틀린 입문(Java to Kotlin Starter Guide) 강의 | 최태현 - 인프런

최태현 | 이 강의를 통해 Kotlin 언어의 특성과 배경, 문법과 동작 원리, 사용 용례, Java와 Kotlin을 함께 사용할 때에 주의할 점 등을 배울 수 있습니다., 요즘 대세인 코틀린을 공부하고 싶다면?⭐ J

www.inflearn.com

 

1. 변수

변수는 varval이 있다.

var(variable)는 값을 한번 할당하고 나서도 계속 바꿀 수 있는 mutable한 값이다.

val(value)는 값을 한번 할당하고나면 바꿀 수 없는 immutable한 값이다.
(final 키워드를 쓴 것과 비슷한 효과지만 nullable 표시를 해주면 처음에 할당하지 않아도 되는 차이가 있다.)

 

또한 nullable한 값일 경우 nullable을 명시 해 줄 수 있다.

어떤 타입을 선언 해 준 후에 ?를 붙이면 해당 값은 nullable 해질 수 있다는 뜻

 

그리고 객체 생성 시에 Java에서는 new Person() 과 같이 선언이 필요하지만 Kotlin에서는 Person()만으로 생성이 된다.

 

fun main() {
    // variable mutable 한 변수
    var number1: Long = 10L
    // value immutable 한 변수 (final과 같은 느낌)
    val number2 = 100L
    // nullable 선언
    var number3: Long? = 1_000L // nullable, val 괜찮다.
    number3 = null
    // 객체 생성
    var person = Person("hihi") // no new keyword
}

 

 

2. Nullable

먼저 함수 파라메터를 nullable하게 받고 싶다면 타입 뒤에 ?를 추가하여 nullable하게 받을 수 있는 값임을 명시한다.

 

// nullable parameter function throw exception
fun startsWithA1(str: String?): Boolean {
    if (str == null) {
        throw IllegalArgumentException("null hi")
    }

    return str.startsWith("A")
}


return 하는 값도 특정 값이 아닌 null 값을 return 하고 싶다면 return 타입에도 ? 를 붙여준다.

// nullable parameter function return nullable
fun startsWithA2(str: String?): Boolean? {
    if (str == null) {
        return null
    }

    return str.startsWith("A")
}

 

str == null 과 같은 코드들은 잘못하면 실수 할 가능성도 있는 코드라고 생각하는데,

이 때 safe call을 쓰면 ?로 값이 없을 수 있고 없는 경우 null 을 반환한다는 것을 알릴 수 있다.

// nullable parameter function safe call
fun startsWithA2SafeCall(str: String?): Boolean? {
    return str?.startsWith("A")
}

 

elvis 연산자(?:)를 이용하면 null일 때 어떤 행동을 할 것인지 뒤에 적을 수 있다.

예제는 에러를 던져보았다.

// nullable parameter function elvis operator
fun startsWithA2Elvis(str: String?): Boolean {
    return str?.startsWith("A")
        ?: throw IllegalArgumentException("hihi")
}

 

early return 해줄 때 elvis 연산자를 이용하면 이런식으로도 가능하다. (null 일 때 false 반환)

// nullable parameter function early return
fun startsWithEarlyReturn(str: String?): Boolean {
    str ?: return false

    return str.startsWith("A")
}

 

엔티티와 같이 처음에 받을 때는 null이지만 실제로 작동할 때는 non-null인 경우에
일단 parameter 연산자는 ? 를 선언하지만 !!를 통해 해당 변수가 non-null임을 선언할 수 있다.

// not nullable
// runtime npe exception
fun startsWithNotNull(str: String?): Boolean {
    return str!!.startsWith("A")
}

 

3. 타입

코틀린은 타입 선언이 중요하기에 타입 변경 시
암시적으로 바뀌는 Java와는 달리 toLong()과 같은 메서드를 이용하여 명시적 변경을 해주어야 한다.

fun main() {
    // type 의 명시적 변경이 필요함
    val number1: Int? = 3
    var number2: Long = number1?.toLong() ?: 0L
}


객체 생성 시에 타입 선언 시 as를 넣어주면 타입을 선언할 수 있다.

그렇지만 as를 선언하지 않아도 기본적으로 되긴한다.

fun main() {
    // null 로 불러보기 (해당 함수는 nullable하지 않기 때문에 런타임 npe가 발생함)
    printAgeIfPerson(null)

    // person 예제
    printAgeIfPerson(Person("", 10))
}

fun printAgeIfPerson(obj: Any) {
    if (obj is Person) {
        val person = obj as Person // 생략해도 알아서 타입 추론 해 주는 듯
        println(person.age)
    }
}

 

nullable하게 타입을 받아주게 하려면 일단 Any? 로 받은 후에 as? 를 통해 null한 값도 받을 수 있다.

fun main() {
    // null 로 불러보기
    printAgeIfNotPerson(null)

    // person 예제
    printAgeIfNotPerson(Person("", 10))
}

fun printAgeIfNotPerson(obj: Any?) {
    // 생략해도 알아서 타입 추론 해 주는 듯
    // nullable 할 때
    val person = obj as? Person

    println(person?.age)
}

 

string.format 같이 변수가 들어간 어떤 string 구문을 쓰고 싶을 경우 활용할 수 있는 방법들

fun main() {
    // String interpolation String Indexing
    val person = Person("hi", 100)
    val log = "사람 이름 ${person.name} 이고 나이는 ${person.age}세 입니다"
    println(log)
    // trim indent
    val log2 = """
        ABC
        DFG
        ${person.name}
    """.trimIndent()
    println(log2)
    // get index string
    println(log2[0])
}

 

그 외 특이한 타입들

Any 타입

Java의 Object와 같은 최상위 객체 타입, 뭐든 받을 수 있다.

 

Unit 타입

Java 타입 중에 void 타입과 비슷하다. 아무것도 반환하지 않는 것 처럼 보이지만 실제로는 Unit을 return 하고 있는 것이다.

아무 타입을 명시하지 않고 함수를 사용한다면 Unit 타입을 반환한다고 생각하면 된다.

fun sayHello(): Unit {
    println("Hello!")
}

 

Nothing 타입

무한 반복 루프나 아무것도 하지않고 예외만 던지는 것에 사용 (실제로 사용은 잘 안한다고 함)

fun fail(message: String): Nothing {
    throw IllegalArgumentException("")
}

 

4. 연산자

 

>, < 와 같은 부등호만 써도 compareTo를 자동으로 읽는다.

fun main() {
    val money1_1 = JavaMoney(2_000L)
    val money1_2 = JavaMoney(1_000L)

    // automatically check compareTo with operators only
    if (money1_1 > money1_2) {
        println("ok")
    }
}

 

새로운 객체를 생성하고 == 로 주소 비교를 하더라도 equals를 실행하기 때문에 equals가 설정되어있다면 true다.

equals 없이 data class로 하면 java와 같이 false인 것을 확인함.

fun main() {
    val money2_1 = JavaMoney(1_000L)
    val money2_2 = money2_1
    val money2_3 = JavaMoney(1_000L)
    // true
    println(money2_1 == money2_3)
}

 

아래의 경우 자바라면 money3_1.plus(money3_2)를 불러주어야 하지만 코틀린에서는 money3_1 + money3_2 로 해결된다.

fun main() {
    // 연산자 overloading
    val money3_1 = Money(1_000L)
    val moeny3_2 = Money(2_000L)
    println(money3_1 + moeny3_2)
}

data class Money (
    val amount: Long
) {

    operator fun plus(other: Money): Money {
        return Money(this.amount + other.amount)
    }
}

 

Comments