Language/Kotlin

Kotlin 자료형 검사하고 변환하기(?. !! ?:)

728x90
반응형

1. null 허용 변수 검사하기

코틀린은 변수를 사용할 때 반드시 값이 할당되어 있어야 한다는 원칙이 있다.

단, ? 기호를 사용하면 null 허용 변수를 만들 수 있다. 

? (널 허용 변수) 를 사용하기 위해서는 null을 검사하고 처리하는 방법을 고려해야 한다. 

null 변수를 읽으면(참조하면) NPE 에러가 발생하기 때문이다. 

 

?.  (세이프콜)
변수를 검사하고 null이 아니면 접근하여 값을 읽고(왼쪽식을 그대로 실행),
null이면 해당변수를 참조(NPE발생)하지 않고 null을 안전하게 호출

!!   (non-null 단정기호)
변수에 할당된 값이 무조건 null이 아님을 단정하고 컴파일러가 null검사 없이 무시함
컴파일은 잘 수행되지만 나중에 실행시 NPE 발생

?:   (엘비스 연산자)
변수를 검사하고 null이 아니면 접근하여 값을 읽고(왼쪽식을 그대로 실행),
null이면 오른쪽식을 실행

 

 

NPE(Null Pointer Exception)
Java 언어로 소프트웨어를 개발하다 보면 NullPointerException 이라는 오류를 자주 만나게 된다.이는 객체의 주소 값이 담겨져 있지 않는 (null 값이 들어있는) 참조 변수를 통해 객체 접근을 시도하면 발생되는 오류이다.

Null safe
Kotlin 은 개발자가 null이 담겨 있는 참조변수를 통해 객체 접근을 시도할 때 오류가 발생되는 것을 방지하고자 다양한 방법을 제공하고 있다.이를 통해 null 값에 대한 안정성을 확보(null safe)할 수 있다.

 

 

?.   세이프콜 연산자 

  • 참조변수를 통해 메서드를 호출하거나 멤버 변수를 사용할 때
    • 만약, 참조변수에 객체의 주소값이 들어 있다면,  객체에 접근해서 메서드나 변수를 사용하고,,
    • 만약, 참조변수에 null이 들어 있다면,  오류가 발생하지 않고(컴파일시 해당 참조변수 접근을 안함)  null을 반환한다. 
fun testFun3(str1: String?){
    println("str1 : $str1")

    println("str1 length : ${str1?.length}")
}
fun main() {
    testFun3("문자열")		// 결과: "문자열"
    testFun3(null)		// 결과: null
}

 

!!     non-null 단정기호

  • !! 연산자는 null을 허용하는 변수에 담긴 객체의 주소 값을 null을 허용하지 않는 형태의 값으로 변환하는 연산자이다.
  • null을 허용하는 변수에 담긴 값을 null을 허용하지 않는 형태의 변수에 담을 경우 사용한다.
  • 값이 존재하지 않을 수 있지만 특정 구역에서는 값이 절대 null일 수 없다고 확신할 경우 굳이 값이 null인지 체크하는 과정을 거치지 않아도 되기에 non-null 단정기호를 사용함
  • 그러나 혹시라도 null 값이 들어 있을 경우 변환 과정에서 오류가 발생하기 때문에 이 연산자의 사용은 권장하지 않는다.
fun testFun1(str1: String?){

    val str2: String = str1!!
    println("str2: $str2")
}
fun main() {

    testFun1("문자열")	// 결과 : "문자열"
    testFun1(null)	// 결과 : 오류발생!!!
}

str1  은 null을 허용하는 변수인데

!! 연산자를 통해 null을 허용하지 않는 변수로 강제로 변환해서

null을 허용하지 않은 변수인 str2에 대입이 가능해졌다. 

 

하지만, 권장하지 않는 경우는 위의 예처럼 널값이 들어가면 오류가 발생하기 때문이다.  (null의 안정성을 보장하지 않음)

 

?:    연산자

  • ?: 연산자는 참조변수에 null 이 들어있으면 지정된 기본값(오른쪽)을 반환한다.
fun testFun2(str1: String?){

    val str2: String = str1 ?: "기본문자열"
    println("str2: $str2")
}

 

fun main() {
    testFun2("문자열")		// 결과 : "문자열 "
    testFun2(null)		// 결과 : "기본 문자열 "
}

 

