코틀린에서는 더 안전하고 편하게 null을 처리하고 형을 다룰 수 있습니다. 제어흐름도 더 깔끔합니다. 이번 편에서는 형과 제어 흐름에 대해 알아봅시다. 아쉽게도 이번이 이 시리즈의 마지막입니다.
null 처리와 캐스팅
찰스 앤터니 리처드 호어는 null
을 컴퓨터 프로그래밍에 도입한 것에 대해 10억 달러 실수
라고 부르며 책임감을 자기고 있습니다.
I call it my billion-dollar mistake. It was the invention of the null reference in 1965. At that time, I was designing the first comprehensive type system for references in an object oriented language (ALGOL W). My goal was to ensure that all use of references should be absolutely safe, with checking performed automatically by the compiler. But I couldn’t resist the temptation to put in a null reference, simply because it was so easy to implement. This has led to innumerable errors, vulnerabilities, and system crashes, which have probably caused a billion dollars of pain and damage in the last forty years.
C.A.R. 호어의 자기 비판 후 많은 사람들은 null
을 좀 더 나은 방법으로 해결하려 하였습니다. 코틀린도 예외는 아닙니다. 이제 코틀린이 어떻게 이 문제를 다루는지 살펴봅시다. 코틀린이 로컬에 설치되어 있다면 아래와 같이 입력해봅시다.
코틀린과 null
$ kotlin
>>> var hello : String = "Hello Realm"
>>> hello = null
String
타입으로 정의된 변수에 null
값을 대입하면 에러가 발생합니다.
error: null can not be a value of a non-null type kotlin.String
hello = null
코틀린에서 특정 타입으로 정의를 하면 기본으로 null 값을 허용하지 않는 변수가 정의되게 됩니다.
만약 null
을 명시적으로 허용하고 싶다면 아래와 같이 코드를 작성해야 합니다.
>>> var hello2: String? = "Hello Realm2"
>>> hello2 = null
이제 hello
와 hello2
에 대해 length
를 호출해봅시다.
>>> hello.length
11
hello.length
는 문제가 전혀 없습니다만 hello2.length
는 에러가 발생합니다.
>>> hello2.length
error: only safe (?.) or non-null asserted (!!.) calls are allowed on a nullable receiver of type kotlin.String?
hello2.length
hello2가 null이 될 수 있기 때문에 length를 호출할 수 없다는 것이지요. 코틀린은 자바에 비해 null
처리에 대해 까다롭습니다.
이를 해결할 간단한 방법은 null
값을 확인하는 방법입니다.
val l = if (hello2 != null) (hello2 as String).length else -1
코틀린에서의 캐스팅은 변수 as 타입
의 형태로 이루어집니다. 캐스팅이 실패할 때면 ClassCastException
을 반환하는데 이를 조용히 넘기기 위해서 as?
를 사용할 수 있습니다.
안전 호출과 엘비스 오퍼레이터
안전 호출(Safe call)와 엘비스 오퍼레이터(Elvis operator)를 이용하면 더 간결하게 할 수 있습니다.
hello2 ?.length ?: -1
안전 호출(?.
)은 앞의 타입이 null
이 아닌 경우만 호출을 해서 값을 리턴하고 그렇지 않은 경우엔 null
을 호출합니다. 엘비스 오퍼레이터(?:
)는 앞의 값이 참이면 참인 값을 그대로 반환하고 아닌 경우에는 지정한 값을 반환합니다.
만약 Null pointer exception을 굳이 보고 싶다면 !!
연산자를 사용할 수 있습니다.
강제 호출
hello2!!.length()
이 방법을 굳이 사용할 일은 많지 않으실 겁니다.
자동 형변환
아래의 예제를 입력해봅시다.
fun getStringLength(something: Any): Int? {
if (something is String) {
return something.length
}
return null
}
something
을 Any
로 받았기 때문에 어떤 타입이든 받게 됩니다. 그런데 여기에서 보면 String
으로의 변환만 있고 something
의 타입은 더 이상 신경쓰지 않고 length
를 호출한 것을 볼 수 있습니다. 자동 형변환 은if
문 밖에서도 가능합니다.
fun getStringLength(something: Any): Int? {
if (something !is String) {
return null;
}
return something.length
}
제어 흐름
코틀린은 자바와 비슷하게 제어 흐름을 가지고 있습니다. 유사한 부분(for
, while
)은 다루지 않고 차이가 있는 부분에 대해서 설명하겠습니다.
if
if
는 표현식으로 사용될 수 있습니다. 구문으로만 사용가능한 자바와의 차이점입니다.
val max = if (a > b) {
print("Choose a")
a
}
else {
print("Choose b")
b
}
when
when
은 기존의 C 언어 형태의 switch
구문에 비해서 훨씬 유연하고 다양하게 사용할 수 있습니다.
when (x) {
1 -> print("x == 1")
2 -> print("x == 2")
else -> {
print("x is neither 1 nor 2")
}
}
1
, 2
가 아닐때 else
부분이 수행됩니다.
when (x) {
parseInt(s) -> print("s encodes x")
else -> print("s does not encode x")
}
parseInt
가 수행이 가능할 때와 아닐 경우로 케이스를 나눌 수 있습니다.
when (x) {
in 1..10 -> print("x is in the range")
in validNumbers -> print("x is valid")
!in 10..20 -> print("x is outside the range")
else -> print("none of the above")
}
in
과 !
도 사용할 수 있습니다.
val hasPrefix = when(x) {
is String -> x.startsWith("prefix")
else -> false
}
타입에 따라 수행할 수 있습니다.
when {
x.isOdd() -> print("x is odd")
x.isEven() -> print("x is even")
else -> print("x is funny")
}
if
-else
구문을 완전히 대체할 수 있습니다.
앞으로
이제 코틀린을 훑어 보았습니다. 더 자세한 내용을 알고 싶다면 온라인 튜토리얼이나 코틀린 사이트의 레퍼런스를 참고하면서 프로그래밍에 코틀린을 포함시켜 보세요. 특히 안드로이드와 코틀린의 조합은 굉장히 안정적이고 편리하니 자바로 개발하던 안드로이드 개발자라면 코틀린을 개발에 사용해 보세요.
컨텐츠에 대하여
이 컨텐츠는 저자의 허가 하에 이곳에서 공유합니다.