Null

๊ทธ๋™์•ˆ์€ ์ฝ”ํ‹€๋ฆฐ์˜ ๋ฌธ๋ฒ• ์ค‘ ๋„“์€ ๋ฒ”์œ„์˜ ๊ฒƒ๋“ค์„ ์‚ดํŽด๋ณด์•˜๋‹ค. ์ด์ œ ๊ฐ€์žฅ ์ค‘์š”ํ•œ ๋ถ€๋ถ„์„ ๋ฐฐ์›Œ๋ณด์ž: ๋ฐ”๋กœ ํƒ€์ž… ์‹œ์Šคํ…œ์ด๋‹ค. ์ฝ”ํ‹€๋ฆฐ์—์„œ๋Š” ์ƒˆ๋กญ๊ฒŒ ๋งŒ๋“ค์–ด์ง„ ๊ธฐ๋Šฅ, ์ฆ‰ nullable ํƒ€์ž…๊ณผ read-only collection ๋“ฑ์„ ์ง€์›ํ•œ๋‹ค.

Nullability

์ฝ”ํ‹€๋ฆฐ ํƒ€์ž… ์‹œ์Šคํ…œ์—์„œ๋Š” ์ž๋ฐ”์—์„œ ํ”ํžˆ ๋ณผ ์ˆ˜ ์žˆ๋Š” java.lang.NullPointerException๋ฅผ ํ”ผํ•  ์ˆ˜ ์žˆ๊ธฐ ์œ„ํ•ด์„œ ์ปดํŒŒ์ผ ์‹œ์ ์— null ์—๋Ÿฌ๋ฅผ ํŒŒ์•…ํ•  ์ˆ˜ ์žˆ๋„๋ก ๋ช…์‹œ์ ์œผ๋กœ ์ง€์›ํ•œ๋‹ค.

/* Java */
int strLen(String s) {
return s.length();
}

์ž๋ฐ”์—์„œ๋Š” ์œ„์™€ ๊ฐ™์€ ํ•จ์ˆ˜์—์„œ String์ด null์ผ ๊ฒฝ์šฐ NullPointerException ์—๋Ÿฌ๋ฅผ ๋งŒ๋“ค์ง€๋งŒ, ์ฝ”ํ‹€๋ฆฐ์˜ ๊ฒฝ์šฐ String ํƒ€์ž…์ด ๋ฐ˜๋“œ์‹œ ๋„˜๊ฒจ์ง€๋„๋ก ๊ฐ•์ œํ•˜๊ธฐ ๋•Œ๋ฌธ์— null์ด ํฌํ•จ๋œ ๋งค๊ฐœ๋ณ€์ˆ˜๋ฅผ ๋„˜๊ฒจ ์ค„ ์ˆ˜ ์—†๋‹ค. ๋งŒ์•ฝ ์ฝ”ํ‹€๋ฆฐ์—์„œ null์„ ๋„˜๊ฒจ์ฃผ๊ณ  ์‹ถ๋‹ค๋ฉด ์ด๋ฅผ ์•จ๋น„์Šค ์—ฐ์‚ฐ์ž ?๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๋ณด์—ฌ์ค˜์•ผ ํ•œ๋‹ค.

fun strLen(s: String) = s.length
>>> strLen(null)
ERROR: Null can not be a value of a non-null type String

//๋ช…์‹œ์ ์œผ๋กœ null ํƒ€์ž…์„ ๋„˜๊ฒจ์ฃผ๊ธฐ ๋•Œ๋ฌธ์— ? ์‚ฌ์šฉ
un strLenSafe(s: String?) = ...

null ํƒ€์ž…์„ ๋ช…์‹œํ•œ ํ›„์—๋Š” ํ•  ์ˆ˜ ์žˆ๋Š” ์ผ์ด ์ œํ•œ๋˜์–ด ์žˆ๋‹ค.

  1. ๋” ์ด์ƒ fun strLenSafe(s: String?) = s.length()์ฒ˜๋Ÿผ ๋ฉ”์†Œ๋“œ ํ˜ธ์ถœ ๋ถˆ๊ฐ€

  2. null ํƒ€์ž…์ด ์•„๋‹Œ ๊ฐ’์—๊ฒŒ val x: String? = null์ฒ˜๋Ÿผ null ํ• ๋‹น ๋ถˆ๊ฐ€

  3. null ํƒ€์ž…์ด ์•„๋‹Œ ํŒŒ๋ผ๋ฏธํ„ฐ๋ฅผ ๊ฐ€์ง„ ํ•จ์ˆ˜์—๊ฒŒ null ํƒ€์ž… pass ๋ถˆ๊ฐ€

๋‹จ, if๋ฅผ ํ†ตํ•ด null์„ ์ฒดํฌํ•ด ์ค€ ๋‹ค์Œ์—๋Š” ์ปดํŒŒ์ผ๋Ÿฌ๊ฐ€ ์ปดํŒŒ์ผ ํ•˜๋Š” ๊ฒƒ์ด ๊ฐ€๋Šฅํ•˜๋‹ค.

fun strLenSafe(s: String?): Int =
if (s != null) s.length else 0

ํƒ€์ž…์ด๋ž€ ๋ฌด์—‡์ธ๊ฐ€?

ํƒ€์ž…์ด๋ž€ โ€œํ•ด๋‹น ํƒ€์ž…์— ๋Œ€ํ•ด ๊ฐ€๋Šฅํ•œ ๊ฐ’๋“ค์„ ์ง‘ํ•ฉ์œผ๋กœ ๋ชจ์•„ ๋†“์€ ๋ถ„๋ฅ˜โ€์ด๋‹ค.

์ž๋ฐ”์—์„œ๋Š” String ํƒ€์ž…์—์„œ String ๊ฐ’๊ณผ null ๊ฐ’ ๋‘˜ ์ค‘์— ํ•˜๋‚˜๋ฅผ ๊ฐ€์งˆ ์ˆ˜ ์žˆ๋‹ค. ๋”ฐ๋ผ์„œ ์ด๋Ÿฐ ๊ฒฝ์šฐ ์ถ”๊ฐ€์ ์ธ ํƒ€์ž… ์ฒดํฌ๊ฐ€ ํ•„์š”ํ•˜๋‹ค.

๐Ÿ“Œ ์ž๋ฐ”์—์„œ๋„ @Nullable๋‚˜ @NotNull๋ฅผ ํ™œ์šฉํ•˜์—ฌ null ํƒ€์ž… ์ฒดํฌ๊ฐ€ ๊ฐ€๋Šฅํ•˜์ง€๋งŒ, ์ด๋Š” ๋ณ„๋กœ ์œ ์šฉํ•˜์ง€ ์•Š๋‹ค. ๋˜ ๋‹ค๋ฅธ ํ•ด๊ฒฐ๋ฒ•์€ Optional class๋ฅผ ํ™œ์šฉํ•˜์—ฌ null ํƒ€์ž…์„ ๊ฐ์‹ธ๋Š” ๊ฒƒ์ด์ง€๋งŒ, ์ด๋Š” ๋” ๋ณต์žกํ•œ ์ฝ”๋“œ๋ฅผ ์ƒ์„ฑํ•˜๊ฒŒ ๋œ๋‹ค.

