+ 항공대학교 김철기 교수님의 객체 지향 프로그래밍 과목 내용를 정리한 글입니다.
널 (NULL)
null은 아무 것도 참조하지 않는 참조 값의 특별한 상태이다.
null에 대해서 멤버 접근을 시도하면 NullPointerException이 발생한다.
(컴파일 시간에 파악이 되지 않아 최악의 에러 중 하나로 간주)
Kotlin에서 일반 참조형에는 null을 담을 수 없다. (에러 발생 => NullPointer Exception 예방)
// 문자로 이루어진 문자열인지 확인하는 함수
fun isLetterString(s:String): Boolean {
if (s.isEmpty()) return false // 빈 문자열이라면 false
for (ch in s) { // 문자가 아니라면
if (!ch.isLetter()) return false // 문자가 아니라면 false
}
return true
}
fun main() {
println(isLetterString("abc"))
println(isLetterString(null)) // 컴파일 에러 발생
}
널이 될 수 있는 타입 (nullable)
참조자의 타입 뒤에 ?를 붙인다.
// s가 "false"나 "true"라면 true를 반환하는 함수
fun isBooleanString(s:String?) = s == "false" || s == "true"
fun main() {
println(isBooleanString(null)) // ok
val s:String? = "abc" // ok
val ss:String = s // Error: type mismatch
}
널이 될 수 있는 타입에 대한 멤버 접근
널이 될 수 있는 타입은 기본 타입의 멤버 접근 등의 연산을 바로 수행하려 할 경우 컴파일 에러가 발생한다.
fun isLetterString(s:String?): Boolean {
if (s.isEmpty()) return false // Error
for (ch in s) { // Error
if (!ch.isLetter()) return false
}
return true
}
널 가능성 제거를 통한 스마트 캐스트
프로그램 흐름에서 null인 경우가 논리적으로 배제되면 컴파일러는 이를 인지하고 널 가능성을 제거하고 컴파일한다.
fun isLetterString(s:String?): Boolean {
if (s == null) return false
if (s.isEmpty()) return false // Error
for (ch in s) { // Error
if (!ch.isLetter()) return false
}
return true
}
조건문 내에서의 스마트 캐스트
fun describeNumber(n: Int?)
= when {
// range를 사용할 경우는 null인 경우를 처리하지 않아도 정상작동한다.
n == null -> "null" // null인 경우 처리
n >= 0 && n <= 10 -> "Small"
n > 10 && n <= 100 -> "Large"
else -> "Out of range"
}
fun isSingleChar(s: String?)
= s != null && s.length == 1
// && 연산은 앞 조건에서 false라면 뒤 조건은 보지 않는다.
// || 연산은 앞 조건에서 true라면 뒤 조건은 보지 않는다.
// 따라서 null을 인자로 받아도 오류가 발생하지 않는다.
fun main() {
println(describeNumber(null))
println(isSingleChar(null))
}
객체의 가변 프로퍼티와 스마트 캐스트
객체의 가변 프로퍼티는 스마트 캐스트가 불가능하다.
=> 프로그램 다른 어떤 곳에서 갑자기 값을 바꿀 수 있기 때문이다. (일말의 가능성 존재)
class MyString {
var str: String? // 가변 프로퍼티
fun isStrEmpty(): Boolean {
if (str == null) return true
if (str.isEmpty()) return true // Error 발생
else return false
}
}
fun main() {
val s = MyString()
s.str = "Hello"
println(s.isStrEmpty())
}
local 변수로 저장하면 스마트 캐스트가 가능하다.
class MyString {
var str: String? // 가변 프로퍼티
fun isStrEmpty(): Boolean {
val s = str // local 변수로 저장
if (s == null) return true
if (s.isEmpty()) return true
else return false
}
}
fun main() {
val s = MyString()
s.str = "Hello"
println(s.isStrEmpty())
}
널 아님 단언 연산자 (!!)
널이 될 수 있는 타입에 대하여 프로그래머가 널이 아니라고 확언해주는 연산자
- 그럼에도 불구하고 널이었을 경우 kotlinNullPointerException이 발생한다.
- 널 아님 단언 연산자는 반드시 필요한 경우를 제외하고는 사용하지 말아야 한다.
fun readInt() = readLine()!!.toInt()
// readLine()은 null을 반환할 수 있다.
// 피할 수 있으면 피하는 것이 좋다.
// 반환형은 Int. 널이 될 수 없다.
따라서 아래 코드를 선호해야한다.
fun readInt() = readLine()?.toInt()
// 널이 아니라면, 널이 아닌 값에 대해 뒤 연산을 실행한다. (반환 타입: Int?)
// 널이라면, 뒤 연산을 하지 않고 널을 반환한다.
엘비스 연산자
연산자 왼쪽의 값이 null인 경우 연산자 오른쪽 값으로 치환한다.
fun readInt() = readLine()?.toInt() ?: 0
// readLine()이 null인 경우 readLine?.toInt() 값이 null이 된다.
// 이 때, null을 ?: 0이 0으로 치환한다.
// 결과적으로 readInt()는 null을 반환할 가능성이 없어지므로 반환형이 Int가 된다.
fun sayHello(name: String?) {
println("Hello, ${name ?: "Unknown"}") // null이라면 "Unknown 반환
}
fun main() {
sayHello("Charlie")
sayHello(null)
}
엘비스 연산자 우측의 return / throw
엘비스 연산자도 일종의 조건문이므로 연산자 우측에 값 대신 return이나 throw를 둘 수 있다.
fun readInt() = readLine()?.toInt() ?: 0
// readLine()이 null인 경우 readLine?.toInt() 값이 null이 된다.
// 이 때, null을 ?: 0이 0으로 치환한다.
// 결과적으로 readInt()는 null을 반환할 가능성이 없어지므로 반환형이 Int가 된다.
class Name(val firstName: String, val familyName: String?)
class Person(val name: Name?) {
fun describe(): String {
val currentName = name ?: return "Unknown" // null일 경우 decribe함수는 "Unknown" 반환
return "${currentName.firstName} ${currentName.familyName}"
}
}
fun main() {
println(Person(Name("John", "Doe")).describe()) // John Doe
// John Doe라는 이름을 갖는 Name 객체를 Person 생성자의 인자로 전달
println(Person(null).describe()) // Unknown
}
'Study > Kotlin Study' 카테고리의 다른 글
| [Kotlin] 객체 (Object) (0) | 2023.09.17 |
|---|---|
| [Kotlin] 단순한 변수 이상인 프로퍼티 (0) | 2023.09.17 |
| [Kotlin] 함수 (4) | 2023.09.03 |
| [Kotlin] 클래스 정의하기 (1) | 2023.08.28 |
| [Kotlin] 예외 처리 (0) | 2023.08.25 |