Nullable
์ฝํ๋ฆฐ์ nullableํ ํ์ ์ ์ง์ ํด์ ์ปดํ์ผ ๋ NPE๋ฅผ ์๋ฐฉํ ์ ์๋ค. ๋ฐํ์์์ ๋ฐ์ํ๋ NPE๋ฅผ ์ปดํ์ผ ์์ ์ผ๋ก ๊ฒ์ฌ์์ ์ ์ฎ๊ฒจ์ ์ฒ๋ฆฌํ๋ ๋ฐฉ์์ด๋ค. ํ์ ์ ?๋ฅผ ๋ถ์ฌ์ ์ฌ์ฉํ๋ค.
val x: String? = null
์๋ฐ์ ๊ฒฝ์ฐ null์ด ๋ ์์๋ ๊ฐ์ Optional ํ์ ๋ฑ ํน๋ณํ ๋ํผ ํ์ ์ผ๋ก ๊ฐ์ธ์ผํ๋๋ฐ, ์ฝํ๋ฆฐ์ ๊ทธ๋ฅ non-null์ด๋ nuallble์ด๋ ๊ฐ์ ํ์ ์ผ๋ก ํ๊ธฐ ๋๋ฌธ์ nullable ํ์ ์ ์คํํ ๋ ๋ถ๊ฐ๋น์ฉ์ด ๋ค์ง ์๋๋ค.
?. - safe call
์์ ๊ฐ์ฒด๊ฐ null์ด๋ฉด null์ ๋ฆฌํดํ๊ณ , null์ด ์๋๋ฉด ์๋ํ ๋ฉ์๋๋ฅผ ํธ์ถํ๋ค.
s?.toUpperCase()
if(s!=null) s.toUpperCase else null
val input = a?.b?.c
์ ๋ ์ค์ ๊ฐ์ ์ฝ๋๋ค. ๋ง์ง๋ง ์ค ์ฒ๋ผ ์ฐ์ํด์ ํธ์ถํ๋ ๊ฒ๋ ๊ฐ๋ฅํ๋ค. c๊น์ง ๊ฐ๊ธฐ์ ์ null์ด ๋ฐํ๋๋ฉด input์๋ null์ด ๋ค์ด๊ฐ๋ค.
?: - elvis, null coalescing
์๋น์ค ์ฐ์ฐ์๋ null์ ๊ฒฝ์ฐ ์ฒ๋ฆฌํ ์์ ์ข ๋ ๊ฐ๊ฒฐํ๊ฒ ํํํ๋๋ก ๋์์ค๋ค.
val address = person.company?.address ?: throw IllegalArgumentException("No address")
?: ์์ ์์ด null์ด๋ฉด ๋ค์ ์์ ์ฐ์ฐํ๋ค. ํจ์์ ์ ์ ์กฐ๊ฑด์ ๊ฒ์ฌํ๋ ๊ฒฝ์ฐ ์ ์ฉํ๋ค.
as? - safe cast
์บ์คํธ์ฐ์ฐ์์ธ as๋ฅผ null safeํ๊ฒ ์ฐ๋ ๋ฐฉ๋ฒ์ด๋ค. ๋์ ํ์ ์ผ๋ก ๋ณํํ ์ ์์ผ๋ฉด null์ ๋ฐํํ๋ ์ฐ์ฐ์๋ค.
!! - not-null assertion
null์ด ์๋์ ๋จ์ธํ๋ ํค์๋๋ก, !!๋ก ์ง์ ํ ๊ณณ์์๋ NPE๊ฐ ๋ฐ์ํ ์ํ์ด ์๋ค. null๊ฒ์ฌ๊ฐ ํ์์๋ ํ์คํ ๊ณณ์์ ์ฌ์ฉํ๋ฉด ๋๋๋ฐ, ์ฐ์ํด์ ์ฌ์ฉํ ๊ฒฝ์ฐ ์ด๋์์ ๋ฐ์ํ NPE์ธ์ง ๋ชจ๋ฅธ๋ค๋ ์ ์ด ๋ฌธ์ ๋ค.
person.company!!.address!!.country
ํด๋น ๋ผ์ธ์์ NPE๊ฐ ๋ฐ์ํ๊ฑด stack trace๊ฐ ์๋ ค์ฃผ์ง๋ง, ์ด๋ ํ๋กํผํฐ์์ NPE๊ฐ ๋ฐ์ํ๋์ง๋ ์๋ ค์ฃผ์ง ์๋๋ค.
let
letํจ์๋ ์์ ์ ์์ ๊ฐ์ฒด๋ฅผ ์ธ์๋ก ์ ๋ฌ๋ฐ์ ๋๋ค์๊ฒ ๋๊ธด๋ค.
์ด์ ์ฌ๊ธฐ์ ?.let{ } ๊ณผ .let์ ์ฐจ์ด๊ฐ ์๊ธด๋ค.
email?.let { sendEmailTo(it) }
email.let { sendEmailTo(it) }
let์ด safeํ๊ฒ ์๋๊ณ let์ safeํ๊ฒ ํธ์ถํ์๋ ๋๋ค์์๋ ํ์ ์ด ํ์คํ๊ฒ null์ด ์๋ ๊ฒ์ ์ ์ ์๋ค. safeํ๊ฒ let์ ํธ์ถํ๋ฉด ์์ ๊ฐ์ฒด๊ฐ null์ด ์๋๋ฉด ๋๋ค์ ์ธ์๋ฅผ ๋ฃ๋๋ค.
๋๋ฒ์งธ ์ค์ ์ฝ๋๋ email์ด String?๊ณผ ๊ฐ์ nullable ํ์ ์ด๋ฉด, ๋๋ค์ ์ธ์๋ก String?์ด ์ถ๋ก ๋๋ค๋ ๊ฒ์ ์ฃผ์ํ์.
lateinit var
ํ๋กํผํฐ๋ฅผ val๋ก ์ ์ธํ๋ฉด ์ ์ธ๊ณผ ๋์์ ์ด๊ธฐํ ํด์ผ๋๊ณ final๋ก ์ปดํ์ผ ๋๋ฉฐ, ์์ฑ์ ์์์ ๋ฐ๋์ ์ด๊ธฐํ ํด์ผํ์ง๋ง, ๋์ค์ ์ด๊ธฐํํ๋ ํ๋กํผํฐ๋ var๋ก ์ ์ธํด์ ์ฌ์ฉํ๋ค.
private lateinit var myService: MyService
์ด๊ธฐํ ์ ์ ์ด ํ๋กํผํฐ์ ์ ๊ทผํ๋ฉด lateinit property has not been initialized ์์ธ๊ฐ ๋ฐ์ํ๋ค.
๋์ด ๋ ์ ์๋ ํ์ ํ์ฅ
ํ์ ์ ๋ํ ํ์ฅํจ์๋ฅผ ์ ์ํ๋ ๊ฑด๋ฐ, ์ด ํ์ฅํจ์๋ null์ด ์๋์ด์ผ ํธ์ถํ ์ ์๋ ํ์ฅํจ์/ํ๋กํผํฐ๊ฐ ์๋๋ผ, null์ด ๋ ์ ์๋ ํ์ ์ ๋ฐ์์ null์ ๋ช ์์ ์ผ๋ก ์ฒ๋ฆฌํ๋ ๋ฐฉ๋ฒ์ด๋ค.
fun verifyUserInput(input: String?) {
if (input.isNullOrBlank()) {
println("TODO")
}
}
ํ์ ํ๋ผ๋ฏธํฐ์ nullable
์ด๊ฑด ์ ๋ค๋ฆญ์์ ๋ค์ ๋์ฌ ๋ถ๋ถ์ด๋ผ ๊ฐ๋จํ๊ฒ ํ๊ณ ๋์ด๊ฐ๋ค.
fun <T> printHashCode(t: T) {
println(t?.hashCode())
}
fun <T: Any> printHashCode(t: T) {
println(t.hashCode())
}
T๋ ํ์ ํ๋ผ๋ฏธํฐ๋ก, ๋ชจ๋ ํ์ ํ๋ผ๋ฏธํฐ๋ ๊ธฐ๋ณธ์ ์ผ๋ก null์ด ๋ ์์๋๋ฐ, ์ด T๋ฅผ ํ์ ์ด๋ฆ์ผ๋ก ์ฌ์ฉํ๋ฉด ์ด๋ฆ ๋์ ?๊ฐ ์์ด๋ nullableํ๋ค. ๋ฐ๋ผ์ ํ์ ์ํ์ ์ง์ ํด๋ฌ์ผ null์ด ๋ ์ ์๋ค.
๊ทธ๋ ๋ค๋ฉด ์๋ฐ์ ํธํ์?
์ฝํ๋ฆฐ์ ์๋ฐ์์ @Nullable, @NotNull ์ ๋ ธํ ์ด์ ์ ์ฝ์ด์ ์ฒ๋ฆฌํ๋๋ฐ, ์ด๊ฒ ์๋ถ๋ ๊ฒฝ์ฐ๋ ํ๋ซํผ ํ์ ์ด๋ผ๊ณ ๋ถ๋ฅธ๋ค. ํ๋ซํผ ํ์ ์ ์ฝํ๋ฆฐ์ด null๊ด๋ จ ์ ๋ณด๋ฅผ ์ ์ ์๋ ํ์ ์ ๋งํ๋๋ฐ, nullable๋ก ํด๋๋๊ณ ์๋์ด๋ ๋๋ ์ฑ ์์ ํ๋ก๊ทธ๋๋จธ๊ฐ ์ง๋ ํ์ ์ด๋ค.
fun yellAtSafe(person: Person) {
println((person.name ?: "Anyone").toUpperCase() + "!!!")
}
Person์ ์๋ฐ ํ์ ์ด๊ณ , kotlin์์ ์๋น์ค ์ฐ์ฐ์๋ก nullableํ ์ ์๋ ๋ถ๋ถ์ ์ฒ๋ฆฌํ๋ค. ํ๋ซํผ ํ์ ์ ๊ฒฝ์ฐ ?๊ฐ ์์ด๋ null ์ด ๋ค์ด๊ฐ ์ ์์์ ์ธ์งํด์ผํ๋ค. ํ๋ซํผ ํ์ ์ด ๋์ ๋ ์ด์ ๋ ๋ชจ๋ ๊ฐ์ null์ ๊ฒ์ฌํ๋ ๊ฒ์ ๋นํจ์จ์ ์ด๋ผ๊ณ ํ๋จํด์, null์ฌ๋ถ๋ฅผ ํ๋ก๊ทธ๋๋จธ๊ฐ ์ฒ๋ฆฌํ๋๋ก ์ค๊ณํ๋ค๊ณ ํ๋ค.
ERROR: Type mismatch: inferred type is String! but Int was expected
ํ๋ซํผ ํ์ ์์ ๋ฐ์ํ ์๋ฌ๋ ! ๊ฐ ๋ถ๋๋ค. nullable ์ ๋ณด๋ค ์๋ค๋ ๋ป์ด๋ค.
์์ ํ์
์๋ฐ์ ๋ฌ๋ฆฌ, ์ฝํ๋ฆฐ์ ์์ํ์ ๊ณผ ๋ํผํ์ ์ ๊ตฌ๋ถํ์ง ์๋๋ค. ๋ํผํ์ ์ ๊ฐ์ฒด์ ์ฃผ์๊ฐ์ด ๋ค์ด๊ฐ๋๋ฐ, ์๋ฐ ์ปฌ๋ ์ ์ด ๊ทธ ๋ํ์ ์ธ ์๋ค. ์ฝํ๋ฆฐ์ nullableํ์ง์์ ์์ํ์ ์ ๊ทธ๋๋ก ์๋ฐ์ ์์ํ์ ์ผ๋ก ์ทจ๊ธ๋์ด ์ปดํ์ผ๋์ง๋ง, nullable์ด ๋ถ์ ์ฝํ๋ฆฐ์ ํ์ ์ ์๋ฐ์์ ๋ํผํ์ ์ผ๋ก ์ปดํ์ผ๋๋ค.
๋ํ JVM์ ์ ๋ค๋ฆญ์ ๊ตฌํํ ๋ ์์ํ์ ์ ํ์ ์ธ์๋ก ํ์ฉํ์ง์๊ธฐ ๋๋ฌธ์ ์ ๋ค๋ฆญ ํด๋์ค๋ฅผ ๋ง๋ค๋๋ ์ฝํ๋ฆฐ ์ญ์ ๋ฐ์คํ์ ์ ์ฌ์ฉํด์ผํ๋ค.(listOf()์ ๊ฐ์)
์ฝํ๋ฆฐ์ ์ซ์ ๋ณํ์ด ์๋์ผ๋ก ๋์ง์๊ธฐ ๋๋ฌธ์ (์ฌ์ง์ด Int-> double๋ก ์ฎ๊ธฐ๋ ๊ฒ๋) ํญ์ ๋ณํํจ์๋ฅผ ์ด์ฉํด ์ฒ๋ฆฌํด์ผํ๋ค.
val x = 1
println(x.toLong() in listOf(1L, 2L, 3L))
int๋ฅผ long๊ณผ ๋น๊ตํ ์ ์์ ๊ฒ ๊ฐ์ง๋ง ๊ทธ๋ ๊ฒ ๋์ง์๋๋ค. ๋ณํํจ์๊ฐ ํ์์์ ๋๋ ์ซ์ ๋ฆฌํฐ๋ด์ ์ฌ์ฉํ ๊ฒฝ์ฐ๋ค.
์ต์์ ํ์ : Any, Any?
์ฝํ๋ฆฐ์์๋ Anyํ์ ์ด ๋ชจ๋ null์ด ์๋๋ ํ์ ์ ์กฐ์ํ์ ์ด๊ณ Any?๋ nullable์ ์กฐ์ํ์ ์ด๋ค. ์๋ฐ์ Object์ ๋์ํ๋๋ฐ, Objectํ์ ์ ์ฝํ๋ฆฐ์ผ๋ก ๊ฐ์ ธ์ค๋ฉด Object!๋ก ํ๋ซํผ ํ์ ์ผ๋ก ํด์๋๋ค.
๋ชจ๋ ์ฝํ๋ฆฐ ํด๋์ค์ ๋ค์ด์๋ toString, equals, hashCode ๋ฉ์๋๊ฐ Any์์ ๊ฐ์ ธ์จ ๊ฒ์ด์ง๋ง, Object์ ์๋ ๋ฉ์๋๋ฅผ Any๊ฐ ์ฌ์ฉํ๋ ค๋ฉด ํ์ ์บ์คํธ๊ฐ ํ์ํ๋ค.
Unit: void, ๊ทธ๋ฆฌ๊ณ Nothing
Unit์ผ๋ก ์ ์ธ๋ ํจ์๋ ๋ฐํ ๊ฐ์ด ์๋ค. ๋ฉ์๋๋ฅผ ์์ฑํ ๋ ์๋ตํ๋ ๋๋๋ฐ, void์ ๋ค๋ฅธ์ ์ void๊ฐ ํ์ ์ธ์๋ก ์ธ ์ ์๋๋ฐ๋ฉด์ Unit์ ๊ฐ๋ฅํ๋ค๋ ์ ์ด๋ค.
Unit ํ์ ์ ํจ์๋ ๋ฐํ ๊ฐ์ด ๋จ ํ๋๋ฉฐ, Unit๊ฐ์ ๋ฌต์์ ์ผ๋ก ๋ฐํํ๊ธฐ ๋๋ฌธ์ return ์ ๋ช ์ํ์ง์์๋ ๋๋ค.
Nothing ํ์ ์ ์๋ฌด ๊ฐ๋ ํฌํจํ์ง์๋๋ค. ํจ์์ ๋ฐํ ํ์ ์ด๋ ๋ฐํํ ํ๋ผ๋ฏธํฐ์ ํ์ ์ผ๋ก ์ฌ์ฉํ ์ ์๋๋ฐ, ๋ฌดํ๋ฃจํ๋ฅผ ์ข ๋ฃ ์ํจ๋ค๋๊ฐ ํ๋ ์ ์์ข ๋ฃ ๋์ง์๋ ์์ ์ ์ฌ์ฉํ๊ธฐ ์ ์ฉํ๋ค.
fun fail(message: String): Nothing {
throw IllegalStateException(message)
}
์ด๋ฐ ์์ผ๋ก ์ ์ํด์ ์ฌ์ฉํ ์ ์๋ค. Unit๊ณผ Nothing ํ์ ์ ๊ตฌ๋ถํด์ผํ๋ค.
์ปฌ๋ ์
์ปฌ๋ ์ ์ผ๋ก ๋ค์ด๊ฐ๋ฉด ๊ณ ๋ คํ ๊ฒ ๋ ๋ง์์ง๋ค.
val ll : List<Int?>
val ll : List<Int>?
val ll : List<Int?>?
์ฒซ๋ฒ์งธ๋ ์ปฌ๋ ์ ์ null์ด ์๋์ง๋ง ์์๊ฐ nullable์ด๊ณ , ๋๋ฒ์งธ๋ ์ปฌ๋ ์ ์์ฒด๊ฐ nullableํ์ง๋ง ๋ค์ด๊ฐ ์ ์๋ ๊ฐ์ not-null์ด๋ค. ๋ชจ๋ nullableํ๊ฒ ๋ง์ง๋ง ์ค์ด๋ค.
mutable : ๋ณ๊ฒฝ ๊ฐ๋ฅํ
MutableCollection์ ๊ธฐ์กด Collection์ add, remove, clear ๋ฉ์๋๋ฅผ ์ถ๊ฐํด ๋ง๋ ์ธํฐํ์ด์ค๋ค. ๋๋๋ก์ด๋ฉด ์ฝ๊ธฐ์ ์ฉ์ผ๋ก ์ฌ์ฉํ๋ ๊ฒ ์ข์ ๋ฐฉ๋ฒ์ด๋ค.
์ฝํ๋ฆฐ์ ์๋ฐ์ ๋ชจ๋ ์ปฌ๋ ์ ์ธํฐํ์ด์ค ๋ง๋ค Mutableํค์๋๋ฅผ ๋ถ์ธ ์ธํฐํ์ด์ค๋ฅผ ์ถ๊ฐ๋ก ์ ๊ณตํ๋๋ฐ(Map๋ ์ ๊ณต), ์ด ์ธํฐํ์ด์ค๋ mutableListOf(), mutableSetOf() ์ ๊ฐ์ ํจ์๋ฅผ ํธ์ถ ํ ๋ ์ฌ์ฉ๋๋ค.
์ฑ ์ด ๋์จ ๋น์์๋ Mutable๋ง ์์๊ณ , ์ง๊ธ๋ kotlin.collections๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ฅผ ์ด์ด๋ณด๋ ๋๊ฐ๋ค. ๋ฌธ์ ๋ ์๋ฐ๊ฐ ์ฝ๊ธฐ์ ์ฉ/ ๋ณ๊ฒฝ๊ฐ๋ฅ ์ปฌ๋ ์ ์ ๊ตฌ๋ถํ์ง ์๊ธฐ ๋๋ฌธ์ ์ฝํ๋ฆฐ์์ Collection์ผ๋ก ์ ์ธ๋์ด ์ฝ๊ธฐ์ ์ฉ์ผ๋ก ์ ์ธ๋ ๊ฐ์ฒด๋ผ๋ ์๋ฐ์์๋ ๋ณ๊ฒฝํ ์ ์๋ค.
// java class
public class CollectionUtils {
public static List<String> uppercaseAll(List<String> items) {
for (int i = 0; i < items.size(); i++) {
items.set(i, items.get(i).toUpperCase());
}
return items;
}
}
// kotlin
fun printInUppercase(list: List<String>) {
println(CollectionUtils.uppercaseAll(list)) // java ๋ฉ์๋ ์ฌ์ฉ์ค
println(list.first())
}
์ฌ๊ธฐ์ Collection, MutableCollection์ ๋ณด๋ฉด์ ์๊ฐ๋๋ ํค์๋, ํ๋ซํผ ํ์ ์ด ์๋ค.
- ์ปฌ๋ ์ ์ null ๊ฐ๋ฅ์ฑ
- ์ปฌ๋ ์ ์์์ null ๊ฐ๋ฅ์ฑ
- ๋ณ๊ฒฝ๊ฐ๋ฅ์ฑ
์ด ์ธ๊ฐ์ง๋ฅผ ๊ณ ๋ คํด์ ๊ฒฐ์ ํ๋ฉด ๋๋๋ฐ, ๋ณ๊ฒฝ ๊ฐ๋ฅ์ฑ์ด ๋ฏธ์น๋ ์ํฅ์ด ์ ์ผ ํฌ๋ค.
๋ฐฐ์ด
์ฝํ๋ฆฐ ๋ฐฐ์ด์ ํ์ ํ๋ผ๋ฏธํฐ๋ฅผ ๋ฐ๋ ํด๋์ค๋ค. arrayOf(), arrayOfNulls()๋ก ๋๊ธฐ๊ฑฐ๋, Array<T>() ๋ก ๋ง๋ค ์ ์๋ค. Array๋ก ๋ง๋๋ ๊ฒฝ์ฐ๋ ๊ฐ ์์๊ฐ null์ด ์๋ ๋ฐฐ์ด๋ก ๋ง๋ค์ด์ผ ํ ๊ฒฝ์ฐ์ ์ฌ์ฉํ๋ค.
val letters = Array<String>(26) { i -> ('a' + i).toString() }
println(letters.joinToString(""))
์ํ๋ฒณ์๋ฌธ์๋ฅผ ๋ฐฐ์ด๋ก ๋ง๋๋ ์ฝ๋๋ค.
๊ฐ๋ณ์ธ์๋ฅผ ๋ฐ๋ ํจ์๋ฅผ ํธ์ถ ํ ๋ ๋ฐฐ์ด์ ์์ฃผ ๋ง๋๋๋ฐ ์ด๋ ๋๊ธฐ๋ ๋ฐฐ์ด์ด ํ์ ์ถ๋ก ์ด ์๋ ์ํ๊ธฐ ๋๋ฌธ์, ์ด๋ ๋ฐ์ดํฐ๊ฐ ์ด๋ฏธ ์ปฌ๋ ์ ์ ๋ค์ด์๋ค๋ฉด toTypedArray()๋ฅผ ์จ์ ๋ฃ์ผ๋ฉด ๋๋ค. vararg์ ๋ฃ๊ธฐ ๋๋ฌธ์ ์คํ๋ ๋ ์ฐ์ฐ์๋ ๊ฐ์ด ์จ์ค์ผํ๋ค.
val strings = listOf("a", "b", "c")
println("%s/%s/%s".format(*strings.toTypedArray()))
์์ ํ์ ๋ณ๋ก ๋ฐฐ์ด์ด ์กด์ฌํ๋๋ฐ, ์ปดํ์ผ ๋ int[], byte[] ๋ก ์์ํ์ ๋ฐฐ์ด๋ก ์ปดํ์ผ๋๋ค. ๋๋ค๋ก ์ด๋ฐ ๋ฐฐ์ด์ ์ฌ์ฉํ๋ ๋ฒ๋ ์๋ค.
val squares = IntArray(5) { i -> (i+1) * (i+1) }
์ถ๊ฐ๋ก ์ฝํ๋ฆฐ์ ์ปฌ๋ ์ ์ ์ฌ์ฉํ ์ ์๋ ๋ชจ๋ ํ์ฅํจ์๋ฅผ ๋ฐฐ์ด์๋ ์ ๊ณตํ๋ค.
public inline fun <T> kotlin.Array<out T>.forEachIndexed(action: (kotlin.Int, T) -> kotlin.Unit): kotlin.Unit {}
์ด๋ฐ์์ผ๋ก ๋ค ์ ์๋์ด ์์ด์ ์ ์๋ํ๋ ๊ฒ์ ๋ณผ ์ ์๋ค.
"๋๊ธ, ๊ณต๊ฐ ๋ฒํผ ํ ๋ฒ์ฉ ๋๋ฅด๊ณ ๊ฐ์ฃผ์๋ฉด ํฐ ํ์ด ๋ฉ๋๋ค"
'๐๐๏ธ > ์ฝํ๋ฆฐ ์ธ ์ก์ ๐' ์นดํ ๊ณ ๋ฆฌ์ ๋ค๋ฅธ ๊ธ
Kotlin in action(8) (0) | 2023.10.10 |
---|---|
Kotlin in action(7) (0) | 2023.10.10 |
Kotlin in action(5) (0) | 2023.10.10 |
Kotlin in action(4) (0) | 2023.10.10 |
Kotlin in action(3) (0) | 2023.10.10 |