์ด๋Ÿฌํ•œ ์ž๋ฐ”์˜ ๋ฌธ์ œ์ ์„ ์ฝ”ํ‹€๋ฆฐ์€ Nullable ํƒ€์ž…์„ ์ œ๊ณตํ•จ์œผ๋กœ์จ ์†์‰ฝ๊ฒŒ ํ•ด๊ฒฐ ๊ฐ€๋Šฅํ•˜๋‹ค. Nullable๊ณผ None-null์„ ๊ตฌ๋ถ„ํ•จ์œผ๋กœ ์ธํ•ด ์–ด๋– ํ•œ ๊ฐ’์ด ์–ด๋–ค ๊ณ„์‚ฐ์„ ํ•  ์ˆ˜ ์žˆ๋Š”์ง€ ๋ช…ํ™•ํ•˜๊ฒŒ ์ดํ•ดํ•  ์ˆ˜ ์žˆ๋‹ค.

Safe call operator: โ€œ?.โ€

ํ•ด๋‹น ์—ฐ์‚ฐ์ž๋Š” null ์ฒดํฌ์™€ ๋™์‹œ์— ๋ฉ”์†Œ๋“œ๋ฅผ ํ˜ธ์ถœํ•˜๋Š” ์—ญํ• ์„ ํ•œ๋‹ค.

s?.toUpperCase()
//๊ฐ™์€ ์˜๋ฏธ
if (s != null) s.toUpperCase() else null.

์ด๋•Œ ์ฃผ์˜ํ•  ์ ์€, ๋น„๋ก String.toUpperCase()์˜ ํ˜ธ์ถœ ๊ฒฐ๊ณผ๊ฐ€ String์ด์–ด์•ผ ํ•˜์ง€๋งŒ, s๊ฐ€ null์ผ ๋•Œ ํ•จ์ˆ˜์˜ ํ˜ธ์ถœ ๊ฒฐ๊ณผ๋Š” String?์ด ๋œ๋‹ค.

class Employee(val name: String, val manager: Employee?)
fun managerName(employee: Employee): String? = employee.manager?.name

์œ„์™€ ๊ฐ™์ด ?.์„ ํ™œ์šฉํ•  ๊ฒฝ์šฐ, manager๊ฐ€ ์กด์žฌํ•˜์ง€ ์•Š๋Š” ๊ฒฝ์šฐ์— ๋Œ€ํ•ด์„œ ์ถ”๊ฐ€์ ์ธ ์ฒดํฌ๊ฐ€ ์—†์ด ํ•œ ์ค„๋กœ ๋ฐ”๋กœ ํ•ด๊ฒฐ์ด ๊ฐ€๋Šฅํ•˜๋‹ค. ๋˜ํ•œ ๋‹ค์Œ๊ณผ ๊ฐ™์ด ์—ฌ๋Ÿฌ ๊ฐœ์˜ Safe call operator๋ฅผ ์ฒด์ธ์œผ๋กœ ๋งŒ๋“ค์–ด ๊ฐ๊ฐ์˜ ๊ฐ’์„ null์ธ์ง€ ์ฒดํฌํ•  ์ˆ˜ ์žˆ๋‹ค.

class Address(val streetAddress: String, val zipCode: Int, val city: String, val country: String)
class Company(val name: String, val address: Address?)
class Person(val name: String, val company: Company?)
fun Person.countryName(): String {
	val country = this.company?.address?.country
	return if (country != null) country else "Unknown"
}

์•จ๋น„์Šค ์—ฐ์‚ฐ์ž: โ€œ?:โ€

์ฝ”ํ‹€๋ฆฐ์—์„œ๋Š” null ๋Œ€์‹  ๋„ฃ์–ด์ค„ ์ˆ˜ ์žˆ๋Š” ๋””ํดํŠธ ๊ฐ’์„ ์ฒ˜๋ฆฌํ•˜๋Š” ์•จ๋น„์Šค ์—ฐ์‚ฐ์ž๊ฐ€ ์žˆ๋‹ค. ๋งŒ์•ฝ ๊ฐ’์ด null์ด ์•„๋‹ ๊ฒฝ์šฐ์—๋Š” ๊ทธ ๊ฐ’์„ ํ™œ์šฉํ•˜๊ณ , null์ผ ๊ฒฝ์šฐ์—๋Š” ๋””ํดํŠธ ๊ฐ’์„ ๋„ฃ์–ด์ค€๋‹ค. ์ด๋Š” ์ข…์ข… ?.์™€ ๊ฐ™์ด ํ™œ์šฉ๋˜๊ธฐ๋„ ํ•œ๋‹ค.

fun strLenSafe(s: String?): Int = s?.length ?: 0
>>> println(strLenSafe("abc"))
3
>>> println(strLenSafe(null))
0

fun Person.countryName() =
	company?.address?.country ?: "Unknown"

๋˜ํ•œ ์ฝ”ํ‹€๋ฆฐ์—์„œ๋Š” ์•จ๋น„์Šค ์—ฐ์‚ฐ์ž๋ฅผ throw๋‚˜ return๊ณผ ํ•จ๊ป˜ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์–ด ๋”์šฑ ํŽธ๋ฆฌํ•˜๋‹ค.

data class Address(val city: String, val country: String)

data class Company(val name: String, val address: Address?)

data class Employee(val name: String, val company: Company?)

fun print(employee: Employee) {
  // ์—˜๋น„์Šค ์—ฐ์‚ฐ์ž๋กœ throw๋„ ๊ฐ€๋Šฅ
  val address = employee?.company?.address ?: throw IllegalArgumentException("Need Address")
  with(address) {
    print("city: $city, countyL $country")
  }
}

์œ„์˜ ์ฝ”๋“œ์—์„œ ๋งŒ์•ฝ address๊ฐ€ ์กด์žฌํ•˜์ง€ ์•Š๋Š”๋‹ค๋ฉด, NullPointerException์„ ๋˜์ง€์ง€ ์•Š๊ณ  ๊ทธ ๋Œ€์‹  ์˜๋ฏธ ์žˆ๋Š” ์—๋Ÿฌ๋ฅผ ๋ณด์—ฌ์ค€๋‹ค.

์•ˆ์ „ํ•œ ์บ์ŠคํŒ…: โ€œas?โ€

