[1] Class : null 객체로 선언하기
1. class 만들기
먼저 코틀린에서 간단한 class를 선언한다.
class School {
var name: String = ""
var grade: Int? = null
constructor(name: String) {
this.name = name
}
}
생성자는 일단 name 필드만 필요로 하는 것으로 만들어 두었다.
grade 필드는 null safe 필드로 선언하여 Int타입 뒤에 ? 를 붙여서 선언하였다.
참고로 kotlin 에서는 class를 선언할때 모든 필드의 초기값을 세팅해 주어야 한다.
2. School 인스턴스 만들기
1) null safe 객체가 아닌데 null 로 초기화
// X 컴파일 오류 : null safe 하지 않은 타입인데 null로 초기화 할 수 없다
var school2: School = null
// X 컴파일 오류 : constructor 에 선언된 필수값을 입력해야 한다.
var school2: School = School()
// O 인스턴스 생성 성공
var school2: School = School("유치원")
null-safe 하게 선언하지 않았기 때문에 인스턴스의 초기값으로 null을 세팅할 수 없다.
또한 School 클래스의 constructor 로 name을 필수로 입력받도록 했기 때문에 인스턴스 초기화 시 해당 값을 필수로 입력해 주어야 한다.
위 예제에서는 컴파일 오류가 발생하기 때문에 쉽게 에러를 찾을 수 있다.
2) null safe 객체로 만들기
> null 로 초기화 후 인스턴스의 필드 가져오기 시도 -> 컴파일 오류 발생
// null safe 객체로 표현한 school1
var school1: School? = null
// 컴파일 에러 발생 : null 객체에서 가져올 수 없다
var school1nameNo = school1.name
인스턴스가 null 이기 때문에 null.{필드} 는 Java와 마찬가지로 NullPointExceptioin 이 발생한다. Java와 다른점은 NullPointException이라고 뜨지 않고
e: file://~/TryCatch.kt:20:32 Only safe (?.) or non-null asserted (!!.) calls are allowed on a nullable receiver of type School?
에러메세지가 표기되는데 읽어보면 null 관련 메세지임을 알 수 있다. 마찬가지로 컴파일 오류로 쉽게 에러를 확인할 수 있다.
> null로 초기화 후 실체 생성
// null safe 객체로 표현한 school1
var school1: School? = null
println("--------------- school ------------------")
school1 = School("학교") // 생성자로 실체 인스턴스 생성
var school1name = school1.name // 정상 실행
println(school1name)
var school1Grade = school1.grade // 정상 실행 : null 로 나온다
println(school1Grade)
>> "학교"
>> null
name을 필수값으로 받는 생성자를 통해 shcool1을 선언하고, name필드와 null-safe한 grade 필드를 출력하면 에러 발생없이 그대로 출력된다. 이때 null 로 초기화 되어 값이 선언되지 않은 grade는 그대로 null로 출력된다.
3) 다수의 constructor + null-safe 필드
grade 값도 입력으로 받는 또하나의 constructor를 생성한다.
class School {
var name: String = ""
var grade: Int? = null
constructor(name: String) {
this.name = name
}
constructor(name: String, grade: Int?) {
this.name = name
this.grade = grade
}
}
이때 grade 필드는 null-safe 필드이다!
이후 해당 constructor를 통해 인스턴스를 생성하면 다음과 같다. 정확한 확인을 위해 name 필드만을 받는 constructor는 삭제했다.
var school3: School = null // 컴파일 오류 : null safe 하지 않은 타입인데 null로 초기화 할 수 없다
var school3: School = School() // 컴파일 오류 : constructor 에 선언된 필수값을 입력해야 한다.
var school3: School = School("유치원") // 컴파일 오류 : constructor에 선언된 모든 필드를 입력해야 한다.
var school3: School = School("대학교", null) // 성공
var school4: School = School("대학원", 1) // 성공
null-safe한 필드여도 constructor에 선언되어 있으면 인스턴스 생성시 필수로 입력해야 한다. 단, null로 입력이 가능할 뿐이다.
[1] Var : null safe 변수
1. null safe 변수
변수에서도 null-safe 변수를 생성할 수 있다. 위 class 예제를 이해하면 변수도 똑같은 메커니즘으로 동작하는것을 이해할 수 있다.
1) null-safe 변수 선언 후 값을 대입하여 확인하기
var name: String? = null // 된다. null을 대입할수 있고, 대이하려면 타입 뒤에 ? 를 붙인다.
name = "jello" // null로 대입된 변수는 이후 다른 값으로 변경될 수 잇다.
println(name)
println(name[0])
>> jello
>> j
null-safe 변수의 값을 null로 초기화 한 후 값을 대입하여 사용하면 된다.
2) null-safe 하지않은 타입에 null로 초기화시 컴파일 오류 발생
var nameNull: String = null
다음과 같은 컴파일 오류가 발생한다.
Null can not be a value of a non-null type String
3) null-safe 변수값 세팅하지 않고 문자열 더하기
var name0: String? = null
var aa = name0 + "1"
println(aa)
>> null1
println(name0[0]) // complie 오류로 잡힌다.
null 상태인 변수값에 "1" string값을 더해 print 하면 컴파일 오류, 런타임 오류 없이 "null1" 로 출력된다.
단, null 상태인 String 타입의 변수를 위에 유효한 값을 대입했던것과 같이 index로 찾으려 하면 컴파일 오류가 발생한다.
Only safe (?.) or non-null asserted (!!.) calls are allowed on a nullable receiver of type String?
에러메세지는 위 class 예제에서 null로 초기화된 인스턴스의 필드에 접근하려 할때 발생했던 에러메세지와 동일하다.
2. non-nullable 변수에 null-safe 변수값 대입
캐스팅만 해주면 변수간 대입이 가능하다. 서로 다른 타입도 캐스팅으로 가능하지만 non-nullabler과 nullable 사이에서도 가능하다. 이때 캐스팅 하는 방법은 여러가지가 있다.
1) null 체크 후 캐스팅
null-safe한 변수가 현재 기준으로 null 상태인지 확인하고, null 이 아닐때에만 non-nullable한 동일타입 변수에 대입한다.
var name1: String? = null
var name2: String = ""
// name 이 현재 null 인지 체크
if (name != null) {
name2 = name
}
단, 현재 kotlin.spring 설정으로 smart casting이 이뤄지고 있다. null 체크를 자동으로 하여 변환해주고 있는 듯 하다.
name2 = name
// 원래는 안되지만 kotlin.Spring 에서 smart casting 이 되어 자동으로 null 체크가 이뤄지는 듯
2) !!를 붙여 ? 를 강제로 떼어내기
단, 이 방법은 개발자가 임의로 null 이 아니라고 한것이기 때문에 컴파일 오류가 아닌 런타임에러가 난다.
name2 = name!!
3) Safe call : ?. 과 let 으로 조건확인하여 대입하기
`?.` 은 null 여부를 체크하고 null 이 아니라면 그 뒤 명령어를 실행한다.
이런식의 null check 는 safe call 을 위한 방법으로 코틀린 공식문서에서도 소개되고 있다.
name?.let{
name2=name
}
확인하여 name의 값이 null 이 아니면 name2에 값을 대입하도록 한다.
'DEV-ing log > Java & Kotlin' 카테고리의 다른 글
[Kotlin] 리팩토링 하며 알아보는 코틀린 문법 : for loop -> elbis -> groupBy -> JPQL + spring data jpa -> Querydsl (0) | 2024.05.01 |
---|---|
[IntelliJ & Kotlin] 빌드 시 Downloading kotlinc-dist? 무한 로딩 오류 (0) | 2024.04.30 |
[Java] 기본 문법 이해하기 (0) | 2024.04.26 |