코틀린 & Java

코틀린 코딩컨벤션 정리

코딩하는후운 2021. 12. 13. 19:50
반응형

클래스 레이아웃

일반적으로 클래스의 내용은 다음의 순서로 정렬된다.

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들의 비용을 이해해야 하고 성능 고려 사항들을 유념해라

 

 

참조 :

https://medium.com/@joongwon/kotlin-%EC%BD%94%EB%94%A9-%EC%BB%A8%EB%B2%A4%EC%85%98-%EC%A0%95%EB%A6%AC-7681cde920ce

반응형

'코틀린 & 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