์ž๋ฐ”์—์„œ๋Š” ์บ์ŠคํŠธํ•˜๋ ค๋Š” ๊ฐ’์ด ์กด์žฌํ•˜์ง€ ์•Š์„ ๊ฒฝ์šฐ ํƒ€์ž… ์บ์ŠคํŠธ ์ค‘์— ClassCastException์ด ๋ฐœ์ƒํ•  ์ˆ˜ ์žˆ์ง€๋งŒ, ์ฝ”ํ‹€๋ฆฐ์€ as?๋ฅผ ํ†ตํ•ด ํ•ด๋‹น ์—๋Ÿฌ๊ฐ€ ๋ฐœ์ƒํ•˜์ง€ ์•Š๋„๋ก ํ•  ์ˆ˜ ์žˆ๋‹ค. ์ด๋Ÿฌํ•œ ํƒ€์ž… ์บ์ŠคํŒ…์€ ์•จ๋น„์Šค ์—ฐ์‚ฐ์ž๋ฅผ ํ•จ๊ป˜ ํ™œ์šฉํ•  ์ˆ˜ ์žˆ๋Š”๋ฐ, ์ด๋Š” equals ๋ฉ”์†Œ๋“œ๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ณผ์ •์—์„œ ์ž˜ ๋“œ๋Ÿฌ๋‚œ๋‹ค.

class Person(val firstName: String, val lastName: String) {
	override fun equals(o: Any?): Boolean {
		val otherPerson = o as? Person ?: return false
		return otherPerson.firstName == firstName &&
			otherPerson.lastName == lastName
	}
	override fun hashCode(): Int =
		firstName.hashCode() * 37 + lastName.hashCode()
}

์œ„์—์„œ ๋ณผ ์ˆ˜ ์žˆ๋“ฏ์ด, ์ด๋Ÿฌํ•œ ํŒจํ„ด์„ ํ™œ์šฉํ•˜๋ฉด ํŒŒ๋ผ๋ฏธํ„ฐ๊ฐ€ ์ ์ ˆํ•œ ํƒ€์ž…์„ ๊ฐ€์ง€๊ณ  ์žˆ๋Š”์ง€ ํ™•์ธํ•˜๊ณ , ์บ์ŠคํŒ…ํ•˜๊ณ , ์ ์ ˆํ•˜์ง€ ์•Š์„ ๊ฒฝ์šฐ false๋ฅผ ๋Œ๋ ค๋ณด๋‚ผ ์ˆ˜ ์žˆ๋‹ค.

๊ทธ๋Ÿฌ๋‚˜ ๊ฐ€๋”์”ฉ์€ ์ปดํŒŒ์ผ๋Ÿฌ์—๊ฒŒ null์ด ์•„๋‹ˆ๋ผ๋Š” ๊ฒƒ์„ ๋ช…์‹œํ•ด์คŒ์œผ๋กœ์จ null์„ ๋‹ค๋ฃฐ ์ˆ˜๋„ ์žˆ๋‹ค.

null ์•„๋‹˜ ๋‹จ์–ธ: โ€œ!!โ€

fun ignoreNulls(s: String?) {
	val sNotNull: String = s!!
	println(sNotNull.length)
}

๋งŒ์•ฝ s๊ฐ€ null์ผ ๊ฒฝ์šฐ์—๋Š” ์–ด๋–ค ์ผ์ด ์ƒ๊ธธ๊นŒ? NullPointerException์™€ ๊ฐ™์€ ์—๋Ÿฌ๋ฅผ ๋Ÿฐํƒ€์ž„์— ๋˜์ง€๋Š” ๋“ฑ์˜ ์—๋Ÿฌ๊ฐ€ ๋ฐœ์ƒํ•œ๋‹ค. ๋”ฐ๋ผ์„œ null ์•„๋‹˜ ๋‹จ์–ธ์€ NPE์™€ ๊ฐ™์€ ์—๋Ÿฌ๋ฅผ ๊ฐ์ˆ˜ํ•  ๋•Œ๋งŒ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค.

๊ทธ๋Ÿฌ๋‚˜ null ์•„๋‹˜ ๋‹จ์–ธ์„ ์œ ์šฉํ•˜๊ฒŒ ํ™œ์šฉํ•  ์ˆ˜ ์žˆ๋Š” ์ƒํ™ฉ๋„ ์žˆ๋Š”๋ฐ, ์˜ˆ๋ฅผ ๋“ค์–ด ํ•œ ํ•จ์ˆ˜์—์„œ ์ด๋ฏธ null์ด ์•„๋‹˜์„ ์ฒดํฌํ–ˆ๊ณ  ๊ทธ ๊ฐ’์„ ๋‹ค๋ฅธ ํ•จ์ˆ˜์—์„œ ํ™œ์šฉํ•  ๋•Œ, ์ปดํŒŒ์ผ๋Ÿฌ๋Š” ํ•ด๋‹น ๊ฐ’์ด null์ด ์•„๋‹ˆ๋ผ๋Š” ๊ฒƒ์„ ๋ชจ๋ฅธ๋‹ค. ๋”ฐ๋ผ์„œ ๋ช…์‹œ์ ์œผ๋กœ ํ‘œํ˜„ํ•ด์ฃผ์–ด์•ผ ๋œ๋‹ค.

class CopyRowAction(val list: JList<String>) : AbstractAction() {
	override fun isEnabled(): Boolean =
		list.selectedValue != null
	override fun actionPerformed(e: ActionEvent) {
		val value = list.selectedValue!!
		// copy value to clipboard
	}
}

๋งŒ์•ฝ ์œ„์˜ ์ƒํ™ฉ์—์„œ !!๋ฅผ ์‚ฌ์šฉํ•˜์ง€ ์•Š๋Š”๋‹ค๋ฉด, val value = list.selectedValue ?: return๋ฅผ ํ†ตํ•ด non-null ํƒ€์ž…์„ ํ™•๋ณดํ•  ์ˆ˜ ์žˆ๋‹ค.

์ปดํŒŒ์ผ๋Ÿฌ๋Š” ์—๋Ÿฌ๊ฐ€ ๋ฐœ์ƒํ•˜๋ฉด ๋ฐœ์ƒํ•œ line์„ ์ถ”์ ํ•˜์ง€ ๋ช…๋ น์–ด๋ฅผ ์ฒดํฌํ•˜์ง€ ์•Š๊ธฐ ๋•Œ๋ฌธ์—, ํ•œ ์ค„์— !!๋ฅผ ๋‘ ๊ฐœ ์ด์ƒ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์€ ๋ฐ”๋žŒ์งํ•˜์ง€ ๋ชปํ•˜๋‹ค.

  • person.company!!.address!!.country //๋ฐ”๋žŒ์งํ•˜์ง€ ๋ชปํ•œ ์ฝ”๋“œ

let ํ•จ์ˆ˜

let ํ•จ์ˆ˜๋Š” nullable์„ ๋‹ค๋ฃจ๊ธฐ ๋” ์‰ฝ๊ฒŒ ๋งŒ๋“ค์–ด์ค€๋‹ค. ์ฃผ๋กœ null์ด ๋ถˆ๊ฐ€๋Šฅํ•œ ํ•จ์ˆ˜์˜ ํŒŒ๋ผ๋ฏธํ„ฐ๋กœ nullableํ•œ ํƒ€์ž…์˜ ๊ฐ’์„ ๋„˜๊ธฐ๋ ค๊ณ  ํ•  ๋•Œ let์„ ํ™œ์šฉํ•œ๋‹ค.

