์ฝ๋ฉ ๊ท์น ์ ํ๊ธฐ
๊ฐ๋ฐ ์ ๋ฌด์์ ๊ท์น์ ์ ํ๋ ๊ฒ์ด ์ผ๋ง๋ ์ค์ํ์ง๋ ๋ชจ๋๊ฐ ์๊ณ ์์ ๊ฒ์ด๋ค.
ํผ์ ๊ฐ๋ฐํ๋ ํ๋ก์ ํธ๋ผ๋ฉด ํฌ๊ฒ ์ค์ํ์ง ์๋ค๊ณ ์๊ฐํ ์ ์์ง๋ง, ์ธ์์ด 1๋ช ์ด์์ธ ์๊ฐ๋ถํฐ ์ํฉ์ด ๋ฌ๋ผ์ง๋ค. ๊ฐ์ ๋ฆฌํฌ์งํ ๋ฆฌ์ ์ฌ๋ฌ ๋ช ์ด ๋์์ ์์ ํ๊ฒ ๋๋ฉด ์๋ก ๋ค๋ฅธ ๊ฐ๋ฐ ์คํ์ผ๊ณผ ๊ด์ ์ด ์ถฉ๋ํ ์๋ฐ์ ์๊ธฐ ๋๋ฌธ์ด๋ค. ๋ฐ๋ผ์ ์ต์ํ์ ์ฝ๋ฉ ๊ท์น์ ์ ํด๋๊ณ ์งํค๋ ๊ฒ์ด ์ข์ ๊ฐ๋ฐ ๋ฌธํ๋ฅผ ๋ง๋๋ ์์์ด๋ผ๊ณ ์๊ฐํ๋ค.
์ฝ๋ฉ ๊ท์น์ ์ ํ๋ฉด ์ข์ ์ด์
-
์ฝ๋์ ์ปค๋ฎค๋์ผ์ด์ ์ด ์ฌ์์ง๋ค.
-
์ ๊ท ์ ์ฌ์๋ ์ธ๋ถ ํ์ ์๊ฐ ๋ค์ด์๋ ๋น ๋ฅด๊ฒ ์ ์ ๊ฐ๋ฅํ๋ค.
-
์ฝ๋ ๋ฆฌ๋ทฐ ์ ๊ท์น ๊ธฐ๋ฐ์ผ๋ก ๋ ผ์๊ฐ ๊ฐ๋ฅํ๋ค.
-
์ฝ๋ ํ์ง์ด ์์ฐ์ค๋ฝ๊ฒ ๋์์ง๊ณ , ๊ฐ๋ ์ฑ์ด ๊ฐ์ ๋๋ค.
-
์ ์ ๋ถ์ ๋๊ตฌ(์: Ktlint)์ ์ฐ๊ณํ์ฌ ์ฝ๋ ํ์ง์ ๊ฐ์ ํ ์ ์๋ค.
๋์ ๊ฒฝ์ฐ Kotlin, Java ๊ธฐ๋ฐ์ผ๋ก ๊ฐ๋ฐ์ ์ฃผ๋ก ํด์์ผ๋ฉฐ, ์ต๊ทผ์๋ AI ๊ด๋ จ ๊ฐ๋ฐ์ ์งํํ๊ณ ์๋ค.
ํนํ Kotlin์ ์ฌ์ฉํ ๊ฒฝ์ฐ, ๊ธฐ๋ณธ์ ์ธ ์ฝ๋ฉ ๊ท์น์ ์ ๋ฆฌํ๊ณ ์ํฉ์ ๋ง๊ฒ ์ถ๊ฐ ๊ท์น์ ์ ์ํ๋ ๊ฒ์ด ํจ๊ณผ์ ์ด๋ผ๊ณ ์๊ฐํ๋ค.
์๋ฅผ ๋ค์ด ๋ค์๊ณผ ๊ฐ์ ์ฝ๋๊ฐ ์์ ์ ์๋ค.
isEmpty:Boolean = false
//์๋ 2๊ฐ์ง๋ ๋์ผํ๊ฒ ๋์ํ๋๋ฐ sonarqube ์์๋ ์ฒซ๋ฒ์งธ๋ ํต๊ณผ ์๋๋ ์คํจ๋ก ๋์จ๋ค.
//๊ฐ์ธ์ ์ผ๋ก๋ ๋๋ฒ์งธ๊ฐ ๊ฐ๋
์ฑ ์ธก๋ฉด์์๋ ์ข๋ค๊ณ ๋ณด์ง๋ง ์ํฉ์ ๋ฐ๋ผ์ ๊ท์น์ ์ ํ๋ฉด ๋๋ค.
if(!isEmpty)
if(isEmpty == false)
์ ๋ ์ฝ๋๋ ๊ฐ์ ๋์์ ํ์ง๋ง SonarQube ๊ธฐ์ค์์๋ ์ฒซ ๋ฒ์งธ๊ฐ ํต๊ณผ๋๊ณ ๋ ๋ฒ์งธ๋ ์คํจํ๋ ๊ฒฝ์ฐ๊ฐ ์๋ค. ๊ฐ๋ ์ฑ ๊ด์ ์์๋ ๋ ๋ฒ์งธ๊ฐ ๋ช ํํ๋ค๊ณ ๋ณด์ง๋ง, ํ์ ์ํฉ๊ณผ ๋๊ตฌ ๊ธฐ์ค์ ๋ฐ๋ผ ๊ท์น์ ํต์ผํด์ผ ํ๋ค
Kotlin ์ฝ๋ฉ ๊ท์น ์ฃผ์ ํฌ์ธํธ
-
Kotlin ๊ธฐ๋ณธ ์คํ์ผ ๊ฐ์ด๋๋ฅผ ๋ฐ๋ฅธ๋ค.
-
๋ณ์๋ช , ํด๋์ค๋ช ์๋ ์ธ๋์ค์ฝ์ด(_) ์ฌ์ฉ์ ์ง์ํ๋ค.
-
์ฃผ์์ KDoc์ ํ์ฉํ์ฌ ์ฝ๊ธฐ ์ฌ์ด ๋ฌธ์๋ฅผ ์์ฑํ๋ค.
-
Klint, GitHub Action ๊ฐ์ ์๋ํ ๋๊ตฌ๋ฅผ ํ์ฉํ์ฌ ์์ค Push ์์ ์์ Fail ์ฒดํฌ๋ฅผ ํ๋๋ก ํ๋ค.
-
ํด๋์ค๋ ์ธํฐํ์ด์ค๋ Companion Object๋ฅผ ์ ์ธํ๊ณ ๋ฌธ์ ์ค๋ช ์ ๋ฐ๋์ ํฌํจํ๋ค.
-
if/when ๋ฌธ, while/for ๋ฃจํ๋ ์ผ๊ด์ฑ ์๋ ํฌ๋งท์ ์ ์งํ๋ค.
-
ํด๋์ค ๋ด ๋ฉค๋ฒ์ ์์๋ ์ฝ๊ธฐ ์ ์ฉ → ์ฝ๊ธฐ/์ฐ๊ธฐ → ์ด๊ธฐํ → ์์ฑ์ → ํจ์ ์์ผ๋ก ์ ๋ฆฌํ๋ค.
-
์์ ๊ฐ์ SNAKE_CASE๋ก ์ ์ธํ๊ณ , const ์์์๋ฅผ ์ฌ์ฉํ๋ค.
// GOOD
private val modifiableElementList: MutableList = mutableListOf()
val elementList: List = modifiableElementList
// BAD
private val _elementList: MutableList = mutableListOf()
val elementList: List = _elementList
์ฝ๋ฉํธ
KDOC์ด๋ Dokka ๊ท์น์ ๋ฐ๋ฅธ๋ค.
๋ํ Klint์ github Action ๊ฐ์ ์๋ํ๋ฅผ ํ๋ค๋ฉด ์์ค push ์์ ์์ Fail ์ฒดํฌ๊ฐ ๊ฐ๋ฅํ๊ธฐ ๋๋ฌธ์ ์ฉ์ดํ๋ค.
๋ ๊ฐ์ ๊ฒฝ์ฐ๋ klint๋ฅผ ์ฃผ๋ก ์ฌ์ฉํ๋๋ฐ ๋ฃฐ์ ์ ์ํ๊ณ push ์ ์ฒด ํ๋ฒ ์ฒดํฌ ํ Push๋ฅผ ์งํํ๋ ๊ฒ ๊ฐ๋ค.
ํด๋์ค
๊ฐ ํด๋์ค, ์ธํฐํ์ด์ค ๋๋ ์ค๋ธ์ ํธ๋ companion object ๋ฐ ์ต๋ช ์ค๋ธ์ ํธ๋ฅผ ์ ์ธํ๊ณ ๋ฌธ์ ์ค๋ช ์ ํฌํจํด์ผ ํ๋ค.
๋ฌธ์์๋ ๋ค์๊ณผ ๊ฐ์ ๋ ๊ฐ์ง ์๊ตฌ์ฌํญ์ด ์๋ค.
- Javadoc/Kdoc ๊ท์น์ ๋ฐ๋ฅด์. ์๋ฅผ ๋ค์ด, ์ฝ๋ฉํธ ์คํ์ผ์ "์ด์ด์ผ ํ๋ค./**... */
- ๋จผ์ "์ ํ์ด ๋ฌด์์ธ์ง , ์ ํ์ด ๋ฌด์์ธ์ง"๋ฅผ ์ค๋ช ํ๋ ์งง์ ์์ฝ์ผ๋ก ๋ช ์ฌ ๊ตฌ์ ์ ์์ํ์.
- ๊ทธ๋ค์, ์ ํ์ ๋ฌธ์ฅ์ ์ฌ์ฉ๋ฒ, ์ ํ์ฌํญ ๋ฑ์ ์ค๋ช ํ๊ธฐ ์ํด ์งง์ ์์ฝ์ ๋ฐ๋ฅผ ์ ์๋ค.
์ฐธ๊ณ : ์ค๋ช ์๊ฐ ์๋ ๊ธฐ์กด ํด๋์ค๋ฅผ ์ฐพ์ผ๋ฉด ์ฝ๋ฉํธ๋ฅผ ์์ฑํ์.
์ ์ด ํ๋ฆ
"if"/"when" ํํ/ํํ
- if-message:ํธ์ถ์๊ฐ ๊ฒฐ๊ณผ๋ฅผ ์๋นํ๋ค(์: ํ ๋น, ๋ฐํ ๊ฐ ๋๋ ํจ์ ๋งค๊ฐ ๋ณ์).
- if-expression์ ๋ณธ๋ฌธ์ ๋์ผํ ์ฝ๋ ๋ผ์ธ์ ๋ชจ๋ ์ ํฉํ ๊ฒฝ์ฐ ๋จ์ผ ๋ผ์ธ ํ์(*)์ผ๋ก ๊ฐ ์ ์์ผ๋ฉฐ, ๊ทธ๋ ์ง ์์ ๊ฒฝ์ฐ ๋ ๊ฐ์ง ์ค์ ๋ณธ์ฒด์ ๋ํด ๋ค์ค ๋ผ์ธ ํ์(**)์ ์ ์ฉํด์ผ ํ๋ค.
- if-datement:if-statement ๋ณธ๋ฌธ์ ๋ค์ค ํ ํ์๊ณผ ์ผ์นํด์ผ ํ๋ค.
- (*) ๋จ์ผ ์ค ํ์:์ปฌ๋ธ ๋ธ๋ ์ด์ค({})๋ฅผ ์ฌ์ฉํ๋ฉด ์ ๋๋ค.
- (**) ๋ค์ค ํ ํ์:({})๊ฐ ํ์ํ๋ค.
๋ค์ ์์ ๋ฅผ ์ฐธ์กฐํด ๋ณด์.
// Standard style
if (condition) {
statement()
}
// with else
if (condition) {
statement()
} else {
anotherStatement()
}
// Assignment on a line
val value = if (condition) valueA else valueB
val longLongLongLongLongNameValue = if (condition) valueA else valueB
// Assignment with block
val anotherValue = if (condition) {
longLongLongLongLongLongNameValueA
} else {
longLongLongLongLongLongNameValueB
}
val oneMoreValue =
if (longLongLongCondition) {
longLongLongLongLongLongNameValueA
} else {
longLongLongLongLongLongNameValueB
}
์๋ฅผ ๋ค์ด, ๋ค์ ์ฝ๋๋ ์ง์ํ๋ค.
// BAD: ๊ฐ ๋ณธ๋ฌธ ๋ธ๋ก์๋ ์ถ๊ฐ ๋ช
๋ น๋ฌธ์ด ์์ต๋๋ค. ๋ณธ๋ฌธ์ ํจ์๋ก ์ถ์ถํ์ฌ "if" ํํ์ ๊ฐ์ ์ฌ์ฉํฉ๋๋ค.
val string = if (i % 2 == 0) {
methodCall()
anotherMethodCall()
"even"
} else {
furtherMoreMethodCall()
"odd"
}
- ์์ด ํ ๋น ๋๋ ๋ฐํ ๊ฐ์ ๋ค๋ฅธ ๋ชฉ์ ์ผ๋ก ์ฌ์ฉ๋์ด์๋ ์ ๋ ๊ฒฝ์ฐ ๊ฐ์ด๋ค.
์๋ฅผ ๋ค์ด, ๋ค์ ์ฝ๋๋ ์ง์ํ๋ค.
// BAD: "if" ํํ์์ ์ด๋ค ๊ฐ๋ ๋ฉ์๋ ์ธ์๋ก ์ฌ์ฉํ ์ ์์ต๋๋ค. ๋จผ์ ๋ก์ปฌ ๊ฐ์ผ๋ก ์ ์ํ์ธ์.
function(if (i % 2 == 0) "even" else "odd")
// BAD:
"if" ํํ์์ ์ด๋ค ๊ฐ๋ ํจ์ ์์ ์๋ก ์ฌ์ฉํ ์ ์์ต๋๋ค. ๋จผ์ ๋ก์ปฌ ๊ฐ์ผ๋ก ์ ์ํ์ธ์.
if (i % 2 == 0) {
"even"
} else {
"odd"
}.capitalize()
- ๋ค์ค ์กฐ๊ฑด ๋ธ๋ก์ ๊ฒฝ์ฐ ์ธ์๊ฐ ์๋ ์์ ์ฌ์ฉํด์ผ ํ๋ค. ๊ทธ๋ ์ง ์์ผ๋ฉด ๊ฐ๋ ์ฑ์ด ๊ฐ์ ๋ ํน์ํ ์ํฉ์์๋ง ๋ฌธ์ ์ฌ์ฉํด์ผ ํ๋ค.
// BAD
if (expression1) {
doStuff()
} else if (expression2) {
doOtherStuff()
} else {
doOtherOtherStuff()
}
// GOOD
when {
expression1 -> doStuff()
expression2 -> doOtherStuff()
else -> doOtherOtherStuff()
}
"while"/"for" ๋ฃจํ
๋ง์น ํํ๊ณผ ๊ฐ์ด, ๋ฐ๋ฉด/๋์ฉ ๋ฃจํ๋ ๊ฐ body ๋ธ๋ก์ ๋ํด ๋ธ๋ ์ด์ค๋ฅผ ๊ฐ์ง๊ณ ์์ด์ผ ํ๋ฉฐ ๋ธ๋ก์ ์๋ก์ด ์ ์ผ๋ก ์์ํด์ผ ํ๋ค.
(์กฐ๊ฑด) ๋ฃจํ๊ฐ ์๋ ๋์ {}์ do์(๋ฅผ) ์ฌ์ฉํ์ง ๋ง์.
๋น ๋ธ๋ก
๋น ๋ธ๋ก์ ์ ์ํ๋ ค๋ฉด ์ฒซ ๋ฒ์งธ ์ค์ ์ด๋ฆฐ ๋ธ๋ ์ด์ค๋ฅผ, ๋ ๋ฒ์งธ ์ค์ ๋ซํ ๋ธ๋ ์ด์ค๋ฅผ ๋์.
https://android.github.io/kotlin-guides/style.html#empty-blocks).
try {
doSomething()
} catch (e: Exception) { // break the line for an empty block
}
:
๋ฉค๋ฒ ๋ณ์ ์์
ํด๋์ค, enum, interface, object ๋ฑ์ ๋ฉค๋ฒ ์ค๋๋ ์๋๋ก์ด๋ ์คํ๋์ค์์ ์ ๊ณตํ๋ ์๋ฐ์ ์ค๋ ํฌ๋งทํฐ๋ฅผ ๋ฐ๋ฅธ๋ค.
์ฝํ๋ฆฐ ์ฃผ๋ฌธ ํฌ๋งทํฐ๋ ๊ณต์ ์ปจ๋ฒค์ ๋ฑ์ด ์๊ธฐ ๋๋ฌธ์ ์๋ฐ์ฝ๋๊ฐ ์ฝํ๋ฆฐ์ผ๋ก ์ ํ๋๋ฉด์ ์ผ๊ด์ฑ์ ์ ๊ณตํ๋ ๋ฐ ๋์์ด ๋ ๊ฒ์ด๋ค.
๊ทธ๋ฌ๋ "์ ์ ํ๋"๋ ๋๋ฐ ๋์์ ํ๋์ ์ํด ์คํ๋๊ธฐ ๋๋ฌธ์ ์ต์ข ์ ์ผ๋ก ๋ฐฐ์น๋์ด์ผ ํ๋ค.
์์๋ ๋ค์๊ณผ ๊ฐ๋ค.
- ์ฝ๊ธฐ ์ ์ฉ ์์ฑ(val)์ผ๋ก ์ ์
- ์ฝ๊ธฐ-์ฐ๊ธฐ ์์ฑ(var)์ผ๋ก ์ ์
- ์ด๊ธฐํ ๋ธ๋ก(์ด๊ธฐ)
- ๋ณด์กฐ ์์ฑ์(๊ตฌ์ฑ์)
- ํจ์()
- ์ฝ๊ธฐ ์ ์ฉ ์์ฑ ํ์ฅ(val T.x)
- ์ฝ๊ธฐ-์ฐ๊ธฐ ์์ฑ ํ์ฅ(var T.x)
- ํจ์ extention(T.foo())
- ์ค์ฒฉ ๋๋ ๋ด๋ถ ํด๋์ค, ์ด๊ฑฐํ, ์ธํฐํ์ด์ค ๋ฐ ๊ฐ์ฒด
- companion object
๋ค์ ์์ ๋ฅผ ์ฐธ์กฐํ์.
class Klass(val parameter: Value) {
// Read-only properties
val publicValue: Value = Value()
private val value: Value = Value()
// Read-write properties
var publicVariable: Value = Value()
private var variable: Value = Value()
// Initialization block
init {
// ...
}
// Other constructors
constructor(firstValue: Int, secondValue: Int) : this(Value())
// Functions
fun publicFunction() { ... }
private fun privateFunction() { ... }
// Extensions of read-only properties
val T.publicReadonly: Value get() = Value()
private val T.readonly: Value get() = Value()
// Extensions of read-write properties
var T.publicReadWrite: Value
get()
set()
private var T.readWrite: Value
get()
set()
// Extensions of functions
fun T.publicFunction() { ... }
private fun .privateFunction() { ... }
// Nested or inner classes, enums, interfaces, and objects
enum class EnumType private constructor(val enumField: Int) {
DEFAULT(1),
A_ENUM_TYPE(2),
}
private data class NestedDataClass(val int: Int)
// Constants
companion object {
const val PRIMITIVE_CONSTANT = 0
@JvmField
val NON_PRIMITIVE_CONSTANT: OtherClass = OtherClass()
}
}
๊ฐ ๋ฒ์ฃผ์ ๋ํด ๊ฐ๋ฅํ ํ ๋ค์๊ณผ ๊ฐ์ ๊ท์น์ ์งํค๋๋ก ๊ถ์ฅํ๋ค.
- public ์ด private ๋ณด๋ค member ordering ์ด ๋๋ค.
- ์ ์ ํญ๋ชฉ์ด ๋์ ์ผ๋ก ๊ฒฐ์ ๋ ํญ๋ชฉ ์ด์์
- ์ถ์ํ ์์ค์ด ๋์ ํญ๋ชฉ์ ๋ฎ์ ์ถ์ํ ์์ค ํญ๋ชฉ๋ณด๋ค ๋๋ค.
์ ํ ์ ์ธ
- ํ์ ์ ์ธ์ ๋ฐ๋์ ์ง์ผ์ผ ํ๋ค.
- ์์ฑ์ ๋๋ ๋ฉ์๋์ ๋งค๊ฐ ๋ณ์
- ๋น์ ๋ ๋ฆฌํดํ ํจ์
- ์ ๋ถ **var** properties
- ๋ค์ ํ์ ์ ์ธ์ ์ญ์ ํ์ญ์์ค.
- ๋จ์๋ฐํํ๋ฒ
- "const" ํ์ ์๊ฐ ์๋ ๋ชจ๋ ํ๋
- ... ์ ๋ํ ํ์ ์ ์ธ์ ์ ์งํ๊ฑฐ๋ ์ทจ์ํ ์ ์๋ค.
- ๋ก์ปฌ ๊ฐ ๋ฐ ๋ณ์
- ๋๋ค์ ํ๋ผ๋ฏธํฐ ์ ํ
- val
- ๊ฐ์์ฑ๊ณผ ๊ด๊ณ์์ด ์์ฑ์์ ๋ํ ํธ์ถ์ ์ฌ์ฉํ์ฌ ์ฆ์ ํ ๋น๋๋ ์์ฑ
๋ค์ ์์ ๋ฅผ ์ฐธ์กฐํ์.
// You must keep type for public values and any variables private var variable: Type = Type() // Type required because `var` // You must keep type if the right value is not direct constructor call or primitive value private val array: Array
= arrayOf(1, 2, 3) // `arrayOf` is not a constructor. private val sum: Int = 1 + 2 // The right value is the result of `plus` function. private val valueWithApply: Type = Type().apply { ... } // `.apply` is appended. // You may keep or drop the type for values instantiated with constructor calls // With constructor call val value: Type = Type() // Kept (somewhat repetitive) val value = Type() // Dropped private val value1: Type = Type() // Kept (somewhat repetitive) private val value2 = Type( // Dropped parameter, parameter2 ) // With primitive value assignment private val value3: Int = 1 // Kept private val value4 = 1 // Dropped // Anti-pattern: dropping type declarations in situations other than explicit constructor calls private val value = Type.generateInstance() // Not an actual constructor call private val value2 = Type( // Starts with a constructor call... parameter, parameter2 ).toOtherType() // But may be deceptive // You must keep the type for private variables private var variable: Superclass = Subclass() // The type may be different than the initial value, because it can be reassigned /* ... */ variable = OtherSubclass() // The variable might take on another type } else { variable = Superclass() // ...or it might be assigned with the super-type // Even if the type was dropped, this code would be compiled successfully due to Kotlin's inferred typing system, but this isn't immediately obvious to readers // You must keep return type with non-Unit methods fun nonUnitFunction(): Int = 1 // You must skip return type if it is Unit fun unitFunction() = Unit // You must keep parameter type fun unitFunction(i: Int) { // You may skip local value/variable type... val j = 0 // or you may also keep the type. val k: Int = i + j // For lambdas, you can choose from any valid format. val firstLambda: (Int) -> Int = { it + 1 } val secondLambda = { i: Int -> i + 1 } val thirdLambda: (someMeaningfulName: Int) -> Int = { anotherName -> anotherName + 1 } }
ํจ์ ์ ์
ํค๋ ํฌ๋งท
ํค๋ ํ์์ Kotlin ์ฝ๋ฉ ๊ท์น์ ํด๋์ค ํค๋ ํ์์ ๋ฐ๋ฅธ๋ค. ํค๋๊ฐ ์ถฉ๋ถํ ์งง์ผ๋ฉด ๋ฐ๋์ ํ ์ค์ ์จ์ผ ํ๋ค. ํค๋๊ฐ ๊ธด ๊ฒฝ์ฐ ๊ฐ ๋งค๊ฐ๋ณ์ ์ ์ธ์ ๋ณ๋์ ์ค์ ์์ด์ผ ํ๋ค. ๋ค์ ์์ ๋ฅผ ์ฐธ์กฐํ์ญ์์ค.
fun shortHeader(): Int { // ... // ... } fun shortHeader(parameter: Int): Int { // ... // ... } fun longHeader( parameter: Parameter, anotherParameter: Parameter, oneMoreParameter: Parameter ): Type { // ... // ... } fun longHeaderWithUnitReturnType( parameter: Parameter ) { // ... // ... }
Brace ๋ฐ = ์ ์ ๊ธฐํธ
- ํ๋์ ํํ์์ผ๋ก ํจ์๋ฅผ ์ ์ํ๋ ค๋ฉด ๋ฐํ ์ ํ์ด ๋จ์์ธ ๊ฒฝ์ฐ์๋ ****= ๊ธฐํธ๋ฅผ ์ฌ์ฉํ์.
- ์ฌ๊ธฐ์๋ if, when, function calls with lambda์ ๊ฐ์ ํํ์ด ํฌํจ๋๋ค.
- ์ฌ์ฉํ๋ค= Unit์ด ๊ท์น์ ์์ธ๋ ๋ณด์กฐ ์์ฑ์๊ฐ ๋ค๋ฅธ ์์ฑ์์๊ฒ ์์ํ๋ ๊ฒฝ์ฐ๋ค.
- ๋น ํจ์๋ฅผ ์ ์ํ์ญ์์ค.
๋ค์ ์์ ๋ฅผ ์ฐธ์กฐํ์.
fun function(): Int = 1 + 2 fun function(parameter: Int): Int = 1 + parameter fun anotherFunction(): Type = Type().also { it.variable = "variable" it.anotherVariable = "variable" } fun whenFunction(type: Type): String = when(type) { Type1 -> "Type1" Type2 -> "Type2" } fun unitFunction() = anotherUnitFunction() fun emptyFunction() = Unit // Exception for secondary constructors constructor(type: Type) : super(type) constructor(type: Type, anotherType: Type) : this(type)
์์ ๊ฐ
์์ ๊ฐ์ ์๋ณธํ๋จ_์ผ๋ก ์ ์ธํด์ผ ํจ์ค๋ค์ดํฌ_์ผ์ด์ค_๋ผ์ดํฌ_์ด๊ฒ. ๋ํ ๋๋ฐ ๊ฐ์ฒด์ ํ๋ ๋๋ ๊ธ๋ก๋ฒ ๊ฐ์ผ๋ก ์ ์ํด์ผ ํ๋ค(๋ค์ ์น์ ์ฐธ์กฐ). ์์ ๊ฐ์ด ์์ ๊ฐ์ด๋ ๋ฌธ์์ด์ธ ๊ฒฝ์ฐ const ์์์ด๋ฅผ ์ถ๊ฐํด์ผ ํ๋ค. ๊ธฐ๋ณธ ์์๊ฐ ์๋ ์์์ ๊ฒฝ์ฐ, Java์์ ํ์๋๋๋ก ํ๋ ค๋ฉด @JvmField ์ฃผ์์ ์ถ๊ฐํด์ผ ํ๋ค.
const val PRIMITIVE_CONSTANT = 0 @JvmField val NON_PRIMITIVE_CONSTANT: NonPrimitive = NonPrimitive()
global value ๋ฐ global function
๊ธ๋ก๋ฒ ๊ฐ, ๊ฐ์ฒด(์์ํจ์๊ฐ ์๋ ๊ฒฝ์ฐ๋ ์์) ๋๋ ํ์ฅ์๋ฅผ ๋ณ๊ฒฝํ์ง ์๊ณ ๊ธฐ๋ฅ ๋๋ ์ ์ญ ๊ฐ์ ์ ์ํ๋ ค๋ฉด ๋ค์๊ณผ ๊ฐ์ด ์ ์ ํ ํจํค์ง์ ์ ํ์ผ์ ์์ฑํ์ญ์์ค.
YourConstants.kt
**`package`** `com.linecorp.yourpackage` `const **val**` `YOUR**_**CONSTANT**:**` `Int **=**` `0;` **`@**JvmField` **`val`** `YOUR**_**ANOTHER**_**CONSTANT**:**` `Value **=**` `Value();`
YourUtils.kt
**`package`** `com.linecorp.yourpackage`
`fun yourUtilityFunction()**:**` `ReturnValue {`
`// ...`
`**return**` `ReturnValue()`
`}`
Java์์ ์ ์ํ ๋ ํ์ผ ์ด๋ฆ ๋ํ ํด๋์ค ์ด๋ฆ์ผ๋ก ์ฌ์ฉ๋๊ธฐ ๋๋ฌธ์ ํ์ผ ์ด๋ฆ์ ๋ค์๊ณผ ๊ฐ์ด ์ ํ๋๋ค.
- ํ์ผ ์ด๋ฆ ์ ๋ฏธ์ฌ๋ ์์์ "Constants"์ฌ์ผ ํ๋ค.
- ํจ์ฉ ํจ์์ ํ์ผ ์ด๋ฆ ์ ๋ฏธ์ฌ๋ "Utils"์ฌ์ผ ํ๋ค.
- ํ์ฅ ๊ธฐ๋ฅ ๋ชจ์์ ๋ํ ํ์ผ ์ด๋ฆ ์ ๋ฏธ์ฌ๋ "ํ์ฅ"์ด์ด์ผ ํ๋ค.
๊ธ๋ก๋ฒ ํ์ฅ์ ๋ง๋ค๋ ค๋ฉด, ๋ค์ ์์ ์์๊ฒ ์์ฒญํ๋ ๊ฒ์ด ์ข๋ค.
Lamda
์ค์ฒฉ๋ ๋๋ค(๋๋ค(๋๋ค))๋ฅผ ํผํ์ญ์์ค.
์ค์ฒฉ๋ ๋๋ค๋ ์ข ์ข ์ฝ์ ์ ์๋ค. ๊ฒ๋ค๊ฐ, ๊ทธ๊ฒ์ ์ ํ์ ์ธ ์ฝ๋ ๋์์ ์ ํธ๋ค. ๋์ ๋ฉ์๋ ์ฐธ์กฐ, ๋ฉ์๋ ์ ์์ฌ, ํ๋ซ๋งต ๋๋ ๊ธฐํ ๋ฉ์๋๋ฅผ ์ฌ์ฉํ์. ์๋ฅผ ๋ค์ด ๋ค์๊ณผ ๊ฐ์ ์ฝ๋๋ ๊ธ์ง๋๋ค.
//BAD
list.map { innerList ->
innerList.map {
// DON'T DO THIS !!!
}
}
์์ธ:
์์ธ์ ์ผ๋ก ์ธ๋ถ ๋๋ค๊ฐ ๊ธ๋ก๋ฒ ๋ฒ์ ๋๋ ํด๋์ค์ ์ต์์ ์์ค(=์ฐ์ฐ์ ํฌํจ ํจ์/๊ฐ ํ ๋น ๋ฒ์ ํฌํจ) ๋ฐ๋ก ์๋์ ์์ผ๋ฉด ์ค์ฒฉ๋ ๋๋ค๋ฅผ ์ฌ์ฉํ ์ ์๋ค. ํ์ฉ ๊ฐ๋ฅํ ์ฝ๋๋ ๋ค์๊ณผ ๊ฐ๋ค.
class Klass {
val intValue: Int by lazy {
intList.sumBy { it + it * it }
}
fun function(mutableObject: MutableClass?, list: List) = mutableObject?.apply {
firstEven = list.first { it % 2 == 0 }
firstOdd = list.first { it % 2 != 0 }
// And more
}
}
//BAD
class Klass {
fun function(mutableObject: MutableClass?, list: List) {
mutableObject?.apply {
firstEven = list.first { it % 2 == 0 }
firstOdd = list.first { it % 2 != 0 }
}
// And more
}
๊ธด ๋๋ค ํผํ๋ค.
์ฝ๊ธฐ ์ฝ๋๋ก "๊ธด" ๋๋ค๋ ํผํด์ผ ํ๋ค. ๋ค์ ์กฐ๊ฑด ์ค ํ๋๋ฅผ ๋ง์กฑํ๋ ๋๋ค๋ "๊ธด" ๋๋ค.
- ๋ฐํ ์์ ์ ์ธํ 2๊ฐ ์ด์์ ๋ฌธ์ฅ์ด ์๋ ๋๋ค.
- if ์, a when ์ ๋๋ for/while ๋ฃจํ๊ฐ ์๋ ๋๋ค.
๋ค์ ์๋ฅผ ์ฐธ์กฐํ์.
// Short lambda expression: 1 statement and 1 return expression
list.map {
methodCall(it)
returnValue(it)
}
// Long lambda: with for when
dialogBuilder.setPositiveButton("OK") { dialog: DialogInterface, which: Int ->
when (which) {
0 -> // ...
else -> // ...
}
}
// Long lambda: 2 statements (the second line is not return expression)
obj.apply {
methodCall()
anotherMethodCall()
}
"๊ธด" ๋๋ค๋ฅผ ์ฌ์ฉํ์ง ์์ผ๋ ค๋ฉด ํํ์์ ๋ฐฉ๋ฒ์ผ๋ก ์ถ์ถํ๊ณ ๋ฉ์๋ ์ฐธ์กฐ๋ฅผ ์ฌ์ฉํ์ฌ ๊ฐ๋ฅํ๋ฉด ๋ช ๋ช ๋ ํด๋์ค๋ฅผ ๋ง๋์ญ์์ค.
์์ธ:
ํธ์์ "๊ธด" ๋๋ค(long)๋ ๋ค์๊ณผ ๊ฐ์ ๊ฒฝ์ฐ์ ํ์ฉ๋๋ค.
- ๋ฐํ ๊ฐ์ผ๋ก ์ง์ ์ฌ์ฉ๋๋ ๋๋ค
- ํจ์์ ๋ง์ง๋ง ์ธ์๋ก ์ง์ ์ฌ์ฉ๋๋ ๋๋ค. ์ฌ๊ธฐ์...
- ๋ค๋ฅธ ์ฃผ์ฅ์ ๋๋ค๊ฐ ์๋๋ค.
- ๋๋ค๋ ์์ ๋๋ ์์ ์์ ๊ธฐ๋ฅผ ํฌํจํ ๊ธฐ๋ฅ์ ๋ฐํ ๊ฐ์ ์์ฑํ๋ ๋ฐ๋ง ์ฌ์ฉ๋๋ค.
- ํจ์ ๋ฐํ ๊ฐ์ ํธ์ถ์์ ํ ๋น ๋๋ ๋ฐํ ๊ฐ์ ์ฌ์ฉ๋์ง ์๊ฑฐ๋ ์ง์ ์ฌ์ฉ๋๋ค.
// OK: Long lambda directly used for return value
fun createComparator(): (Int, Int) -> Int = { x: Int, y: Int ->
// Code...
// Code...
result
}
// OK: Long lambda used for assignment directly.
val mappedList = list.map {
when (it) {
0 -> it
else -> it + 1
}
}
// OK: Long lambda used for delegation directly.
val view by lazy {
// initialization
// another initialization
inflatedView
}
// BAD: the result of function taking lambda is not directly used for assignment
val mappedList = list.map {
when (it) {
0 -> it
else -> it + 1
}
}
.map { /* another map */ }
// BAD: the result of function taking lambda is not directly used for assignment
val value: View = parent?.let {
// initialization
// another initialization
foundView
} ?: defaultView
๋ก์ปฌ ๊ฐ/๋ณ์์ ๊ด๋ จํ์ฌ ๋ซ๊ธฐ๋ฅผ ๋ฐํํ์ง ์์
๋์ concrete ํด๋์ค ๋๋ ๊ฐ์ฒด๋ฅผ ๋ง๋์ญ์์ค.
try-catch ๋ธ๋ก๋ณ๋ก ์์๋ ์์ธ ์ ํ์ ๋ช ์์ ์ผ๋ก ์ง์ ํ์ญ์์ค.
๊ณต์ ๊ฐ์ด๋ ์ธ์๋ ๊ฐ ์กฐ์ง ์ํฉ์ ๋ง๊ฒ ์ถ๊ฐ ๊ท์น์ ๋ ผ์ํ๊ณ ์ ์ํ๋ ๊ฒ์ด ์ค์ํ๋ค. ๊ทธ๋ฆฌ๊ณ ๊ท์น์ ๋ฌธ์๋ก๋ง ์กด์ฌํ๋ ๊ฒ์ด ์๋๋ผ ์๋ํ ๋๊ตฌ์ ์ฐ๊ณํ์ฌ ์ค์ง์ ์ธ ์ฝ๋ ํ์ง ํฅ์์ ์ด๋์ด๋ด์ผ ํ๋ค.
์ค์ ์์ ๋๋ ์
๊ฐ๋ฐ ๋ฌธํ๋ฅผ ์ก์๊ฐ๋ ๊ณผ์ ์์ ๊ธฐ๋ณธ ๊ท์น + ํ๊ณผ์ ํฉ์ + ์๋ํ ๋ฐ ์ ์ ๋ถ์ ๋๊ตฌ์ ์ผ๋ฐ์๊ฐ ๊ฐ์ฅ ์ด์์ ์ด๋ผ๊ณ ์๊ฐํ๋ค. ๊ทธ๋์ผ๋ง ์ฝ๋๊ฐ ์์ฐ๋ ๋ ๊ฐ๋ ์ฑ ๋์, ์ฝ๊ธฐ ์ฌ์ด ์ฝ๋๊ฐ ๋ ํ๋ฅ ์ด ๋๋ค.
๋ด๊ฐ ์ฌ๋ฌ ๊ตญ๊ฐ ๊ฐ๋ฐ์๋ค๊ณผ ํ์ ํ๋ฉด์ ๊ฐ์ฅ ํฌ๊ฒ ๋๋ ์ ์, ์ฌ๋๋ง๋ค, ์ธ์ข ๋ง๋ค ์ฝ๋ฉ ์คํ์ผ์ด ์ฒ์ฐจ๋ง๋ณ์ด๋ผ๋ ๊ฒ์ด๋ค. ํนํ ํ๊ตญ, ์ธ๋, ๊ธฐํ ๊ตญ๊ฐ๋ค์ ๊ฐ๋ฐ์๋ค์ด ์์ฑํ ์ฝ๋๋ ๊ฐ๊ฐ ๋ ๋ค๋ฅธ ๋งค๋ ฅ์ด ์๋ค. ๋ค์ํ ์ฝ๋๋ฅผ ๋ณด๋ฉด์ ๋๋ง์ ์คํ์ผ์ ์ฐพ์๊ฐ๋ ๊ฒ๋ ์ข์ ๋ฐฉ๋ฒ์ด๋ผ ์๊ฐํ๋ค.
AI ์๋์ ์ ์ด๋ ์ง๊ธ, ์์ ์ด ์์ฑํ ์ฝ๋๋ฅผ ChatGPT ๊ฐ์ AI์ ๋์์ผ๋ก ๊ฐ์ ํ๋ ๊ฒ๋ ์ข์ ์ต๊ด์ด๋ค. ๋ฌผ๋ก ๋ชจ๋ ๊ฒ์ AI์ ์์กดํ๋ ๊ฒ์ ์ข์ ํ๋๊ฐ ์๋์ง๋ง, AI๊ฐ ์ ๊ณตํ๋ ๋์์ ์ฐธ๊ณ ํ๋ฉด์ ๋ ๋์ ์ฝ๋๋ฅผ ๋ง๋ค์ด๋ด๋ ๊ฐ๋ฐ์๊ฐ ๋์ด์ผ ํ๋ค๊ณ ์๊ฐํ๋ค.
๋ง์น๋ฉฐ
์ด๋ฒ ํธ์์๋ ์ฝ๋ฉ ๊ท์น์ ์ ํ๋ ์ด์ ์ ์ค์ ์ ์ฉ ๋ฐฉ๋ฒ์ ์๊ฐํ๋ค.
์์ง๋ง ๋ช ํํ ๊ท์น ํ๋๊ฐ ํ์ ์ปค๋ฎค๋์ผ์ด์ ๊ณผ ์์ฐ์ฑ์ ํฐ ์ฐจ์ด๋ฅผ ๋ง๋ค์ด๋ธ๋ค.
๋ค์ ํธ์์๋ ์ฝ๋ ๋ฆฌ๋ทฐ ๋ฌธํ์ ๊ทธ ์์น์ ์ ๋ฆฌํ์ฌ, ์ฝ๋ ํ์ง๊ณผ ํ ํ์ ์ ํ์ธต ๋ ๊ฐํํ๋ ๋ฐฉ๋ฒ์ ์๊ฐํ๊ณ ์ ํ๋ค.
๋ค์ ํธ ์๊ณ
๊ฐ๋ฐ ๋ฌธํ ์ ๋ฆฝ ์๋ฆฌ์ฆ - 4ํ : ์ฝ๋ ๋ฆฌ๋ทฐ ์์น๊ณผ ๋ฌธํ ์ ๋ฆฝํ๊ธฐ
์ข์ ์ฝ๋ ๋ฆฌ๋ทฐ๋ ํ์ ์ฑ์ฅ ์์ง์ด๋ค.
๋ค์ ํธ์์๋ ์ฝ๋ ๋ฆฌ๋ทฐ ์ ์ง์ผ์ผ ํ ์์น๊ณผ, ๋ฆฌ๋ทฐ ๋ฌธํ๋ฅผ ๊ฑด๊ฐํ๊ฒ ๋ง๋ค๊ธฐ ์ํ ํ์ ๊ณต์ ํ ์์ ์ด๋ค.
๋๊ธ ์ฐ๊ธฐ