티스토리 뷰

Java & Kotlin

[Kotlin] 변수와 자료형 (2)

터프남 2021. 4. 6. 18:33
728x90

[Kotlin] 변수와 자료형 (2) 까지 갈 생각은 없었으나 좀 길어질 것 같아서 나눴다.

지금 작성하려는 부분이 코틀린에서 자랑(?) 하는 nullable에 관한 이야기인 것 같아서이다.

코틀린을 구글에 검색해봐도 항상 나오는 이야기가 NullPointerException(NPE) 에 대한 예외를 예방할 수 있다는 장점이 있다.

프로그래머라면 NPE 오류는 한번 쯤은 겪어봤을 만한 이야기이다. 코틀린에서는 아예 이런 오류를 미리 방지할 수 있다.

null을 허용한 변수 검사

코틀린은 변수를 사용할 때 반드시 값이 할당되어 있어야 한다는 원칙이 있다. 만약 값이 할당되지 않은 변수를 사용하려고하면 컴파일 오류가 발생한다.

코틀린에서는 변수에 반드시 값을 할당해야한다.

코틀린에서도 값에 null을 할당할 수는 있지만 특별한 기호를 사용해야 한다. 바로 물음표(?)이다.

코틀린의 물음표(?) 기호로 NPE로 부터 좀 더 안전하게 프로그래밍 할 수 있다.

 

코틀린에서 변수에 직접 null을 할당해보자. 아래와 같은 오류가 나타난다.

fun main() {
    var str1: String = "Hello World"
    str1 = null	//오류 null을 허용하지 않음
    println("str1 = $str1")
}

만약 null을 허용하고 싶다면 str1에 위에서 설명했던 null을 허용할 수 있게하는 물음표 기호를 사용하면 된다.

fun main() {
    var str1: String? = "Hello World"
    str1 = null
    println("str1 = $str1")
}

//결과
str1 = null

str1 변수 선언 시 자료형 뒤에 물음표(?) 기호를 넣으면 컴파일 오류가 나지 않고 결과도 null로 나온다.

변수의 null 허용 여부에 따라 String과 String?이 서로 다른 자료형이란 것을 이해해야 한다.

Safe call과 non-null 단정기호 

위의 코드에서 문자열 str1의 길이를 구하려면 어떻게해야할까? str1.length를 사용하면 될 것 같지만 null 이므로 null에 점(.)을 찍으면 NPE가 발생될 것 같은데.. 맞다. IDE내에서도 컴파일 오류를 발생시킨다.

친절하게도 IDE에서 알려주는 오류를 읽어보면 String? 형에서는 safe call (?.) 이나 non-null 단정기호(!!.)만 허용한다는 팁이 나온다.

즉 str1의 length 에 접근하려면 이 2가지 기법 중 하나를 사용해야 한다.

먼저 safe call (?.) 을 실행해보자.

fun main() {

    var str1: String? = "Hello World"
    str1 = null
    println("str1: $str1, length: ${str1?.length}")
}

//결과
str1: null, length: null

컴파일 오류없이 잘 실행이된다. 그러나 결과값은 모두 null이다. 이 코드는 str1을 검사한 다음에 null이 아니면 str1의 멤버 변수인 length에 접근해 값을 읽도록 만든 코드이다. str1을 검사해보니 null 이기 때문에 length에 접근하지 않고 바로 null을 출력한다.

 

다른 기법인 non-null 단정기호 (!!.)를 사용하면 어떻게 될까? non-null 단정기호는 변수에 할당된 값이 null이 아님을 단정하므로 컴파일러가 null 검사 없이 무시한다. 따라서 변수에 null이 할당되어 있어도 컴파일은 잘 진행되고 실행중에 NPE를 발생시킨다.  (책에서는 이렇게 되어있으나 직접 타이핑 해보면 컴파일 오류를 출력한다.)

str1이 null이므로 컴파일에서 length가 정의되어 있지 않다고 메시지가 나온다.

Elvis (엘비스) 연산자 사용

null을 허용한 변수를 조금 더 안전하게 사용하려면 세이프 콜(?.)과 엘비스(?:) 연산자를 같이 사용하면 된다.

엘비스 연산자는 변수가 null 인지 아닌지 검사해서 null이라면 왼쪽 식 null이 아니면 오른쪽 식을 실행한다.

fun main() {
    var str1: String? = "Hello Kotlin"
    str1 = null

    //Safe-Call 연산자 ?. 와 Elvis 연산자 ?:를 사용
    // 엘비스 연산자는 null이 아니라면 왼쪽 식 실행 null이면 오른쪽 실행
    println("str1: $str1 length: ${str1?.length ?: -1}")
}