fun sendEmailTo(email: String) { /*...*/ }
>>> val email: String? = ...
>>> sendEmailTo(email)
ERROR: Type mismatch: inferred type is String? but String was expected

//์†”๋ฃจ์…˜ ์ค‘ ํ•˜๋‚˜: null์ด ์•„๋‹˜์„ ์ฒดํฌํ•œ๋‹ค.
if (email != null) sendEmailTo(email)

let ํ•จ์ˆ˜๋ฅผ ํ™œ์šฉํ•˜๋ฉด ์œ„์˜ ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•  ์ˆ˜ ์žˆ๋‹ค. null์ด ์•„๋‹ ๋•Œ๋Š” ์ž๋™์œผ๋กœ ์ƒ์„ฑ๋œ it์œผ๋กœ ํ™œ์šฉ ๊ฐ€๋Šฅํ•˜๋‹ค.

์—ฌ๋Ÿฌ ๊ฐ’์„ null์ธ์ง€ ์•„๋‹Œ์ง€ ์ฒดํฌํ•ด์•ผ ํ•  ๋•Œ๋Š” ์ค‘์ฒฉ let์„ ํ™œ์šฉํ•˜์—ฌ ํ•  ์ˆ˜ ์žˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ์ด๋Ÿด ๊ฒฝ์šฐ ๊ต‰์žฅํžˆ ์ฝ”๋“œ๊ฐ€ ๋ณต์žกํ•ด์งˆ ์ˆ˜ ์žˆ๊ธฐ ๋•Œ๋ฌธ์—, ํ‰๋ฒ”ํ•œ if ์กฐ๊ฑด๋ฌธ์„ ํ™œ์šฉํ•˜๋Š” ๊ฒƒ์ด ๋”์šฑ ๊ถŒ์žฅ๋œ๋‹ค.

null ๋ถˆ๊ฐ€๋Šฅ ํƒ€์ž…์˜ ์ง€์—ฐ ์ดˆ๊ธฐํ™”

๋งŽ์€ ๊ฒฝ์šฐ ์ดˆ๊ธฐํ™” ๋ฉ”์†Œ๋“œ๋Š” ์ธ์Šคํ„ด์Šค๊ฐ€ ์ƒ์„ฑ๋œ ์งํ›„ ์ง„ํ–‰๋œ๋‹ค. ํ‰๋ฒ”ํ•œ ๊ฒฝ์šฐ, ์ฝ”ํ‹€๋ฆฐ์€ ๊ฐ’์„ ์ƒ์„ฑ์ž์—์„œ ์ดˆ๊ธฐํ™”ํ•  ๊ฒƒ์„ ๊ถŒ์žฅํ•˜๊ณ  ํ”„๋กœํผํ‹ฐ๊ฐ€ non-null์ผ ๊ฒฝ์šฐ์— non-null ์ดˆ๊ธฐํ™” ๊ฐ’์„ ์ œ๊ณตํ•ด์•ผ ํ•œ๋‹ค. ๊ทธ๋ ‡์ง€ ์•Š์„ ๊ฒฝ์šฐ์—๋Š” nullable ํƒ€์ž…์„ ๋Œ€์‹  ์‚ฌ์šฉํ•ด์•ผ ํ•œ๋‹ค.

class MyService {
	fun performAction(): String = "foo"
}
class MyTest {
	private lateinit var myService: MyService
	@Before fun setUp() {
		myService = MyService()
	}
	@Test fun testAction() {
		Assert.assertEquals("foo", myService.performAction())
	}
}

์ง€์—ฐ ์ดˆ๊ธฐํ™”์˜ ํ”„๋กœํผํ‹ฐ๋Š” ํ•ญ์ƒ var์ด๋ผ๋Š” ๊ฒƒ์„ ๋ช…์‹œํ•˜์ž(์ฝ๊ธฐ์™€ ์“ฐ๊ธฐ ๊ฐ€๋Šฅ). lateinit์„ ํ™œ์šฉํ•˜๋ฉด null์ด ๋ถˆ๊ฐ€๋Šฅํ•œ ํƒ€์ž…์„ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์ง€๋งŒ, ํ”„๋กœํผํ‹ฐ ์ดˆ๊ธฐํ™”์ „์— ์ ‘๊ทผํ•  ๊ฒฝ์šฐ์—๋Š” โ€œlateinit property myService has not been initializedโ€์™€ ๊ฐ™์€ ์—๋Ÿฌ๊ฐ€ ๋ฐœ์ƒํ•œ๋‹ค.

nullable ํƒ€์ž…์˜ ํ™•์žฅ

//ํ™•์žฅ ํ•จ์ˆ˜๋ฅผ ํ˜ธ์ถœํ•˜๋Š” ๊ฒฝ์šฐ
fun verifyUserInput(input: String?) {
	if (input.isNullOrBlank()) {
		println("Please fill in the required fields")
	}
}

nullable ํƒ€์ž…์œผ๋กœ ํ™•์žฅ ํ•จ์ˆ˜๋ฅผ ํ˜ธ์ถœํ•˜๋Š” ๊ฒฝ์šฐ, nullable ํƒ€์ž…์œผ๋กœ ํ•ด๋‹น ํ•จ์ˆ˜๋ฅผ ๋ถ€๋ฅผ ์ˆ˜ ์žˆ๊ฒŒ ๋œ๋‹ค. ๋˜ํ•œ null ํƒ€์ž…์„ ๊ฐ€์งˆ ์ˆ˜ ์žˆ๊ธฐ ๋•Œ๋ฌธ์— ์ด๋ฅผ ๋ช…์‹œ์ ์œผ๋กœ ์ฒดํฌํ•ด์ค˜์•ผ ํ•œ๋‹ค.

ํƒ€์ž… ํŒŒ๋ผ๋ฏธํ„ฐ์™€ nullable

๋ชจ๋“  ํ•จ์ˆ˜์˜ ํƒ€์ž… ํŒŒ๋ผ๋ฏธํ„ฐ๋Š” nullable์ผ ์ˆ˜ ์žˆ๋‹ค. ?๋กœ ๋๋‚˜์ง€ ์•Š์•„๋„ ํƒ€์ž… ํŒŒ๋ผ๋ฏธํ„ฐ๋Š” null ํƒ€์ž…์„ ํ—ˆ์šฉํ•œ๋‹ค.

// ํƒ€์ž… ํŒŒ๋ผ๋ฏธํ„ฐ๋Š” ์œ ์ผํ•˜๊ฒŒ **Any?**๋กœ ์ถ”๋ก ๋˜๋ฏ€๋กœ nullableํ•˜๋‹ค.
fun <T> some1(): T = TODO()

