본문 바로가기

Kotlin

[Kotlin] 5. Nullable 타입, Safe Call, 엘비스 연산자, Safe Cast

# Null이 될 수 있는 타입

  1. 코틀린에는 널이 될 수 있는 타입이 따로 존재하며 명시적으로 타입 뒤에 '?'를 붙여 사용한다 ex)String?
  2. 모든 타입은 기본적으로 Non- Null Type 이라는 의미
  3. Nullable Type일 경우 변수.메소드()처럼 사용할 수 없다
     
  4. Non-Null Type에 null도, nullable 타입도 대입할 수 없으며,  함수의 파라미터에도 마찬가지 
  5. Nullable Type을 일단 널 체크 하고 나면, Non-Null Type처럼 사용할 수 있다
  6.  이렇게 컴파일 시점 NullPointException이 발생할 가능성을 체크해서 Null Safety를 보장할 수 있다
  7.  모든 검사는 컴파일 시점에 수행되므로, Nullable/Non-Null 타입 처리 관련해서 실행시점에 추가적인 부가 비용은 없다

 

# Safe Call Operator ?.

  • null 체크와 메소드 호출을 한번에 수행한다
  • 호출하려는 값이 null이 아니면 메소드가 호출 된다
  • 호출하려는 값이 null이면 메소드 호출은 무시되고 결과값은 null 이 된다 
  • 객체 안에 객체가 여럿 있다면 한 식 안에서 ?. 를 이용해 사용하기가 편한 경우가 있다
    class ClassType(val classNm: String?)
    class Subject(val className: String, val classType: ClassType?)
    class Student(val name: String, val subject: Subject?)
    
    //1)기존 방식
    fun Student.getClassType(): String? {
        if (this.subject != null) {
            if (this.subject.classType != null) {
                return this.subject.classType.classNm
            }
        }
        return ""
    }
    
    //2)Safe Call 사용 방식
    fun Student.getClassType2(): String? = this.subject?.classType?.classNm​

 

# 엘비스 연산자 ?:

  • null 대신 사용할 디폴트 값을 지정할 때 편리하게 사용할 수 있는 연산자 이다
  • 위의 Safe Call Operator 예제에서 Student.getClassType2( )의 리턴값이 Nullable이었는데,  이 때 null을 대신할 기본값을 엘비스 연산자를 이용해 아래와 같이 사용할 수 있다(리턴값을 Non-Null로 설정한 것을 볼 수 있다)
    fun Student.getClassType2(): String = this.subject?.classType?.classNm ?: "No classNm"​
  • 코틀린에서는 return이나 throw도 '식'이라서 엘비스 연산자의 우항에 넣을 수가 있다. 즉, 좌항이 null일 경우 바로 어떤값을 return 하고나 예외를 throw 할 수 있다 
  • //1. 우항에 return 처리
    fun Student.getClassType(): String {
        this.subject ?: return "No subject"
        this.subject.classType ?: return "No classType"
        return this.subject.classType.classNm ?: "No classNm"
    }
    
    //2. 우항에 exception throw 처리
    fun Student.getClassType3(): String =this.subject?.classType?.classNm ?: throw IllegalStateException("No classNm")

 

# 안전한 캐스트  as?

  • 코틀린에서 캐스트 연산은 as로 하는데, 캐스팅 불가 타입일 경우 ClassCastException이 발생한다
  • 그럼 as 연산을 할 때마다 미리 is를 통해 변환 가능한지 검사해 봐야 하느냐? -> 그러지 말고 as? 를 사용하면 캐스팅 불가 타입일 경우 null을 반환한다
  • 불가 타입일 경우 null이 반환 되므로, 뒤에 엘비스 연산자와 함께 유용하게 쓰인다

아래 예제에서 어떤 구문이 출력 될지 생각해 보자

class Subject(val className: String, val classType: ClassType?)
open class Student(val name: String, val subject: Subject?)
class HighSchoolStudent(val grade: Int, name: String, subject: Subject?) :
    Student(name, subject)

fun saveCast(highSchoolStudent: HighSchoolStudent, subject: Subject){
    highSchoolStudent as? Student ?: println("highSchoolStudent is Not Student") //1번
    subject as? Student  ?: println("subject is Not Student") //2번
}

1번은 캐스팅 될 것이므로 print 되지 않고,  2번 구문이 print 될 것이다


잘못된 내용이나 궁금한 내용 있으시면 댓글 달아주세요

좋은 하루 되세요!

 

출처 : Kotlin In Action - 에이콘 출판사

(위 도서를 학습하고 개인 학습용으로 정리한 내용입니다)