//결과
str1: null length: -1

세이프 콜과 엘비스 연산자를 사용하면 null 발생을 대비할 수 있으므로 안전하다.

자료형 비교하고 검사하고 변환하기

자바에서는 서로 다른 자료형을 연산하더라도 두 자료형 중 큰 자료형으로 받을 수 있다.

int intValue = Integer.MAX_VALUE;
long longValue = 2L;

long result = intValue + longValue;
System.out.println("result = " + result);

//결과
result = 2147483649

그러나 코틀린에서는 자료형이 서로 다른 변수를 비교하거나 연산할 수 없다. 예를 들어 Int형으로 선언한 변수와 Long형으로 선언한 변수를 서로 더하거나 뺄 수 없다.

코틀린에서는 자료형이 서로 다른 변수를 같은 자료형으로 만들어야 연산할 수 있다.

자바에서는 서로 다른 자료형이라도 int와 double 이라면 double이 더 큰 자료형이므로 int형의 값을 double의 변수에 할당하면 자동으로 int값이 double로 변환이 된다.

//자바 코드
int a = 100;
double b = a;

//컴파일 오류 없음

코틀린에서는 Int 형 값을 Double에 할당할 경우 컴파일 에러가 난다.

코틀린에서 Int형 변수를 Double에 할당하려면 Int형 변수를 Double로 변환한 후에 할당해야 한다.

val a: Int = 100
val b: Double = a	//컴파일 오류

//해결방법
val b: Double = a.toDouble() //변환 메서드 사용

만약 표현식에서 자료형이 서로 다른 값을 연산하면 이때는 자료형이 표현할 수 있는 범위가 큰 자료형으로 자동 형 변환되어 계산된다.

val result = 1L + 100

//Long형

기본형과 참조형 자료형의 비교

코틀린에서 값 비교연산  == (등호2개) ===(등호3개) 등호는 자바스크립트와 닮았다.

==는 값에 대한 연산만 결과로 알려주고 참조주소 값이 같은지 확인하려면 === 비교연산을 하면된다.

fun main() {
    val a: Int = 128
    val b = a   //기본형 값 대입한거임

    println(a === b)    //true

    val c: Int? = a //null을 허용한 변수는 참조형으로 저장된다.
    val d: Int? = a
    val e: Int? = c

    println(c == d) // == 두개는 값만 비교  true
    println(c === d)    //값의 내용은 같지만 참조 주소를 비교해 다른 객체(주소 다름) 이므로 false
    println(c === e)    //값의 내용도 같고 참조된 객체도 동일(주소 동일) 하므로 true

}

//결과
true
true
false
true

스마트 캐스트

어떤 값이 정수일 수도 실수일 수도 있다면 컴파일러가 자동으로 형 변환을 하는 스마트 캐스트(Smart Cast)를 사용하는 것이 편리하다.

대표적으로 스마트 캐스트가 적용되는 자료형은 Number 형이 있다. Number 형을 사용하면 숫자를 저장하기 위한 특수한 자료형 객체를 만든다. Number형으로 정의된 변수에는 저장되는 값에 따라 정수형이나 실수형 등으로 자료형이 변환된다.

fun main() {
    //컴파일러가 자동으로 형 변환을 하는 스마트캐스트(Smart cast)
    var test: Number = 12.2 //12.2에 의해 test는 Float형으로 스마트 캐스트
    println("$test")

    test = 12   //int형
    println("$test")

    test = 120L //Long
    println("$test")

    test += 12.0f   //Float형
    println("$test")
}

//결과
12.2
12
120
132.0

자료형 검사

코틀린에서 자료형 검사를 하려면 is 키워드를 사용하면 된다.

is는 왼쪽 항의 변수가 오른쪽 항의 자료형과 같으면 true 아니면 false를 반환한다. 코드를 보면 바로 알수 있다.

fun main() {
    val num = 256

    if (num is Int) {
        print(num)
    }else if (num !is Int) {
        print("Not a Int")
    }
}

//결과
256

as에 의한 스마트 캐스트

as 키워드로 스마트 캐스트할 수도 있지만 as는 형 변환이 가능하지 않으면 예외를 발생시킨다.

val x: String = y as String

이 경우 y가 null이 아니면 String으로 형 변환되어 x에 할당된다. 반대로 y가 null이면 형 변환을 할 수 없어 예외가 발생한다.

null 가능성까지 고려해서 예외를 피하려면 물음표(?)기호를 사용하면 된다.

val x: String? = y as? String

참고

Do it 코틀린 프로그래밍 www.yes24.com/Product/Goods/74035266

728x90
댓글
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
«   2024/05   »
1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30 31
글 보관함