// ์ƒํ•œ์„ ๋‘์–ด null์ด ๋ถˆ๊ฐ€๋Šฅํ•˜๊ฒŒ ํ•  ์ˆ˜๋„ ์žˆ๋‹ค.
fun <T : Any> some2(): T = TODO()

์ž๋ฐ”์™€ nullable

์ฝ”ํ‹€๋ฆฐ์—์„œ์™€ ๋‹ฌ๋ฆฌ ์ž๋ฐ”์—์„œ๋Š” nullable ํƒ€์ž…์„ ์ง€์›ํ•˜์ง€ ์•Š๋Š”๋‹ค. ๊ทธ๋ ‡๋‹ค๋ฉด ์ž๋ฐ”์™€ ์ฝ”ํ‹€๋ฆฐ์„ ๊ฐ™์ด ์‚ฌ์šฉํ•  ๋•Œ๋Š” ์–ด๋–ป๊ฒŒ ๋ ๊นŒ?

์ฒซ์งธ, ์ž๋ฐ”์—์„œ๋Š” ๊ฐ€๋”์”ฉ @Nullable String๋“ฑ์œผ๋กœ null์— ๋Œ€ํ•œ ์ •๋ณด๋ฅผ ํ‘œ์‹œํ•ด์ค€๋‹ค. ์ด๋Š” ์ฝ”ํ‹€๋ฆฐ์˜ String?๊ณผ ๋Œ€์น˜๋œ๋‹ค.

๊ทธ๋Ÿฐ๋ฐ ์ด๋ ‡๊ฒŒ nullable์„ ๋ช…์‹œํ•ด์ฃผ๋Š” ์ฃผ์„์ด ์—†๋Š” ๊ฒฝ์šฐ๋Š” ํ”Œ๋žซํผ ํƒ€์ž…์„ ์‚ฌ์šฉํ•œ๋‹ค.

ํ”Œ๋žซํผ ํƒ€์ž…

์ฝ”ํ‹€๋ฆฐ์ด null์— ๋Œ€ํ•œ ์ •๋ณด๋ฅผ ์•Œ์ˆ˜ ์—†๋Š” ํƒ€์ž…์ผ ๊ฒฝ์šฐ, ์ฒ˜๋ฆฌ๋ฅผ ๊ฐœ๋ฐœ์ž์—๊ฒŒ ์ „์ ์œผ๋กœ ๋งก๊ธฐ๊ฒŒ ๋œ๋‹ค.

/* Java */
public class Person {
	private final String name;
	public Person(String name) {
		this.name = name;
	}
	public String getName() {
		return name;
	}
}

getName์€ null์„ ๋ฐ˜ํ™˜ํ• ๊นŒ, ์•„๋‹ˆ๋ฉด ๋ฐ˜ํ™˜ํ•˜์ง€ ์•Š์„๊นŒ? ์ฝ”ํ‹€๋ฆฐ ์ปดํŒŒ์ผ๋Ÿฌ๋Š” ์ด ๊ฒฝ์šฐ์— null์ธ์ง€ ์•„๋‹Œ์ง€ ๋ชจ๋ฅด๊ธฐ ๋•Œ๋ฌธ์— ๊ฐœ๋ฐœ์ž๊ฐ€ ์Šค์Šค๋กœ ํ•ด๊ฒฐํ•ด์•ผ ํ•œ๋‹ค. ๊ฐ’์ด null์ด ์•„๋‹ˆ๋ผ๋Š” ๊ฒƒ์„ ํ™•์‹ ํ•œ๋‹ค๋ฉด ์ถ”๊ฐ€์ ์ธ ํ™•์ธ ์—†์ด ์‚ฌ์šฉํ•  ์ˆ˜๋„ ์žˆ๋‹ค. ์ฝ”ํ‹€๋ฆฐ์—์„œ๋Š” ์œ„์˜ ์ž๋ฐ” ์ฝ”๋“œ๋ฅผ ๋‹ค์Œ๊ณผ ๊ฐ™์ด ๋‹ค๋ฃฐ ์ˆ˜ ์žˆ๋‹ค.

fun yellAtSafe(person: Person) {
	println((person.name ?: "Anyone").toUpperCase() + "!!!")
}
>>> yellAtSafe(Person(null))
ANYONE!!!

์ƒ์†

์ž๋ฐ” ๋ฉ”์†Œ๋“œ๋ฅผ ์ฝ”ํ‹€๋ฆฐ์—์„œ ์˜ค๋ฒ„๋ผ์ด๋”ฉ ํ•œ ๊ฒฝ์šฐ, ํŒŒ๋ผ๋ฏธํ„ฐ์™€ ๋ฆฌํ„ดํƒ€์ž…์„ nullable ๋˜๋Š” non-null๋กœ ํ•  ์ง€ ๊ฒฐ์ •ํ•  ์ˆ˜ ์žˆ๋‹ค.

/* Java */
interface StringProcessor {
void process(String value);
}
**//๋‘ ๊ฐ€์ง€ ์˜ค๋ฒ„๋ผ์ด๋”ฉ ๋ชจ๋‘ ํ—ˆ์šฉ ๊ฐ€๋Šฅ**
class StringPrinter : StringProcessor {
	override fun process(value: String) {
		println(value)
	}
}
class NullableStringPrinter : StringProcessor {
	override fun process(value: String?) {
		if (value != null) {
			println(value)
		}
	}
}

์ด๋•Œ ์ž๋ฐ” ๋ฉ”์†Œ๋“œ๋ฅผ ์˜ค๋ฒ„๋ผ์ด๋“œํ•˜๊ณ , ๋ฉ”์†Œ๋“œ ๋ณ€์ˆ˜๊ฐ€ null ๋ถˆ๊ฐ€๋Šฅํ•œ ํƒ€์ž…์œผ๋กœ ์„ ์–ธ๋˜์—ˆ์„ ๊ฒฝ์šฐ ์ปดํŒŒ์ผ๋Ÿฌ๋Š” null ์•„๋‹˜์„ ๋‹จ์–ธํ•˜๋Š” ํ™•์ธ์„ ์ž๋™์œผ๋กœ ์ถ”๊ฐ€ํ•ด์ค€๋‹ค.

์›์‹œ ํƒ€์ž…

