클래스 레이아웃
일반적으로 클래스의 내용은 다음의 순서로 정렬된다.
1. Property declartions and initializer block
2. Secondary constructors
3. Method declarations
4. Companion object
- 관련된 것들을 한데 모아 클래스를 읽는 사람이 위에서 아래로 무슨 일이 일어나고 있는지 로직을 따라갈 수 있도록 해라.
- 중첩 클래스들이 외부에서 사용되도록 의도되었고 클래스 내부에서 참조되지 않는다면 companion object 다음의 마지막에 위치시켜라.
콜론
- 아래와 같은 경우에 콜론 앞에 공백을 넣어라
- 타입과 슈퍼 타입을 분리할 때
- 동일한 클래스의 다른 생성자 또는 슈퍼 클래스의 생성자에게 위임할 때
- object 키워드 다음에
- 변수 선언과 그 타입을 분리할 때 콜론 앞에 공백을 두지 않는다. a: Int
- 콜론 뒤에는 항상 공백을 둔다.
클래스 헤더 형식
- 파라미터가 몇개 없는 기본 생성자의 경우 한 줄로 작성할 수 있다.
class Person(id: Int, name: String) - 헤더가 긴 기본 생성자의 경우 들여쓰기와 함께 라인으로 구분한다. 또한 닫는 소괄호는 새로운 라인에 있어야 하고,
- 만약 상속을 하는 경우 슈퍼클래스의 생성자 호출 및 인터페이스 구현은 닫는 소괄호와 동일한 라인에 있어야한다.
class Person(
id: Int,
name: String,
surname: String
) : Human(id, name) { ... } - 다중 인터페이스를 구현하는 경우 슈퍼 클래스의 생성자를 먼저 닫는 소괄호에 같은 라인으로 위치시키고
각 인터페이스는 각각 다른 라인으로 위치해야 한다.
class Person(
id: Int,
name: String,
surname: String
) : Human(id, name),
KotlinMaker { ... } - 긴 슈퍼 타입 목록을 가지는 클래스의 경우 콜론 다음에 각 타입별로 줄 바꿈 처리하고 가로 정렬을 맞춘다.
class MyFavouriteVeryLongClassHolder :
MyLongHolder<MyFavouriteVeryLongClass>(),
SomeOtherInterface,
AndAnotherOne {
fun foo() { ... }
} - 클래스 헤더가 길 경우 헤더와 몸체를 명확히 구분하려면 위와 같이 빈라인을 두거나 아래와 같이 중괄호를 별도의 라인으로 둔다.
class MyFavouriteVeryLongClassHolder :
MyLongHolder<MyFavouriteVeryLongClass>(),
SomeOtherInterface,
AndAnotherOne
{
fun foo() { ... }
}
제어자
- 여러 개의 제어자를 가질 경우 아래의 순서를 따른다.
함수 형식
- 함수의 시그니처를 한줄로 표현하기 알맞지 않다면 아래와 같은 구문을 따른다
fun longMethodName(
argument: ArgumentType = defaultValue,
argument2: AnotherArgumentType
): ReturnType {
// body
}
- 함수가 단일 표현식으로 구성되어있을 경우 {}와 return을 제거하고 =로 표현하는 방식이 좋다
fun foo(): Int { // bad
return 1
}
fun foo() = 1 // good
제어문 형식
- if나 when과 같은 조건식이 멀티라인일 경우 항상 여는 중괄호 {를 실행 구문에 가깝게 둔다.
- when 제어문에서 분기문이 한 줄 이상일 경우 인접한 case블록과 빈 라인으로 구분하는 것을 고려하라.
- 짧은 분기문의 경우 중괄호 없이 조건과 동일한 라인에 둔다.
private fun parsePropertyValue(propName: String, token: Token) {
when (token) {
is Token.ValueToken ->
callback.visitValue(propName, token.value)
Token.LBRACE -> { // ...
}
}
}
메소드 호출 형식
- 긴 인자 목록을 가지는 메소드를 호출할 때, 여는 소괄호 다음 줄바꿈을 한 뒤 인자들을 4칸 공백으로 들여쓰기 한다.
- 밀접하게 관련된 인자끼리 그룹핑한다.
- 인자의 이름과 값을 구분하는 = 주변에 공백을 둔다.
drawSquare(
x = 10, y = 10,
width = 100, height = 100,
fill = true
)
람다형식
- 람다 표현식에서 중괄호 {} 주변에는 공백을 두어야 한다.
- 파라미터를 나타내는 화살표 -> 주변에도 공백을 두어야 한다.
- 호출에 사용된 람다가 한 개인 경우 가능한 한 소괄호 ()를 제거해야 한다.
list.filter { it > 10 }
- 만약 람다에 label을 할당한다면 label과 여는 중괄호 {사이에 공백을 두지 않는다.
fun foo() {
ints.forEach lit@{
// ...
}
}
- 다중 라인 람다에서 파라미터의 이름을 선언할 때, 첫 번째 줄에 파라미터 이름과 화살표 ->를 선언하고 개행처리 한다.
appendCommaSeparated(properties) { prop ->
val propertyValue = prop.get(obj) // ...
}
- 만약 파라미터 목록이 한 쭐로 표현하기 적합하지 않다면 파라미터 목록과 화살표 ->를 들여쓰기와 함께 개행처리 한다.
foo {
context: Context,
environment: Env
->
context.configureEnv(environment)
}
주석
- 일반적으로 @param과 @return태그는 사용하지 마라
- 대신, 파라미터 및 반환 값에 대한 설명을 주석 내용에 직접 포함시키고, 언급된 모든 파라미터에 링크를 추가한다.
- 주석 내용의 흐름에 맞지 않는 장황한 설명이 필요한 경우에만 @param 및 @return을 사용해라.
// Avoid doing this:
/**
* Returns the absolute value of the given number.
* @param number The number to return the absolute value for.
* @return The absolute value.
*/
fun abs(number: Int) = ...
// Do this instead:
/**
* Returns the absolute value of the given [number].
*/
fun abs(number: Int) = ...
불변성
- Immutable컬렉션을 선언할 때는 항상 Collection, List, Set, Map과 같은 인터페이스를 사용해라
- 컬렉션 인스턴스를 생성할 때 가능한 Immutable컬렉션 타입으로 생성해라.
// Bad: use of mutable collection type for value which will not be mutated
fun validateValue(actualValue: String, allowedValues: HashSet<String>) { ... }
// Good: immutable collection type used instead
fun validateValue(actualValue: String, allowedValues: Set<String>) { ... }
// Bad: arrayListOf() returns ArrayList<T>, which is a mutable collection type
val allowedValues = arrayListOf("a", "b", "c")
// Good: listOf() returns List<T>
val allowedValues = listOf("a", "b", "c")
- 기본적으로 Kotlin에서 List는 Read-only
기본 인자 값
오버로딩을 선언하기 위해 기본 인자 값을 가지는 함수를 선언하는 것이 좋다.
// Bad
fun foo() = foo("a")
fun foo(a: String) { ... }
// Good
fun foo(a: String = "a") { ... }
람다에서의 return
- 람다 안에서 label이 붙은 return을 여러개 사용하는 것을 피해라
- 하나의 탈출 포인트를 갖도록 구조를 바꾸는 것을 고려해라.
- 만약 그것이 불가능하거나 충분히 명확하지 않다면, 람다를 익명 함수로 변환하는 것을 고려해라.
- 람다의 마지막 문장에서 label이 붙은 return을 사용하지 마라.
조건문 사용
try, if, when은 아래와 같은 표현식을 사용하는 것이 좋다.
return if (x) foo() else bar()
return when(x) {
0 -> "zero"
else -> "nonzero"
}
if vs when
조건이 2개라면 when보다 if를 사용해라.
루프 사용
- 루프에는 filter, map과 같은 고차 함수를 사용하는 것이 좋다.
- 예외적으로 forEach의 경우 forEach의 리시버가 nullable이거나 forEach가 긴 호출 체인의 일부로 사용되는 경우가 아니라면 일반적인 for루프가 더 좋다.
- 복수의 고차 함수를 이용한 복잡한 표현과 루프를 선택할 때에는 각 상황에서 실행되는 operation들의 비용을 이해해야 하고 성능 고려 사항들을 유념해라
참조 :
'코틀린 & Java' 카테고리의 다른 글
lateinit 초기화 확인하기 (0) | 2022.01.11 |
---|---|
LiveData와 StateFlow의 차이 (0) | 2021.12.27 |
스트림 함수 (0) | 2021.08.04 |
Kotlin 코딩규칙 서식 (0) | 2021.07.07 |
Kotlin 코딩규칙 명명 규칙 (0) | 2021.07.07 |