예제

 

  • 세이프콜(?.)과 엘비스연산자(?:)를 함께 사용하여 null 허용변수 사용 예제
fun exFun1(str1: String?){

    val str2: String = str1?.lenth ?: -1
    println("str2: $str2")
}
fun main() {
    exFun1("문자열")		// 결과 : 3
    exFun1(null)		// 결과 : -1
}

 

  • 함수에서 null 리턴 예제
fun exFun2(node: Node): String?{
	val parent = node.getParent() ?: return null
    
    // ...
}

 

  • 함수에서 Throw Exception 발생하도록 구현한 예제
fun testFun3(noed: Node): String?{

   val name = node.getName() ?: throw IllegalArgumentException("name expected")
}

 


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

코틀린의 자료형은 모두 참조형으로 선언한다.

컴파일을 거처 최적화될 때 Int, Long, Short와 같은 참조형 자료형은 모두 기본 자료형으로 변환된다. 

 

형변환

  • 변수에 담긴 값이나 객체를 다른 형태로 변환하는 것을 의미한다.
  • Kotlin은 모든 값을 객체로 관리하기 때문에 Kotlin에서의 형변환은 다른 클래스 타입의 객체로 변환하는 것을 의미한다.
  1. 자식 클래스 타입으로의 변환
  2. 부모 클래스 타입으로의 변환
  3. 다른 자료형 타입으로의 변환
  4. null 허용과 null 불허용 간의 변환

 

 

스마트 캐스팅

  • 특정 조건을 만족하면 자동으로 형변환이 발생하는 개념이다.
  • 스마트 캐스팅 기능 덕분에 형변환에 대해 개발자가 크게 신경을 쓰지 않아도 된다.
  • 형 변환은 객체의 클래스 타입이 아닌 객체의 주소 값을 가지고 있는 참조 변수의 타입이 변경되는 것이다.

객체 타입 변환

  • 객체의 타입 변환은 상속관계나 구현한 인터페이스 타입에 해당한다.
  • 부모 클래스 타입으로의 형 변환
  • 자식 클래스 타입으로의 형 변환
  • 구현한 인터페이스 타입으로의 형 변환
  • 인터페이스를 구현한 클래스 타입으로의 형 변환

as 연산자

  • 객체를 지정된 클래스 타입으로 변환하는 연산자이다.
  • 참조변수 as 클래스타입
  • 만약 객체가 지정된 클래스타입과 관계가 없을 경우 오류가 발생한다.
  • 형 변환이 발생한 참조 변수는 변환된 타입을 유지한다.

is 연산자

  • 형 변환이 가능하면 변환을 하고 true를 반환한다.
  • if 문으로 구성하여 사용하며 if 문 내에서만 변환된 타입을 사용하고 if 문을 나가게 되면 변환되기 전의 타입으로 다시 변경된다.

Any 타입

  • Kotlin은 모든 클래스가 직접 혹은 간접적으로 Any 클래스를 상속받는다.
  • 따라서 모든 객체의 주소 값은 Any 타입 참조 변수에 담을 수 있다.
  • Any 타입과 is 연산자를 활용하여 다양한 타입의 객체에 대응할 수 있는 코드를 만들 수 있다.

기본 타입의 형 변환

  • Kotlin 에서는 기본 타입을 관리하는 객체의 타입을 변경하는 메서드를 제공한다.
  • 참조 변수의 타입이 변경되는 것이 아닌 새로운 객체가 생성되어 반환된다.
  • toByte(), toShort(), toInt(), toLong(), toFloat(), toDouble(), toChar()

 

 

null 안전성을 위한 형변환

  • null 값이 담긴 객체에 대해 보다 안전한 형 변환 방법을 제공하고 있다.
  • null 을 허용하는 변수가 null 값이 들어있지 않다는 것을 보장해 주면 null 을 허용하지 않는 타입으로 스마트 캐스팅이 발생한다.

if 문 사용

  • if 문을 통해 null 허용 변수에 null 값이 아닌 객체의 주소 값이 들어 있음을 검사해 주면 if 문 내부에서는 null을 허용하지 않는 변수로 변환되어 사용할 수 있다.
  • if 문이 종료되면 다시 null 허용 변수가 된다.
  • 이 때 비교 연산자 보다는 is 연산자를 추천한다.
  • 비교 연산자로 검사할 경우 타입이 Any 인 경우 컴파일 오류가 발생한다.

 

728x90
반응형