์ž๋ฐ”๋Š” ์›์‹œ ํƒ€์ž…๊ณผ ๋ ˆํผ๋Ÿฐ์Šค ํƒ€์ž…์˜ ๋ช…ํ™•ํ•œ ๊ตฌ๋ถ„์„ ๊ฐ€์ง„๋‹ค. ์›์‹œ ํƒ€์ž…์€ ๊ทธ๊ฒƒ์˜ ๊ฐ’์„ ๋ฐ”๋กœ ๊ฐ€์ง€๊ณ  ์žˆ๊ณ , ๋ ˆํผ๋Ÿฐ์Šค ํƒ€์ž…์˜ ๊ฒฝ์šฐ ํ•ด๋‹น ๊ฐ์ฒด๋ฅผ ๊ฐ€์ง€๋Š” ๋ฉ”๋ชจ๋ฆฌ ์œ„์น˜๋ฅผ ๊ฐ€์ง€๊ณ  ์žˆ๋‹ค. ์›์‹œ ํƒ€์ž…์˜ ๊ฒฝ์šฐ ํ•ด๋‹น ๊ฐ’์„ ์ €์žฅํ•˜๊ฑฐ๋‚˜ ๋„˜๊ฒจ์ฃผ๊ธฐ ๋” ํŽธํ•˜์ง€๋งŒ, ์ปฌ๋ ‰์…˜์— ์ €์žฅํ•˜๊ฑฐ๋‚˜ ๋ฉ”์†Œ๋“œ๋ฅผ ํ˜ธ์ถœํ•  ์ˆ˜๋Š” ์—†๊ธฐ ๋•Œ๋ฌธ์— ์ž๋ฐ”์—์„œ๋Š” ํŠน๋ณ„ํ•œ wrapper ํƒ€์ž…(Integer์™€ ๊ฐ™์€)์„ ์ œ๊ณตํ•œ๋‹ค. ๋”ฐ๋ผ์„œ ์ปฌ๋ ‰์…˜์„ ์‚ฌ์šฉํ•˜๊ธฐ ์œ„ํ•ด์„œ๋Š” Collection<Integer>๊ณผ ๊ฐ™์ด ์‚ฌ์šฉํ•ด์•ผ ํ•œ๋‹ค.

๊ทธ๋Ÿฐ๋ฐ ์ฝ”ํ‹€๋ฆฐ์€ ์›์‹œ ํƒ€์ž…๊ณผ ๋ž˜ํผ ํƒ€์ž…์˜ ๊ตฌ๋ถ„์ด ์—†๋‹ค. ์ฝ”ํ‹€๋ฆฐ์€ ๋‚ด๋ถ€์ ์œผ๋กœ ๋Ÿฐํƒ€์ž„์— ๊ฐ€์žฅ ํšจ์œจ์ ์ธ ๋ฐฉ์‹์œผ๋กœ ์ฒ˜๋ฆฌํ•œ๋‹ค. ์•„๋ž˜์™€ ๊ฐ™์ด ๋” ํŽธ๋ฆฌํ•˜๊ฒŒ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค.

val i: Int = 1
val list: List<Int> = listOf(1, 2, 3)

์ž๋ฐ”์˜ ์›์‹œ ํƒ€์ž…๊ณผ ์ผ์น˜ํ•˜๋Š” ํƒ€์ž… ๋ฆฌ์ŠคํŠธ๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™๋‹ค.

  • Integer typesโ€”Byte, Short, Int, Long

  • Floating-point number typesโ€”Float, Double

  • Character typeโ€”Char

  • Boolean typeโ€”Boolean

Number conversions

์ฝ”ํ‹€๋ฆฐ๊ณผ ์ž๋ฐ”์˜ ์ค‘์š”ํ•œ ์ฐจ์ด๋Š” ์ˆซ์ž์˜ ๋ณ€ํ™˜์ด๋‹ค. ์ฝ”ํ‹€๋ฆฐ์€ ํ•œ ์ˆซ์ž ํƒ€์ž…์—์„œ ๋‹ค๋ฅธ ์ˆซ์ž ํƒ€์ž…์œผ๋กœ ๋ณ€ํ™˜ํ•ด์ฃผ์ง€ ์•Š๋Š”๋‹ค(๋ณ€ํ™˜๋˜๋Š” ๊ฐ’์ด ๋” ํฌ๋‹ค๊ณ  ํ•˜๋”๋ผ๋„). ์˜ˆ๋ฅผ ๋“ค์–ด ๋‹ค์Œ๊ณผ ๊ฐ™์€ ์ฝ”๋“œ๋Š” type mismatch ์—๋Ÿฌ๋ฅผ ์ƒ์„ฑํ•œ๋‹ค.

val i = 1
val l: Long = i

๋”ฐ๋ผ์„œ i.toLong()์ฒ˜๋Ÿผ ํƒ€์ž… ๋ณ€ํ™˜์„ ๋ช…์‹œ์ ์œผ๋กœ ๋ณด์—ฌ์ค˜์•ผ ํ•œ๋‹ค. ์ด๋Ÿฌํ•œ ํƒ€์ž… ๋ณ€ํ™˜์€ ์ˆซ์ž ๋ฟ๋งŒ ์•„๋‹ˆ๋ผ toByte(), toShort(), toChar()์ฒ˜๋Ÿผ ๋‹ค๋ฅธ ํƒ€์ž…์—๋„ ์ ์šฉ๋œ๋‹ค. ์ด๋Ÿฌํ•œ ํ•จ์ˆ˜๋Š” ์ž‘์€ ํƒ€์ž…์—์„œ ํฐ ํƒ€์ž…, ํฐ ํƒ€์ž…์—์„œ ์ž‘์€ ํƒ€์ž… ๋ชจ๋‘ ์ง€์›ํ•œ๋‹ค.

๐Ÿ“Œ ์ฐธ๊ณ : ์›์‹œ ํƒ€์ž… ๋ฆฌํ„ฐ๋Ÿด Long: use the L suffix: 123L. Double: use the standard representation of floating-point numbers: 0.12, 2.0, 1.2e10, 1.2e-10. Float: use the f or F suffix: 123.4f, .456F, 1e3f. Hexadecimal literals: use the 0x or 0X prefix (0xCAFEBABL). Binary literals: 0b or 0B prefix (0b000000101).

๋งŒ์•ฝ ์ด๋Ÿฌํ•œ ์ˆซ์ž ๋ฆฌํ„ฐ๋Ÿด์„ ์‚ฌ์šฉํ•œ๋‹ค๋ฉด, ์ปดํŒŒ์ผ๋Ÿฌ๊ฐ€ ํƒ€์ž… ๋ณ€ํ™˜์„ ๋ช…์‹œ์ ์œผ๋กœ ํ•  ์ˆ˜ ์žˆ๋‹ค.

fun foo(l: Long) = println(l)
>>> val b: Byte = 1
>>> val l = b + 1L **//๋ฆฌํ„ฐ๋Ÿด์„ ์‚ฌ์šฉํ•˜์—ฌ ํƒ€์ž… ๋ณ€ํ™˜ ๊ฐ€๋Šฅ**
>>> foo(42)
42

โ€œAnyโ€์™€ โ€œAny?โ€: ์ตœ์ƒ์œ„ ํƒ€์ž…

