Java에서는 암시적 형변환과 명시적 형변환 둘 다 가능했는데 Kotlin에서는 여러가지 오류를 막기위해 개발자가 직접 형변환을 해야하는 명시적 형변환을 지원한다.
* 명시적 형변환 : 개발자가 직접 자료형을 지정해 형변환
* 암시적 형변환 : 자료형을 지정해주지 않아도 자동으로 형변환
Java에서는 아래와 같은 코드로 형변환이 가능했다.
Java에서 명시적 형변환은 (자료형) 형식으로 작성해주면 해당 값은 작성해준 자료형으로 형변환된다.
결과가 잘 출력되는 것을 볼 수 있다.
하지만 Kotlin에서는 암시적 형변환은 지원되지 않는다. 오로지 명시적 형변환만 지원한다.
기본 타입 형변환
Kotlin에서는 명시적 형변환을 할때 여러가지 함수들을 제공한다.
함수 | 설명 | 예 |
toByte() | Byte으로 강제 형변환 | a.toByte() |
toUByte() | UByte으로 강제 형변환 | a.toUByte() |
toShort() | Short으로 강제 형변환 | a.toShort() |
toUShort() | UShort으로 강제 형변환 | a.toUShort() |
toInt() | Int으로 강제 형변환 | a.toInt() |
toUInt() | UInt으로 강제 형변환 | a.toUInt() |
toLong() | Long으로 강제 형변환 | a.toLong() |
toULong() | ULong으로 강제 형변환 | a.toULong() |
toFloat() | Float으로 강제 형변환 | a.toFloat() |
toDouble() | Double으로 강제 형변환 | a.toDouble() |
toChar() | Char으로 강제 형변환 | a.toChar() |
toString() | String으로 강제 형변환 | a.toString() |
String은 Java와 동일하다.
Kotlin에서 제공하는 함수들로 간단하게 형변환을 할 수 있다.
is 연산자
Java에서는 객체가 어떤 객체인지 비교하고 싶을때 instanceof를 사용했었는데 Kotlin에서는 is 연산자를 사용해 어떤 객체인지 비교한다. -> 클래스 비교(값 X, 객체/타입 O)
어떤 객체가 그 객체의 값, 객체/자료형인지를 비교하고 싶을때 사용하며 Boolean형으로 반환한다. 때로는 when문을 사용할 때 is 연산자를 사용해서 그 값이 동일한지 확인하는 용도로 사용한다.
위 코드에서 알 수 있는 사실이 있다. if문에서 타입 체크하고 맞으면 체크한 타입으로 자동 형변환을 해준다. 이를 스마트 캐스팅이라고 부른다. (캐스팅 == 형 변환)
이렇게 되면 if문의 중괄호 안에서 변경된 타입으로 이것저것 할 수 있다는 소리인데..
(단, is 연산자를 캐스팅 용도로 사용하려면 조건문에서만 가능하며 아닌 경우에는 객체/타입 체크 용으로만 사용된다.)
해당 변수 위에 마우스를 가져다대면 스마트 형변환됐다고 나온다.
as 연산자
as 연산자는 is 연산자와 비슷한 점이 있다. 둘 다 스마트 캐스팅을 해준다는 말인데. 뭐가 다른지 알아보자.
as 연산자는 조건문 없이 스마트 캐스팅 되고 선언한 이후 시점부터 해당 클래스에 전역으로 캐스팅된다.
is 연산자를 사용했을 경우에는 조건문 중괄호 안에서만 캐스팅된 타입으로 사용 가능했고 빠져나올시 다시 원래 타입으로 돌아갔었는데, as 연산자는 선언한 이후 시점부터 해당 클래스에 전역으로 캐스팅된다. -> 한번 캐스팅되면 쭉 계속 그 객체/타입으로 사용가능하다는게 포인트
as? 연산자도 있다. as?는 어떤 값을 지정한 객체/타입으로 캐스팅해주고, 만약 캐스팅 해줄 수 없으면 null을 반환하는 연산자이다. 기본적으로 캐스팅 해줄 수 없으면 ClassCastException 예외를 발생시킨다. as? 연산자는 ClassCastException 예외를 발생시키지 않고 null을 반환해준다. (본 필자는 as? 연산자를 이해하기 위해서 본 글 아래에 Null 안전성(Null safety)부터 읽고 오길 추천한다.)
첫번째부터 보자. Double에서 Int으로 캐스팅을 해줄 수 없다. 그러므로 double1 as? Int이 코드는 null이 되고 결국엔 null ?: 0 상태가 되어 0이 반환하게 된다.
두번째는 모든 자료형을 대신하는 Any 타입으로 선언된 double3가 있다. 해당 변수는 Double로 캐스팅을 해줄 수 있으며 결국엔 21.0이 반환된다.
지금까지는 Any 타입으로 스마트 캐스팅을 해줬는데 이번에는 Number 타입으로 해보겠다.
Number 타입도 스마트 캐스팅이 가능한 특수한 자료형이다.
이 친구는 그냥 캐스팅하고 초기화까지 하네ㄷㄷ
Null 안전성(Null Safety)
- null : 값이 아직 없다. / 값이 없다. 등의 의미로 사용된다.
Kotlin은 NullPointerException(NPE)을 방지하기 위해서 null 안전성(Null Safety)이라는 것을 제공한다.
그럼 Jetbrains에서는 왜 Null Safety를 만들었냐! -> Java에서 흔히 발생하는 NullPointerException 문제를 해결하기 위함과 런타임시에 null의 가능성이 있기 때문이다.
Kotlin에서는 기본적으로 null를 저장하는 것은 허용되지 않는다.(notNullable) 하지만 해당 타입에 물음표(?)를 붙여 사용하면 null이 허용(nullable)되어 에러가 발생하지 않는다. 물음표(?)를 사용하면 '나는 값이 있을 수도 있고 없을 수도 있는 변수야'라는 의미가 된다.
Kotlin은 명시적으로 null 가능성을 다룰수 있도록 하고 있다.
이로 인해 우리는 예외들을 최소화하고 관리하기 쉬운 코드를 작성할 수 있다.
관련 연산자
관련 연산자로는 ?. / !!. / ?: 가 있는데 하나씩 살펴보자.
1. 안전한 호출 연산자(safe call)
?. : null이 될 수 있는 변수를 사용할 때, 안전하게 호출 할 수 있도록 한다. 변수에 null 값이 있으면 호출을 무시하고 null을 반환한다.
?. 연산자를 사용해줌으로써 null 값을 허용시켜준다.
위 코드는 ?. 연산자를 사용하지 않고 원래 방식대로 했을 때 코드이다. 확실히 ?. 연산자를 사용했을 때 코드의 간결성이 좋아보인다.
2. null이 아님을 확신하는 연산자(non-null assertion)
!!. : 변수에 null 값이 없다고 확신(null이 아님을 보증)할 때 사용한다. 하지만 개발자의 예상이 틀렸을 경우(null 값일 경우) NullPointerException(NPE)을 발생시킨다. Intellij가 친절하게 경고해준다. 그래도 잘 생각해서 사용하자.
nullable에 '홍길동'이라는 문자열이 할당되어 있다. 개발자가 null로 바꾸지 않는 이상 null 값이 될 수 없기 때문에 !!. 연산자를 사용해서 null이 아님을 확신해준다.
3. 엘비스 연산자(elvis)
?: : null이 될 수 있는 변수가 null 일 때 기본 값을 제공한다.
'nullable이 null이 아니면 해당 값의 길이를 반환해주고 null이면 0을 반환한다.' 라고 해석이 가능하다.
?: 연산자 뒤에는 null일 때의 기본 값이고, 앞에는 null이 될 수 있는 변수이다. (null이 될 수 있는 변수 ?: null일 경우에 기본값)
관련 함수
let 함수
let 함수는 주로 ?. / !!.연산자와 함께 쓰이며 원하는 식의 결과가 null인지 검사한 다음 '그 값을 전달받아'(it) 처리한다.
값이 null이 아니면 let 함수를 수행하고 null이면 수행하지 않고 빠져나간다.
it은 전달 받은 해당 변수/값이며 null이 아니라는 것을 보장한다. 왜냐하면 이미 확인했으니까. ?. / !!. 연산자로
잘못된 부분이나 부족한 부분이 있을 수 있습니다. 댓글로 남겨주시면 감사하겠습니다.
'Kotlin' 카테고리의 다른 글
[Kotlin] 제어문(2) - 반복문(while, for) (1) | 2024.11.15 |
---|---|
[Kotlin] 배열(Array) (0) | 2024.11.14 |
[Kotlin] 제어문(1) - 조건문(when, if-else) (0) | 2024.11.14 |
[Kotlin] 자료형과 연산자 (0) | 2024.11.12 |
[Kotlin] 변수와 상수 (7) | 2024.11.11 |