์์ดํ 1. ๊ฐ๋ณ์ฑ์ ์ ํํ๋ผ
(๊ฐ๋ฅํ๋ฉด) var ๋ณด๋ค๋ val ์ฌ์ฉ
(๊ฐ๋ฅํ๋ฉด) mutable ํ๋กํผํฐ๋ณด๋ค๋ immutable ํ๋กํผํฐ ์ฌ์ฉ
mutable ๊ฐ์ฒด๋ฅผ ์ธ๋ถ์ ๋ ธ์ถํ์ง ๋ง์.
class Test {
fun calculate(): Int {
println("Cal...")
return 42
}
val fizz = calculate()
val buzz
get() = calculate()
}
fun main() {
println(Test().buzz)
}
//Cal...
//Cal...
//42
์ฝ๊ธฐ ์ ์ฉ ์ปฌ๋ ์ ์ Mutable ์ปฌ๋ ์ ์ผ๋ก ๋ค์ด์บ์คํ ํ๋ฉด ์๋๋ค.
์ฝ๊ธฐ ์ ์ฉ์์ mutable๋ก ๋ณ๊ฒฝํด์ผ ํ๋ค๋ฉด, ๋ณต์ ๋ฅผ ํตํด ์๋ก์ด mutable ์ปฌ๋ ์ ์ ์์ฑํ์.
val list = listOf(1, 2, 3)
val mutableList = list.toMutableList()
mutable ๊ฐ์ฒด๋ ์์ธกํ๊ธฐ ์ด๋ ค์ฐ๋ฉฐ ์ํํ๋ค๋ ๋จ์ ์ด ์๊ณ , immutable ๊ฐ์ฒด๋ ๋ณ๊ฒฝํ ์ ์๋ค๋ ๋จ์ ์ด ์๋ค.
๋ฐ๋ผ์, immutable ๊ฐ์ฒด๋ ์์ ์ ์ผ๋ถ๋ฅผ ์์ ํ ์๋ก์ด ๊ฐ์ฒด๋ฅผ ๋ง๋ค์ด๋ด๋ ๋ฉ์๋๋ฅผ ๊ฐ์ ธ์ผ ํ๋ค.
Int๋ immutable์ด์ง๋ง ๋ด๋ถ์ ์ผ๋ก plus(), minus() ๋ฑ ์์ ์ ์์ ํ ์๋ก์ด Int๋ฅผ ๋ฆฌํดํ๋ค.
public operator fun plus(other: Int): Int
์ฐ๋ฆฌ๊ฐ ์ง์ ๋ง๋๋ immutable ๊ฐ์ฒด๋ ์์ ๋น์ทํ ํํ๋ก ์๋ํด์ผ ํฉ๋๋ค.
data class User(val name: String, val surname: String) {
fun witName(name: String) = User(name, surname)
}
์์ดํ 2. ๋ณ์์ ์ค์ฝํ๋ฅผ ์ต์ํํ๋ผ
ํ๋ก๊ทธ๋จ์ ์ถ์ ํ๊ณ ๊ด๋ฆฌํ๊ธฐ ์ฝ๊ธฐ ๋๋ฌธ์ด๋ค.
๋ณ์๋ฅผ ์ ์ํ ๋ ์ด๊ธฐํ๋๋ ๊ฒ์ด ์ข๋ค.
// ๋์ ์์
var user: User
for(i in users.indices){
user = users[i]
print("User at $i is $user")
}
// ์กฐ๊ธ ์ข์ ์์
for(i in users.indices){
var user = users[i]
print("User at $i is $user")
}
// ์ข์ ์์
for((i, user) in users.withIndex()){
print("User at $i is $user")
}
์์ดํ 3. ์ต๋ํ ํ๋ซํผ ํ์ ์ ์ฌ์ฉํ์ง ๋ง๋ผ
ํ๋ซํผ ํ์ : ๋ค๋ฅธ ํ๋ก๊ทธ๋๋ฐ ์ธ์ด์์ ์ ๋ฌ๋์ด nullable์ธ์ง ์๋์ง ์ ์ ์๋ ํ์
- ์ฝํ๋ฆฐ์ ์ฃผ์ ๊ธฐ๋ฅ ์ค ํ๋๋ Null-Safety ์ด๋ค.
- ํ๋ซํผ ํ์ ์ ์ฌ์ฉํ๋ ์ฝ๋ ์ธ ํ์ฉํ๋ ๊ณณ๊น์ง ์ํฅ์ ์ค ์ ์์ผ๋ฏ๋ก ๊ฐ๊ธ์ ์ ๊ฑฐํ๋ ๊ฒ์ด ์ข๋ค.
- ์ฝํ๋ฆฐ์ nullable -> ?, not null -> !!
์์ดํ 4. inferred ํ์ ์ผ๋ก ๋ฆฌํดํ์ง ๋ง๋ผ
- ์ฝํ๋ฆฐ ํ์ ์ถ๋ก ์ ์์ง ๋ง์์ผ ํ ์ ์ inferredType์ ์ ํํ ์ฐ์ธก์ ์๋ ํผ์ฐ์ฐ์์ ๋ง๋ ํ์ ์ด ์ค์ ๋๋ค๋ ๊ฒ์ด๋ค.
- ์ถ๊ฐ์ ์ผ๋ก ์ฝํ๋ฆฐ์์ ํ์ ์ถ๋ก ์ ๋ณ์ ์ด๊ธฐํ์ ๊ทธ ํ์ ์ ์ถ๋ก ํ๋ค.
- ์๋ฐ๋ ์๋ฐ10๋ถํฐ ํ์ ์ถ๋ก ์ ๋์ ํ์ฌ ์ง์ํ๋ค.
- ํ์ ์ ํ์คํ๊ฒ ์ง์ ํด์ผ ํ๋ ๊ฒฝ์ฐ์๋ ๋ช ์์ ์ผ๋ก ํ์ ์ ์ง์ ํด์ผ ํ๋ค๋ ์์น์ ๊ฐ์ง์. (๊ณต๊ฐ API, ๋ผ์ด๋ธ๋ฌ๋ฆฌ ๋ฑ)
์์ดํ 5. ์์ธ๋ฅผ ํ์ฉํด ์ฝ๋์ ์ ํ์ ๊ฑธ์ด๋ผ
ํ์คํ๊ฒ ์ด๋ค ํํ๋ก ๋์ํด์ผ ํ๋ ์ฝ๋๊ฐ ์๋ค๋ฉด, ์์ธ๋ฅผ ํ์ฉํด ์ ํ์ ๊ฑธ์ด์ฃผ๋ ๊ฒ์ด ์ข๋ค.
์ฝํ๋ฆฐ์์๋ ์ฝ๋์ ๋์์ ์ ํ์ ๊ฑธ ๋ ๋ค์ ํค์๋๋ฅผ ์ฌ์ฉํ ์ ์๋ค.
- require: ์๊ท๋จผํธ ์ ํ
- check: ์ํ์ ๊ด๋ จ๋ ๋์ ์ ํ
- assert: ์ด๋ค ๊ฒ์ด true์ธ์ง ํ์ธํ ์ ์๊ณ , ํ ์คํธ ๋ชจ๋์์๋ง ์๋
fun decode(encoded: ByteArray): ByteArray {
require(isBase62Encoding(encoded)) { "Input is not encoded correctly" }
val prepared = translate(encoded, lookup)
return convert(prepared, TARGET_BASE, STANDARD_BASE)
}
์์ ๊ฐ์ ์ ์ฝ์ฌํญ์ ๋ํ ์ฅ์ ์?
- ๋ฌธ์๋ฅผ ์ฝ์ง ์์ ๊ฐ๋ฐ์๋ ์์๋๋ ๋ฌธ์ ๋ฅผ ํ์ธํ ์ ์๋ค.
- ์์ํ์ง ๋ชปํ ๋์์ ํ๋ ๊ฒ์ ์์ธ๋ฅผ throwํ๋ ๊ฒ๋ณด๋ค ์ํํ๊ณ , ์ํ๋ฅผ ๊ด๋ฆฌํ๋ ๊ฒ์ด ํ๋ค๋ค.
- ์ฝ๋๊ฐ ์ด๋์ ๋ ์์ฒด์ ์ผ๋ก ๊ฒ์ฆ์ด ๋๋ค.
์๊ท๋จผํธ (require)
- ํจ์๋ฅผ ์ ์ํ ๋ ํ์ ์์คํ ์ ํ์ฉํด์ ์๊ท๋จผํธ์ ์ ํ์ ๊ฑฐ๋ ์ฝ๋
- IllegalArgumentException์ throwํ๋ค.
์ํ (check)
๊ตฌ์ฒด์ ์ธ ์กฐ๊ฑด์ ๋ง์กฑํ ๋๋ง ํจ์๋ฅผ ์ฌ์ฉํ ์ ์๊ฒ ํด์ผ ํ ๋,
- ์ด๋ค ๊ฐ์ฒด๊ฐ ๋ฏธ๋ฆฌ ์ด๊ธฐํ๊ฐ ๋์ด ์์ด์ผ๋ง ์ฒ๋ฆฌ๋ฅผ ํ๊ฒ ํ๊ณ ์ถ์ ํจ์
- ์ฌ์ฉ์๊ฐ ๋ก๊ทธ์ธ์ ํ์๋๋ง ์ฒ๋ฆฌ๋ฅผ ํ๊ฒ ํ๊ณ ์ถ์ ํจ์
- ๊ฐ์ฒด๋ฅผ ์ฌ์ฉํ ์ ์๋ ์์ ์ ์ฌ์ฉํ๊ณ ์ถ์ ํจ์
- IllegalStateException์ throwํ๋ค.
assert
- ์ผ๋ฐ์ ์ผ๋ก ๋จ์ ํ ์คํธ์์ ์ฌ์ฉ
- ํ๋ก๋์ ํ๊ฒฝ์ ์ฝ๋์์๋ ์ฌ์ฉ์ด ๊ฐ๋ฅ
// ๋จ์ ํ
์คํธ
assertThat(...)
assertEquals(...)
// ํ๋ก๋์
์ฝ๋
fun pop(index: Int, numbers: MutableList<Int>) {
val size = numbers.size
numbers.removeAt(index)
assert(size == numbers.size)
}
์์ดํ 6. ์ฌ์ฉ์ ์ ์ ์ค๋ฅ๋ณด๋ค๋ ํ์ค ์ค๋ฅ๋ฅผ ์ฌ์ฉํ๋ผ
ํ์ค ๋ผ์ด๋ธ๋ฌ๋ฆฌ์ ์์ธ๋ฅผ ์ฌ์ฉํ๋ฉด ๋ค์๊ณผ ๊ฐ์ ์ด์ ์ด ์๋ค:
- ๋๋ถ๋ถ์ ๊ฐ๋ฐ์๊ฐ ์ด๋ฏธ ์ ์๊ณ ์๋ ์์ธ๋ค์ด๋ค.
- API๋ฅผ ๋ ์ฝ๊ฒ ์ดํดํ๊ณ ์ฌ์ฉํ ์ ์๋ค.
- ์์ธ ์ฒ๋ฆฌ์ ๋ํ ์ผ๊ด์ฑ์ ์ ์งํ ์ ์๋ค.
์ปค์คํ ์์ธ๊ฐ ํ์ํ ๊ฒฝ์ฐ๋?
- ํ์ค ๋ผ์ด๋ธ๋ฌ๋ฆฌ์ ์์ธ๋ก ํํํ๊ธฐ ๊น๋ค๋ก์ด ๊ฒฝ์ฐ
- ํน์ ๋น์ฆ๋์ค ๋๋ฉ์ธ์ ํนํ๋ ์์ธ๊ฐ ํ์ํ ๊ฒฝ์ฐ
- ๋ณด์ ํธ๋์ญ์ , ์ฌ์๋ ๋ฑ์ด ํ์ํ ๊ฒฝ์ฐ
- ํด๋ผ์ด์ธํธ ๋ถ๊ธฐ ์ฒ๋ฆฌ๋ฅผ ์ํ ์๋ฌ ์ฝ๋ ํ์ฉ
์์ดํ 7. ๊ฒฐ๊ณผ ๋ถ์กฑ์ด ๋ฐ์ํ ๊ฒฝ์ฐ null๊ณผ Failure๋ฅผ ์ฌ์ฉํ๋ผ
๊ฒฐ๊ณผ ๋ถ์กฑ์ ์ฒ๋ฆฌํ๋ ๋ ๊ฐ์ง ๋ฐฉ๋ฒ
1. null ๋๋ Failure ๋ฐํ
- null: ๊ฒฐ๊ณผ๊ฐ ์์์ ๋ํ๋ด๊ธฐ ์ํด ๋ฆฌํด
- Failure: sealed class๋ฅผ ์ฌ์ฉํด ์คํจ ์ํ๋ฅผ ๋ช ํํ๊ฒ ํํ (Success, Failure)
- ์ฅ์ : Failure๋ฅผ ์ฌ์ฉํ๋ฉด ์คํจ ์์ธ์ ๋ด์ ์ ์๊ณ , when์ ํตํด ์ํ๋ฅผ ๋ช ํํ๊ฒ ๋ถ๋ฆฌํ์ฌ ์ฒ๋ฆฌํ ์ ์๋ค.
- ๋จ์ : null์ ๋ช ์์ ์ด์ง ์๊ณ , NPE(Null Pointer Exception) ๋ฐ์์ ์ํ์ด ์๋ค.
2. ์์ธ throw
- ์ฅ์ : ์์ธ๋ฅผ ๋์ง๋ฉด ํธ์ถ์์๊ฒ ์ค๋ฅ๊ฐ ์ ๋ฌ๋๋ฉฐ ์ฒ๋ฆฌ๊ฐ ๊ฐ์ ๋๋ค.
- ๋จ์ : ์์ธ๋ ํ๋ก๊ทธ๋จ ํ๋ฆ์ ๋ฐฉํดํ๊ณ , ๋ฌด๋ถ๋ณํ๊ฒ ์ฌ์ฉํ๋ฉด ์ฝ๋์ ๊ฐ๋ ์ฑ์ด ์ ํ๋ ์ ์๋ค.
+ ์ถ๊ฐ
Success, Failure ๋ฅผ ์๋ฏธํ๋ ์ฝํ๋ฆฐ์ Result ํด๋์ค
์์ดํ 8. ์ ์ ํ๊ฒ null์ ์ฒ๋ฆฌํ๋ผ.
null์ ์ต๋ํ ๋ช ํํ ์๋ฏธ๋ฅผ ๊ฐ๋ ๊ฒ์ด ์ข๋ค.
String.toIntOrNull() // String์ Int๋ก ์ ์ ํ๊ฒ ๋ณํํ ์ ์์ผ๋ฉด null ๋ฆฌํด
Iterable<T>.firstOrNull(() → Boolean) // ์ฃผ์ด์ง ์กฐ๊ฑด์ ๋ง๋ ์์๊ฐ ์์ผ๋ฉด null ๋ฆฌํด
nullable ํ์ ์ ์ฒ๋ฆฌํ ์ ์๋ ๋ฐฉ๋ฒ
- ?.(safe call), ์ค๋งํธ ์บ์คํ , Elvis ์ฐ์ฐ์ ๋ฑ ํ์ฉ
- ์ค๋ฅ throw
- ํจ์, ํ๋กํผํฐ๋ฅผ ๋ฆฌํฉํฐ๋งํด์ nullable ํ์ ์ด ๋์ค์ง ์๊ฒ ๋ฐ๊พผ๋ค.
not-null assertion (!!)
- !! ์ ์ฌ์ฉํ๋ฉด ์๋ฐ์์ nullable์ ์ฒ๋ฆฌํ ๋ ๋ฐ์ํ ์ ์๋ NPE ๋ฌธ์ ๊ฐ ๋์ผํ๊ฒ ๋ฐ์ํ๋ค.
- ํ์คํ ์ํฉ์ด ์๋๋ผ๋ฉด ์ฌ์ฉ์ ์ง์ํ์.
์๋ฏธ ์๋ nullability ํผํ๊ธฐ
nullability๋ ์ด๋ป๊ฒ๋ ์ ์ ํ๊ฒ ์ฒ๋ฆฌํด์ผ ํ๋ฏ๋ก ์ถ๊ฐ ๋น์ฉ์ด ๋ฐ์ํ๊ธฐ์ ๊ฐ๋ฅํ๋ค๋ฉด ์ฌ์ฉํ์ง ์๋ ๊ฒ์ด ์ข๋ค.
- ํด๋์ค์์ค nullability์ ๋ฐ๋ผ ์ฌ๋ฌ ํจ์๋ฅผ ๋ง๋ค์ด์ ์ ๊ณตํ ์ ์๋ค. (List<T> ์ get, getOrNull)
- ์ด๋ค ๊ฐ์ด ํด๋์ค ์์ฑ ์ดํ ๊ฐ์ด ์ค์ ๋๋ค๋ ๋ณด์ฅ์ด ์๋ค๋ฉด, lateinit ํ๋กํผํฐ์ notNull ๋ธ๋ฆฌ๊ฒ์ดํธ๋ฅผ ์ฌ์ฉํ๋ผ.
- ์ปฌ๋ ์ ์์๋ null์ด ์๋ ๋น ์ปฌ๋ ์ ์ ๋ฐํํ๋ผ.
lateinit ํ๋กํผํฐ
- ๋์ค์ ์์ฑ์ ์ด๊ธฐํํ ์ ์๋, lateinit ํ์ ์ → ํ๋กํผํฐ๊ฐ ์ดํ ์ค์ ๋ ๊ฒ์์ ๋ช ์ํ๋ ํ์ ์
- ์ฆ, ์ฒ์ ์ฌ์ฉํ๊ธฐ ์ ์ ๋ฐ๋์ ์ด๊ธฐํ๊ฐ ๋์ด ์์ ๊ฒฝ์ฐ์๋ง ์ฌ์ฉ
- ์๋์น ์๊ฒ ์ฌ์ฉ๋์ด ์์ธ๊ฐ ๋ฐ์ํ๋ค๋ฉด, ๊ทธ ์ฌ์ค์ ์์์ผ ํ๋ฏ๋ก ์์ธ๊ฐ ๋ฐ์ํ๋ ๊ฒ์ ์คํ๋ ค ์ข์ ์ผ
์์ดํ 9. use๋ฅผ ์ฌ์ฉํ์ฌ ๋ฆฌ์์ค๋ฅผ ๋ซ์๋ผ
์ฝํ๋ฆฐ/JVM์์ ์ฌ์ฉํ๋ ์๋ฐ ํ์ค ๋ผ์ด๋ธ๋ฌ๋ฆฌ ์ค ๋ ์ด์ ํ์ํ์ง ์์ ๋ close ๋ฉ์๋๋ฅผ ์ฌ์ฉํด์ ๋ช ์์ ์ผ๋ก ์ข ๋ฃ๋ฅผ ํด์ผํ๋ ๋ฆฌ์์ค๊ฐ ์๋ค.
- InputStream, OutputStream
- java.sql.Connection
- Java.io.Reader
์์ ๋ฆฌ์์ค๋ ์ต์ข ์ ์ผ๋ก ๋ ํผ๋ฐ์ค๊ฐ ์์ด์ง ๋ GC๊ฐ ์ฒ๋ฆฌํ์ง๋ง, ์ฝ๊ฒ ์ฒ๋ฆฌ๋์ง ์๊ณ ๋๋ฆฌ๋ฉฐ Resource Leak๊ณผ ๊ฐ์ ๋ฌธ์ ๋ ๋ฐ์ํ ์ฌ์ง๊ฐ ์๋ค.
// ๊ฐ๋
์ฑ
fun countCharactersInFile(path: String): Int {
val reader = BufferedReader(FileReader(path))
try {
return reader.lineSequence().sumOf { it.length }
} finally {
reader.close() // ์์ธ ๋ฐ์ํ ์ ์์
}
}
fun countCharactersInFile(path: String): Int {
val bufferedReader = BufferedReader(FileReader(path))
bufferedReader.use { reader ->
return reader.lineSequence().sumOf { it.length }
}
}
// ๊ฐ์ 1.
fun countCharactersInFile(path: String): Int {
BufferedReader(FileReader(path)).use { reader ->
return reader.lineSequence().sumOf { it.length }
}
}
// ๊ฐ์ 2.
fun countCharactersInFile(path: String): Int {
File(path).useLines { lines ->
return lines.sumOf { it.length }
}
}
์์ดํ 10. ๋จ์ ํ ์คํธ๋ฅผ ๋ง๋ค์ด๋ผ
๋จ์ ํ ์คํธ๋ฅผ ํตํด ํ์ธํ ์ ์๋ ์ ๋ณด
- ์ผ๋ฐ์ ์ธ ์ ์ค ์ผ์ด์ค(happy path)
- ์ผ๋ฐ์ ์ธ ์ค๋ฅ ์ผ์ด์ค์ ์ ์ฌ์ ์ธ ๋ฌธ์ (fail)
- ์์ธ ์ผ์ด์ค์ ์๋ชป๋ ์๊ท๋จผํธ (range, nullable, ...)
@Test
fun `์ ํจํ์ง ์์ ์ธ๋ฑ์ค์ ์ ๊ทผํ๋ฉด ์์ธ๊ฐ ๋ฐ์ํด์ผ ํ๋ค`() {
val numbers = listOf(1, 2, 3, 4, 5)
// ์ ํจํ์ง ์์ ์ธ๋ฑ์ค(์: ์ธ๋ฑ์ค 10)๋ ์์ธ๋ฅผ ๋ฐ์์์ผ์ผ ํ๋ค.
assertThrows(IndexOutOfBoundsException::class.java) {
get(numbers, 6) // ๋ฒ์ ๋ฐ์ ์ธ๋ฑ์ค
}
}
'Kotlin' ์นดํ ๊ณ ๋ฆฌ์ ๋ค๋ฅธ ๊ธ
์ดํํฐ๋ธ ์ฝํ๋ฆฐ - 3์ฅ ์ฌ์ฌ์ฉ์ฑ (0) | 2025.06.25 |
---|---|
์ดํํฐ๋ธ ์ฝํ๋ฆฐ 2์ฅ - ๊ฐ๋ ์ฑ (2) | 2025.06.14 |
Kotlin Collection (1) - (forEach, onEach, filter, filterNot, map, mapNotNull, flatMap, fold, reduce, sum, sumOf) (0) | 2025.02.09 |
Kotlin for iterator (1) | 2025.01.17 |
Kotlin - Scope functions (let, with, run, apply, also) (0) | 2024.12.15 |
๋๊ธ