๋งˆ์น˜ ๊ฐ์ฒด์—์„œ Object๊ฐ€ ๋ชจ๋“  ํด๋ž˜์Šค์˜ ๋ฃจํŠธ๊ฐ€ ๋˜๋Š” ๊ฒƒ์ฒ˜๋Ÿผ, ํƒ€์ž…์˜ ์ตœ์ƒ์œ„๋Š” Any๊ฐ€ ๋œ๋‹ค. ์ž๋ฐ”์—์„œ๋Š” Wrapper๋กœ ๊ฐ์‹ผ ํƒ€์ž…์˜ ๋ฃจํŠธ๊ฐ€ Object๊ฐ€ ๋˜์ง€๋งŒ, ์ฝ”ํ‹€๋ฆฐ์—์„œ๋Š” ๋ชจ๋“  ํƒ€์ž…์˜ ์ตœ์ƒ์œ„ ํƒ€์ž…์ด Any๊ฐ€ ๋œ๋‹ค๋Š” ์ฐจ์ด๊ฐ€ ์žˆ๋‹ค.

โ€Unitโ€: ์ฝ”ํ‹€๋ฆฐ์˜ โ€œVoidโ€

์ฝ”ํ‹€๋ฆฐ์˜ Unit์€ ์ž๋ฐ”์˜ void์™€ ๊ฐ™์€ ์—ญํ• ์„ ํ•œ๋‹ค. ์ฆ‰, ๋Œ๋ ค์ค„ ๋งŒํ•œ ๋ฆฌํ„ด ํƒ€์ž…์ด ๋”ฑํžˆ ์—†์„ ๋•Œ ์‚ฌ์šฉ๋œ๋‹ค. Unit์€ ์ƒ๋žต ๊ฐ€๋Šฅํ•˜๋‹ค.

fun f(): Unit { ... }
fun f(): { ... }

Unit๊ณผ void์˜ ์ฐจ์ด์ ์€ ๋ฐ”๋กœ Unit์ด ๋ณธ๊ฒฉ์ ์ธ ํƒ€์ž…์ด๋ผ๋Š” ๊ฒƒ์ด๋‹ค. void์™€ ๋‹ฌ๋ฆฌ, Unit์€ ํƒ€์ž… ์š”์†Œ๋กœ ์‚ฌ์šฉ๋  ์ˆ˜ ์žˆ๋‹ค. ๋‹จ, Unit ํƒ€์ž…์— ๋Œ€ํ•ด์„œ๋Š” ๋‹จ ํ•˜๋‚˜์˜ ๊ฐ’๋งŒ ์กด์žฌํ•œ๋‹ค-๋ฐ”๋กœ implicitly์ด๋‹ค. ๋˜ํ•œ return Unit์„ ์ž‘์„ฑํ•  ํ•„์š”๊ฐ€ ์—†๋Š”๋ฐ, ์ปดํŒŒ์ผ๋Ÿฌ์— ์˜ํ•ด ์ž๋™์œผ๋กœ ์ถ”๊ฐ€๋˜๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค.

Nothing ํƒ€์ž…: ์ด ํ•จ์ˆ˜๋Š” ๋ฆฌํ„ดํ•˜์ง€ ์•Š์Œ

๊ฐ’์„ ๋ฆฌํ„ดํ•ด์ค€๋‹ค๋Š” ๊ฐœ๋…์€ ํ•จ์ˆ˜๊ฐ€ ์„ฑ๊ณต์ ์œผ๋กœ ๋๋‚˜์ง€ ์•Š์„ ๊ฒฝ์šฐ์— ์‚ฌ์šฉํ•  ์ˆ˜ ์—†๋‹ค. ์ด๋•Œ Nothing ํƒ€์ž…์„ ์‚ฌ์šฉํ•ด์ฃผ๋ฉด ํ•จ์ˆ˜๊ฐ€ ์ •์ƒ์ ์œผ๋กœ ๋๋‚˜์ง€ ์•Š์Œ์„ ํ‘œํ˜„ํ•  ์ˆ˜ ์žˆ๋‹ค. ์˜ค์ง ๋ฐ˜ํ™˜ ํƒ€์ž…์œผ๋กœ๋งŒ ์“ธ ์ˆ˜ ์žˆ์œผ๋ฉฐ, ์–ด๋– ํ•œ ๊ฐ’๋„ ๊ฐ€์ง€์ง€ ์•Š๋Š”๋‹ค.

์ปฌ๋ ‰์…˜๊ณผ ๋ฐฐ์—ด

fun readNumbers(reader: BufferedReader): List<Int?> {
	val result = ArrayList<Int?>()
	for (line in reader.lineSequence()) {
		try {
			val number = line.toInt()
			result.add(number)
		}
		catch(e: NumberFormatException) {
			result.add(null)
		}
	}
	return result
}

List<Int?>๋Š” Int?: ํƒ€์ž…์„ ๊ฐ€์ง€๊ณ  ์žˆ๋Š” ๋ฐฐ์—ด์ด๋‹ค. List<Int>?์™€์˜ ์ฐจ์ด๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™๋‹ค.

Read-only and mutable collections

๊ธฐ๋ณธ์ ์œผ๋กœ ์ฝ”ํ‹€๋ฆฐ์ด ๊ฐ€์ง„ ์ปฌ๋ ‰์…˜์€ ์ „๋ถ€ ๋ณ€๊ฒฝํ•  ์ˆ˜ ์—†๋Š” ์ปฌ๋ ‰์…˜์ด๋‹ค. ๊ทธ๋Ÿฐ๋ฐ MutableCollection์„ ์‚ฌ์šฉํ•˜๋ฉด ์ปฌ๋ ‰์…˜์„ ๋ณ€๊ฒฝํ•  ์ˆ˜ ์žˆ๋Š” ์ปฌ๋ ‰์…˜์„ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค. val๊ณผ var์„ ๋ถ„๋ฆฌํ•œ ๊ฒƒ์ฒ˜๋Ÿผ, ์ฝ๊ธฐ ์ „์šฉ ์ปฌ๋ ‰์…˜๊ณผ ๋ณ€๊ฒฝ ๊ฐ€๋Šฅ ์ปฌ๋ ‰์…˜์„ ๋ถ„๋ฆฌํ•˜๋ฉด ํ”„๋กœ๊ทธ๋žจ ์•ˆ์˜ ๋ฐ์ดํ„ฐ์— ๋ฌด์Šจ ์ผ์ด ์ผ์–ด๋‚˜๊ณ  ์žˆ๋Š”์ง€ ๋” ์‰ฝ๊ฒŒ ์ดํ•ดํ•  ์ˆ˜ ์žˆ๋‹ค. ๋งŒ์•ฝ Collection์„ ์‚ฌ์šฉํ•œ๋‹ค๋ฉด ๋ฐ์ดํ„ฐ์˜ ๋ณ€๊ฒฝ์€ ์ผ์–ด๋‚˜๊ณ  ์žˆ์ง€ ์•Š์Œ์„, MutableCollection์— ๋ฐ์ดํ„ฐ๋ฅผ ๋„˜๊ฒจ์ค€๋‹ค๋ฉด ๋ณ€๊ฒฝ์„ ์˜๋„ํ•˜๊ณ  ์žˆ๋Š” ๊ฒƒ์ž„์„ ์•Œ ์ˆ˜ ์žˆ๋‹ค.

fun <T> copyElements(source: Collection<T>, target: MutableCollection<T>) {
	for (item in source) {
		target.add(item) **//๋ณ€๊ฒฝ ๊ฐ€๋Šฅํ•œ ์ปฌ๋ ‰์…˜์— ๋„˜๊ฒจ์คŒ**
	}
}
>>> val source: Collectionthread-safe<Int> = arrayListOf(3, 5, 7)
>>> val target: MutableCollection<Int> = arrayListOf(1)
>>> copyElements(source, target)
>>> println(target)
[1, 3, 5, 7]

๊ทธ๋ ‡๋‹ค๊ณ  ํ•ด์„œ collection์ด ๊ฐ€๋ฆฌํ‚ค๋Š” ๋ฐ์ดํ„ฐ๊ฐ€ ํ•ญ์ƒ ๋ณ€๊ฒฝ ๋ถˆ๊ฐ€๋Šฅํ•˜๋‹ค๋Š” ๊ฒƒ์€ ์•„๋‹ˆ๋‹ค. ๋‹ค๋ฅธ ๋ ˆํผ๋Ÿฐ์Šค๋Š” ๋ณ€๊ฒฝ ๊ฐ€๋Šฅํ•œ MutableCollection์ผ ์ˆ˜๋„ ์žˆ๋‹ค! ๊ทธ๋Ÿฐ๋ฐ ๋‹ค์–‘ํ•œ ๋ ˆํผ๋Ÿฐ์Šค๊ฐ€ ํ•˜๋‚˜์˜ ๋ฐ์ดํ„ฐ๋ฅผ ๊ฐ€๋ฆฌํ‚ค๊ณ  ์žˆ์„ ๋•Œ ConcurrentModificationException์ด ๋ฐœ์ƒํ•  ์ˆ˜ ์žˆ์œผ๋ฏ€๋กœ, ์ฝ๊ธฐ ์ „์šฉ๊ณผ ๋ณ€๊ฒฝ ๊ฐ€๋Šฅ์„ ๊ตฌ๋ถ„ํ•ด์ฃผ๋Š” ๊ฒƒ์ด ํ•„์ˆ˜์ ์ด๋‹ค.

Kotlin collections and Java

์ฝ”ํ‹€๋ฆฐ๊ณผ ์ž๋ฐ” ์ปฌ๋ ‰์…˜์€ ์„œ๋กœ ์ƒํ˜ธ์ž‘์šฉํ•˜๋Š” ์ธํ„ฐํŽ˜์ด์Šค๊ฐ€ ์กด์žฌํ•œ๋‹ค. ์ด ์‚ฌ์ด์—๋Š” ๋ณ€ํ™˜์ด ํ•„์š” ์—†์œผ๋ฉฐ, ๋ฐ์ดํ„ฐ๋ฅผ ๋ณต์‚ฌํ•˜๊ฑฐ๋‚˜ wrapper๋ฅผ ์ƒ์„ฑํ•  ํ•„์š”๊ฐ€ ์—†๋‹ค. ๊ทธ๋Ÿฐ๋ฐ ๋ชจ๋“  ์ž๋ฐ” ์ปฌ๋ ‰์…˜์—๋Š” 2๊ฐœ์˜ ์ฝ”ํ‹€๋ฆฐ ์ปฌ๋ ‰์…˜, ์ฆ‰ ์ฝ๊ธฐ ์ „์šฉ๊ณผ ๋ณ€๊ฒฝ ๊ฐ€๋Šฅํ•œ ์ปฌ๋ ‰์…˜์ด ์กด์žฌํ•œ๋‹ค.

์ž๋ฐ”๋Š” ์ฝ๊ธฐ ์ „์šฉ๊ณผ ๋ณ€๊ฒฝ ๊ฐ€๋Šฅ์„ ๊ตฌ๋ถ„ํ•˜์ง€ ์•Š๊ธฐ ๋•Œ๋ฌธ์— ์ฝ๊ธฐ ์ „์šฉ ์ปฌ๋ ‰์…˜์„ ๋ณ€๊ฒฝํ•˜๊ฒŒ ๋  ์ˆ˜๋„ ์žˆ๋‹ค. ์ด๋•Œ ์ฝ”ํ‹€๋ฆฐ์€ ์ฝ๊ธฐ ์ „์šฉ ์ปฌ๋ ‰์…˜์„ ์ž๋ฐ”๊ฐ€ ๋ณ€๊ฒฝํ•˜๋ ค๋Š” ๊ฒฝ์šฐ ๊ทธ ํ˜ธ์ถœ์„ ๊ฑฐ์ ˆํ•œ๋‹ค.

/* Java */
// CollectionUtils.java
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
// collections.kt
fun printInUppercase(list: List<String>) {
	println(CollectionUtils.uppercaseAll(list))
	println(list.first())
}
>>> val list = listOf("a", "b", "c")
>>> printInUppercase(list)
[A, B, C]
A

๋”ฐ๋ผ์„œ ์ฝ”ํ‹€๋ฆฐ ์ปฌ๋ ‰์…˜์„ ์ž๋ฐ”์—๊ฒŒ ๋„˜๊ฒจ์ค„ ๋•Œ๋Š” ์ •ํ™•ํ•œ ํŒŒ๋ผ๋ฏธํ„ฐ ํƒ€์ž…์„ ๊ฐœ๋ฐœ์ž๊ฐ€ ์ž‘์„ฑํ•ด์•ผ ํ•œ๋‹ค.

๋ฐฐ์—ด

์ฝ”ํ‹€๋ฆฐ์—์„œ ๋ฐฐ์—ด์„ ์ƒ์„ฑํ•˜๊ธฐ ์œ„ํ•ด์„œ๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์€ ๊ฒฝ์šฐ๋ฅผ ๊ฑฐ์น  ์ˆ˜ ์žˆ๋‹ค.

  1. arrayOf ํ•จ์ˆ˜๋กœ ๋ฐฐ์—ด์„ ์ƒ์„ฑํ•œ๋‹ค.

  2. arrayOfNulls ํ•จ์ˆ˜๋กœ null์„ ํฌํ•จํ•œ ๋ฐฐ์—ด์„ ๋งŒ๋“ ๋‹ค.

  3. Array ์ƒ์„ฑ์ž๋กœ ๋ฐฐ์—ด๊ณผ ๋žŒ๋‹ค๋ฅผ ๋งŒ๋“ ๋‹ค. ๊ฐ ์š”์†Œ๋“ค์€ ๋žŒ๋‹ค๋กœ ์ดˆ๊ธฐํ™”๋œ๋‹ค. ๋ฐฐ์—ด์€ non-null ์š”์†Œ๋กœ ์ดˆ๊ธฐํ™”ํ•œ๋‹ค.

Last updated