Search

Kotlin Coding Conventions

소스 코드 구성

디렉토리 구조

Kotlin 프로젝트에서 권장되는 디렉토리 구조는 공통 루트 패키지가 생략된 패키지 구조를 따른다.
JVM에서 Kotlin과 Java를 함께 사용하는 경우 동일한 소스 루트에 있어야 하며 동일한 디렉토리 구조를 따라야 한다.

소스 파일 이름

Kotlin 파일에 단일 클래스 또는 인터페이스가 포함된 경우 해당 이름은 클래스 이름과 동일해야한다.
Kotlin 파일에 여러 클래스 또는 최상위 선언만 포함된 경우 파일에 포함된 내용을 설명하는 이름을 지정해야한다.
첫 글자를 대문자로 시작하는 대문자 카멜 케이스(Pascal 케이스)를 사용한다.
파일의 확장자는 .kt 여야한다.

소스 파일 구성

여러 선언(클래스, 최상위 함수 또는 속성)을 동일한 Kotlin 소스 파일에 넣는 것은 이러한 선언이 의미적으로 서로 밀접하게 관련되어 있고 파일 크기가 적당한 한(수백 줄을 넘지 않음) 권장된다.
클래스의 모든 클라이언트와 관련된 클래스에 대한 확장 함수를 정의할 때는 클래스 자체와 같은 파일에 넣는다.
특정 클라이언트에게만 의미가 있는 확장 함수를 정의할 때는 해당 클라이언트의 코드 옆에 넣는다.
어떤 클래스의 모든 확장 함수를 보관하기 위한 파일을 만드는 것을 피한다.

클래스 레이아웃

클래스의 내용은 다음 순서를 따라야 한다.
1.
property 선언 및 초기화 블록
2.
secondary constructors
3.
method 선언
4.
companion object
메서드 선언을 알파벳순이나 가시성순으로 정렬하지 말고 일반 메서드와 확장 메서드를 분리하지 말고 관련된 내용을 모아서 클래스를 위에서 아래로 읽는 사람이 무슨 일이 일어나고 있는지의 논리를 따라갈 수 있도록 하라.
중첩된 클래스를 해당 클래스를 사용하는 코드 옆에 둬라.
클래스가 외부에서 사용되도록 의도되었고 클래스 내부에서 참조되지 않는 경우 companion object 뒤의 끝에 둬라.

인터페이스 구현 레이아웃

인터페이스를 구현할 때 구현 멤버를 인터페이스 멤버와 동일한 순서로 유지한다.
필요한 경우 구현에 사용되는 추가 개인 메서드를 삽입한다.

오버로드 레이아웃

클래스에서 오버로드는 항상 서로 옆에 둬라.

네이밍 규칙

패키지 이름은 항상 소문자이고 밑줄을 사용하지 않는다. (여러 단어일 경우 그냥 연결하거나 카멜 케이스를 사용한다.)
클래스와 객체의 이름은 대문자로 시작하고 카멜 케이스를 사용한다.
//org.example.myProject open class DeclarationProcessor { /*...*/ } object EmptyDeclarationProcessor : DeclarationProcessor() { /*...*/ }
Kotlin
복사

함수 이름

함수, 속성 및 로컬 변수의 이름은 소문자로 시작하고 카멜 케이스를 사용하며 밑줄을 사용하지 않는다.
fun processDeclarations() { /*...*/ } var declarationCount = 1
Kotlin
복사
클래스 인스턴스를 생성하는데 사용되는 팩토리 함수는 인터페이스 반환 타입과 동일한 이름을 가질 수 있다.
interface Foo { /*...*/ } class FooImpl : Foo { /*...*/ } fun Foo(): Foo { return FooImpl() }
Kotlin
복사

테스트 메서드 이름

오직 테스트에서는 백틱(`)으로 묶인 공백이 있는 메서드 이름을 사용할 수 있다.
메서드 이름에 밑줄을 사용하는 것도 테스트 메서드에서 허용된다.

프로퍼티 이름

상수의 이름은 대문자와 밑줄로 구분된 형식(스크리밍 스네이크 케이스)를 사용해야 한다.
변경 불가능한 데이터를 보유한 const로 표시된 프로퍼티
사용자 지정 get 함수가 없는 최상위 또는 객체 val 프로퍼티
const val MAX_COUNT = 8 val USER_NAME_FIELD = "UserName"
Kotlin
복사
동작이나 변경 가능한 데이터가 있는 객체를 보관하는 최상위 프로퍼티나 객체 프로퍼티의 이름은 카멜 케이스를 사용해야 한다.
val mutableCollection: MutableSet<String> = HashSet()
Kotlin
복사
object 싱글톤 객체에 대한 참조를 보유하는 속성의 이름은 선언과 동일한 네이밍 스타일을 사용할 수 있다.
val PersonComparator: Comparator<Person> = /*...*/
Kotlin
복사
열거형 상수의 경우 사용법에 따라 스네이크 케이스나 대문자 카멜 케이스를 사용해도 된다.
enum class Color { RED, GREEN }
Kotlin
복사

백킹 프로퍼티의 이름

클래스에 개념적으로 동일하지만 하나는 공개 API의 일부이고 다른 하나는 구현 세부 사항인 두 개의 프로퍼티가 있는 경우 비공개 프로퍼티의 이름에 대한 접두사로 밑줄을 사용한다.
class C { private val _elementList = mutableListOf<Element>() val elementList: List<Element> get() = _elementList }
Kotlin
복사

좋은 이름을 사용하라

클래스의 이름
일반적으로 명사이거나 클래스가 무엇인지 설명하는 명사구이다.
ex) List, PersonReader
메서드의 이름
일반적으로 메서드가 무엇을 하는지 나타내는 동사구이다.
ex) close, readPersons
메서드가 객체를 변형하는지 아니면 새 객체를 반환하는지 여부도 이름에 암시해야한다.
ex) sort는 제자리에서 정렬, sorted는 정렬된 복사본을 반환
이름을 통해 엔티티의 목적이 명확하게 드러나야 하므로 이름에 무의미한 단어는 사용하지 않는 것이 좋다.
ex) Manager, Wrapper
선언 이름의 일부로 약어를 사용할 때 두 글자로 구성된 경우 대문자로 시작하고 두 글자가 더 길면 첫 글자만 대문자로 시작한다.
ex) IOStream, XmlFormatter, HttpInputStream

서식 지정

들여쓰기

들여쓰기에는 4개의 공백을 사용합니다. (탭을 사용하지 마세요)
중괄호의 경우 여는 중괄호를 구문이 시작되는 줄 끝에 놓고 닫는 중괄호는 여는 중괄호와 수평으로 맞춰 별도의 줄에 놓습니다.
if (elements != null) { for (element in elements) { // ... } }
Kotlin
복사
Kotlin에서 세미콜론은 선택사항이므로 줄 바꿈이 중요하다.

수평 공백

이진 연산자 a + b 주위에 공백을 둬라
범위 연산자 0..i 주위에 공백을 두지마라.
단항 연산자 a++ 주위에 공백을 두지마라.
제어 흐름 키워드 if, when, for, while 과 여는 괄호 사이에 공백을 둬라.
(, [, ), ] 뒤나 앞에 공백을 두지마라.
기본 생성자 선언, 메서드 선언 또는 메서드 호출에서 여는 괄호 앞에 공백을 두지마라.
class A(val x: Int) fun foo(x: Int) { ... } fun bar() { foo(1) }
Kotlin
복사
. 또는 ?. 주위에 공백을 두지마라.
foo.bar().filter { it > 2 }.joinToString() foo?.bar()
Kotlin
복사
// 뒤에 공백을 둬라.
// This is a comment
Kotlin
복사
타입 매개변수를 지정하는데 사용되는 <, > 주위에 공백을 두지마라.
class Map<K, V> { ... }
Kotlin
복사
:: 주위에 공백을 두지마라.
Foo::class String::length
Kotlin
복사
? 키워드 앞에 공백을 두지마라.
String?
Kotlin
복사

콜론

: 앞에 공백을 두는 경우
타입과 슈퍼 타입을 구분하는데 사용되는 경우
슈퍼클래스 생성자 또는 동일 클래스의 다른 생성자에게 위임할 때
object 키워드 뒤에
: 앞에 공백을 두지 않는 경우
선언과 타입을 구분할 때
abstract class Foo<out T : Any> : IFoo { abstract fun foo(a: Int): T } class FooImpl : Foo() { constructor(x: String) : this(x) { /*...*/ } val x = object : IFoo { /*...*/ } }
Kotlin
복사

클래스 헤더

몇 개의 기본 생성자 매개변수가 있는 클래스는 한 줄로 작성할 수 있다.
class Person(id: Int, name: String)
Kotlin
복사
헤더가 긴 클래스는 각 기본 생성자 매개변수가 들여쓰기가 있는 별도의 줄에 있도록 포맷해야한다.
또한 닫는 괄호는 새 줄에 있어야 한다.
상속을 사용하는 경우 슈퍼클래스 생성자 호출 또는 구현된 인터페이스 목록은 닫는 괄호와 같은 줄에 있어야 한다.
class Person( id: Int, name: String, surname: String ) : Human(id, name) { /*...*/ }
Kotlin
복사
여러 인터페이스의 경우 슈퍼클래스 생성자 호출을 먼저 찾은 다음 각 인터페이스를 다른 줄에 찾아야 한다.
class Person( id: Int, name: String, surname: String ) : Human(id, name), KotlinMaker { /*...*/ }
Kotlin
복사
긴 슈퍼타입 목록이 있는 클래스의 경우 콜론 뒤에 줄 바꿈을 넣고 모든 슈퍼타입 이름을 가로로 맞춘다.
class MyFavouriteVeryLongClassHolder : MyLongHolder<MyFavouriteVeryLongClass>(), SomeOtherInterface, AndAnotherOne { fun foo() { /*...*/ } }
Kotlin
복사
클래스 헤더가 길 때 클래스 헤더와 본문을 명확하게 구분하려면 클래스 헤더 뒤에 빈 줄을 넣거나 여는 중괄호를 별도의 줄에 넣는다.
class MyFavouriteVeryLongClassHolder : MyLongHolder<MyFavouriteVeryLongClass>(), SomeOtherInterface, AndAnotherOne { fun foo() { /*...*/ } }
Kotlin
복사
생성자 매개변수에 일반 들여쓰기(공백 4개)를 사용한다.
이렇게 하면 기본 생성자에서 선언된 프로퍼티가 클래스 본문에서 선언된 프로퍼티와 동일한 들여쓰기를 갖도록 한다.

수정자 순서

선언에 여러 개의 수정자가 있는 경우 항상 다음 순서에 따라 배치하라.
public / protected / private / internal expect / actual final / open / abstract / sealed / const external override lateinit tailrec vararg suspend inner enum / annotation / fun // as a modifier in `fun interface` companion inline / value infix operator data
Kotlin
복사
모든 어노테이션은 수정자 앞에 둬라.
@Named("Foo") private val foo: Foo
Kotlin
복사
라이브러리에서 작업하지 않는 한 중복되는 수정자 (public) 은 생략하라.

어노테이션

어노테이션은 첨부된 선언문 앞에 별도 줄에 동일한 들여쓰기로 배치한다.
@Target(AnnotationTarget.PROPERTY) annotation class JsonExclude
Kotlin
복사
인수가 없는 어노테이션은 같은 줄에 배치할 수 있다.
@JsonExclude @JvmField var x: String
Kotlin
복사
인수가 없는 단일 어노테이션은 해당 선언과 같은 줄에 배치할 수 있다.
@Test fun foo() { /*...*/ }
Kotlin
복사

파일 어노테이션

파일 어노테이션은 주석 뒤, package 문장 앞에 배치하고 package 문장과 빈 줄로 구분한다.
package 파일을 대상으로 하고 패키지가 아니라는 점을 강조하기 위함
/** License, copyright and whatever */ @file:JvmName("FooBar") package foo.bar
Kotlin
복사

함수

함수 매개변수가 한 줄에 들어가지 않으면 다음 구문을 사용하라.
함수 매개변수에는 일반 들여쓰기(공백 4개)를 사용한다.
생성자 매개변수와의 일관성을 보장하는데 도움이 된다.
fun longMethodName( argument: ArgumentType = defaultValue, argument2: AnotherArgumentType, ): ReturnType { // body }
Kotlin
복사
본문이 단일 표현식으로 구성된 함수의 경우 표현식 본문을 사용하는 것이 좋다.
fun foo(): Int { // bad return 1 } fun foo() = 1 // good
Kotlin
복사

표현체

함수의 첫 줄이 선언과 같은 줄에 맞지 않는 표현식 본문이 있는 경우 첫 번째 줄에 = 부호를 넣고 표현식 본문을 줄바꿈하여 4칸 들여쓴다.
fun f(x: String, y: String, z: String) = veryLongFunctionCallWithManyWords(andLongParametersToo(), x, y, z)
Kotlin
복사

프로퍼티

매우 간단한 읽기 전용 속성의 경우 한 줄 서식을 고려하라.
val isEmpty: Boolean get() = size == 0
Kotlin
복사
더 복잡한 프로퍼티의 경우 항상 get, set 키워드를 별도의 줄에 넣어라.
val foo: String get() { /*...*/ }
Kotlin
복사
초기화가 있는 프로퍼티의 경우 초기화가 길면 = 기호 뒤에 줄 바꿈을 추가하고 초기화를 공백 4개로 들여쓰기한다.
private val defaultCharset: Charset? = EncodingRegistry.getInstance().getDefaultCharsetForPropertiesFiles(file)
Kotlin
복사

제어 흐름 문장

if or when 문의 조건이 여러 줄인 경우 항상 문의 본문 주위에 중괄호를 사용한다.
조건의 각 후속 줄은 문의 시작을 기준으로 4칸씩 들여쓰기한다.
조건의 닫는 괄호와 여는 중괄호를 별도의 줄에 함께 넣는다.
이는 조건문과 진술문 본문을 정렬하는데 도움이 된다.
if (!component.isSyncing && !hasAnyKotlinRuntimeInScope(module) ) { return createKotlinNotConfiguredPanel(module) }
Kotlin
복사
do-while의 while 키워드 뿐만 아니라 else, catch, finally 키워드도 앞의 중괄호와 같은 줄에 넣어라.
if (condition) { // body } else { // else part } try { // body } finally { // cleanup }
Kotlin
복사
when 문장에서 분기가 한 줄 이상인 경우 빈 줄로 인접한 케이스 블록과 분리하는 것을 고려하라.
private fun parsePropertyValue(propName: String, token: Token) { when (token) { is Token.ValueToken -> callback.visitValue(propName, token.value) Token.LBRACE -> { // ... } } }
Kotlin
복사
when 문장에서 분기가 짧은 경우 조건과 같은 줄에 중괄호 없이 짧은 분기문을 넣는다.
when (foo) { true -> bar() // good false -> { baz() } // bad }
Kotlin
복사

메서드 호출

긴 인수 목록에서는 여는 괄호 뒤에 줄 바꿈을 넣고 인수를 4칸 들여쓰기한다.
여러 개의 밀접하게 관련된 인수는 같은 줄에 그룹화한다.
인수와 값을 구분하는 = 기호 주위에 공백을 넣는다.
drawSquare( x = 10, y = 10, width = 100, height = 100, fill = true )
Kotlin
복사

체인 메서드 호출

체인 메서드를 호출할 때는 . 문자나 ?. 연산자를 다음 줄에 한 번 들여쓰기하여 입력한다.
체인의 첫 번째 호출은 일반적으로 앞에 줄 바꿈이 있어야 하지만 없는게 더 의미가 있다면 생략해도 된다.
val anchor = owner ?.firstChild!! .siblings(forward = true) .dropWhile { it is PsiComment || it is PsiWhiteSpace }
Kotlin
복사

람다

람다 표현식에서 중괄호 주변과 매개변수와 본문을 구분하는 화살표 주변에 공백을 사용해야 한다.
호출이 단일 람다를 사용하는 경우 가능하면 괄호 밖으로 전달한다.
list.filter { it > 10 }
Kotlin
복사
람다에 대한 라벨을 지정하는 경우 라벨과 여는 중괄호 사이에 공백을 넣지 않는다.
fun foo() { ints.forEach lit@{ // ... } }
Kotlin
복사
다중 줄 람다에서 매개변수 이름을 선언할 때는 첫 번째 줄에 이름을 쓰고 그 뒤에 화살표와 줄 바꿈 문자를 쓴다.
appendCommaSeparated(properties) { prop -> val propertyValue = prop.get(obj) // ... }
Kotlin
복사
매개변수 목록이 한 줄에 들어가기에는 너무 긴 경우 화살표를 별도의 줄에 넣는다.
foo { context: Context, environment: Env -> context.configureEnv(environment) }
Kotlin
복사

후행 쉼표

후행 쉼표는 일련의 요소에서 마지막 항목 뒤에 오는 쉼표 기호다.
class Person( val firstName: String, val lastName: String, val age: Int, // trailing comma )
Kotlin
복사
후행 쉼표를 사용 했을 때의 이점
모든 초점이 변경된 값에 맞춰지므로 버전 제어 차이점이 더 깔끔해진다.
요소를 조작할 때 쉼표를 추가하거나 삭제할 필요가 없으니 요소를 추가하고 재정렬하는 것이 쉽다.
마지막 요소에도 쉼표가 있을 수 있으니 객체 초기화를 위한 코드 생성을 간소화한다.
후행 쉼표는 권장 사항이기 때문에 전적으로 선택 사항이고 후행 쉼표 없이도 코드는 작동한다.

문서 주석

더 긴 문서 주석의 경우 별도의 줄에 시작 부분을 입력하고 각 후속 줄을 별표로 시작하라.
/** * This is a documentation comment * on multiple lines. */
Kotlin
복사
짧은 주석은 한 줄에 넣을 수 있다.
/** This is a short documentation comment. */
Kotlin
복사
일반적으로 @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): Int { /*...*/ } // Do this instead: /** * Returns the absolute value of the given [number]. */ fun abs(number: Int): Int { /*...*/ }
Kotlin
복사

중복된 구조를 피하라

일반적으로 Kotlin의 특정 구문 구조가 선택 사항이고 IDE에서 중복으로 강조 표시되면 코드에서 생략해야 한다.
명확성을 위해 불필요한 구문 요소를 코드에 남기지마라.

Unit 반환 타입

함수가 Unit을 반환하는 경우 반환 타입은 생략해야 한다.
fun foo() { // ": Unit" is omitted here }
Kotlin
복사

세미콜론

가능한 세미콜론을 생략하라.

문자열 템플릿

문자열 템플릿에 간단한 변수를 삽입할 때는 중괄호를 사용하지마라.
긴 표현식에만 중괄호를 사용하라.
println("$name has ${children.size} children")
Kotlin
복사

언어적 특징의 관용적 사용

불변성

변경 가능한 데이터보다 변경 불가능한 데이터를 사용하는 것을 선호하라.
초기화 후 수정되지 않는 경우 var 보다 val 을 사용하여 로컬 변수와 프로퍼티를 선언하라.
항상 불변 컬렉션 인터페이스를 사용하여 변형되지 않는 컬렉션을 선언하라.
팩토리 함수를 사용하여 컬렉션 인스턴스를 만들 때는 가능한 경우 항상 불변 컬렉션 타입을 반환하는 함수를 사용하라.
// Bad: use of a 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
복사

기본 매개변수 값

오버로드된 함수를 선언하는 것보다 기본 매개변수 값을 사용하여 함수를 선언하는 것을 사용하라.
// Bad fun foo() = foo("a") fun foo(a: String) { /*...*/ } // Good fun foo(a: String = "a") { /*...*/ }
Kotlin
복사

타입 별칭

코드베이스에서 여러 번 사용되는 함수의 타입이나 타입 매개변수가 있는 타입이 있는 경우 해당 타입에 대한 타입 별칭을 정의하는 것이 좋다.
typealias MouseClickHandler = (Any, MouseEvent) -> Unit typealias PersonIndex = Map<String, Person>
Kotlin
복사
이름 충돌을 피하기 위해 private 또는 internal 타입 별칭을 사용하는 경우 import … as … 를 사용하라.

람다 매개변수

짧고 중첩되지 않은 람다에서는 매개변수를 명시적으로 선언하는 대신 it 을 사용하는 것이 좋다.
매개변수가 있는 중첩된 람다에서는 항상 매개변수를 명시적으로 선언해야한다.
// 'it'을 사용하여 매개변수를 명시하지 않는 경우 val doubled = numbers.map { it * 2 } // 중첩된 람다에서 매개변수를 명시적으로 선언하는 경우 val result = numbers.map { num -> (1..num).map { innerNum -> innerNum * 2 } }
Kotlin
복사

람다로 반환

람다에서 여러 라벨이 붙은 리턴을 사용하지마라.
람다를 재구성하여 단일 종료 지점을 갖도록 하는 것을 고려하라.
이것이 불가능하거나 충분히 명확하지 않다면 람다를 익명 함수로 변환하는 것을 고려하라.
람다의 마지막 문장에는 라벨이 붙은 return을 사용하지마라.
//여러 라벨이 붙은 리턴 val found = numbers.map { number -> run { if (number == 3) return@map "Found 3" "Not 3" } } //단일 종료 지점을 갖도록 재구성 val found = numbers.map { number -> if (number == 3) { "Found 3" } else { "Not 3" } } //람다를 익명 함수로 변환 val found = numbers.map(fun(number): String { return if (number == 3) { "Found 3" } else { "Not 3" } }) //라벨이 붙은 리턴을 사용하지 않고 단순히 값을 반환 val found = numbers.map { number -> if (number == 3) "Found 3" else "Not 3" }
Kotlin
복사

Named arguments

메서드가 동일한 기본 유형 또는 Boolean 타입의 여러 매개변수를 받는 경우 모든 매개변수의 의미가 문맥상 완벽하게 명확하지 않는 한 명명된 인수 구문을 사용하라.
drawSquare(x = 10, y = 10, width = 100, height = 100, fill = true)
Kotlin
복사

조건문 표현식

try, if, when의 표현식을 사용하는 것이 좋다.
// Good return if (x) foo() else bar() // Bad if (x) return foo() else return bar()
Kotlin
복사
// Good return when(x) { 0 -> "zero" else -> "nonzero" } // Bad when(x) { 0 -> return "zero" else -> return "nonzero" }
Kotlin
복사

when 대신 if

바이너리 조건에 대해 when 대신 if를 사용하라
when 은 분기가 3개 이상인 경우 사용하는 것이 좋다.
// Good if (x == null) ... else ... // Bad when (x) { null -> // ... else -> // ... }
Kotlin
복사

조건에서 Nullable Boolean

조건문에서 nullable Boolean을 사용해야 하는 경우 true나 false로 명시적으로 비교하라.
명시적으로 비교해야 null에 안전하게 사용할 수 있다.
if (value == true) if (value == false)
Kotlin
복사

반복문

반복문을 사용할 때는 filter, map 같은 고차 함수를 사용하라.
단, forEach는 nullable하거나 해당 함수가 긴 호출 체인의 일부로 상요된다면 전통적인 for문을 사용하라.

범위의 반복

..< 연산자를 사용하여 개방형 범위를 반복하라.
for (i in 0..n - 1) { /*...*/ } // bad for (i in 0..<n) { /*...*/ } // good
Kotlin
복사

문자열

문자열 연결보다 문자열 템플릿을 사용하라.
일반 문자열 리터럴에 이스케이프 시퀀스를 내장하는 것보다 다중 줄 문자열을 사용하는 것이 좋다.
다중 줄 문자열에서 들여쓰기를 유지하려면 trimIndent(), trinMargin()을 사용하라.
trimIndent() : 공통 최소 들여쓰기를 감지하고 모든 줄에서 제거한다.
trimMargin() : 들여쓰기의 기준이 되는 문자열을 두고 그 부분까지 제거한다.
println(""" Not trimmed text """ ) println(""" Trimmed text """.trimIndent() ) println() val a = """Trimmed to margin text: |if(a > 1) { | return a |}""".trimMargin() println(a)
Kotlin
복사

함수 vs 프로퍼티

몇몇 경우에 매개변수가 없는 함수는 read-only 프로퍼티와 서로 호환된다.
서로 문법은 비슷하지만 둘 중 어느 하나를 사용해야 하는 스타일적인 규칙이 존재한다.
함수보다 프로퍼티를 사용해야 하는 경우
예외를 던지지 않는 경우
계산 비용이 적거나 캐시되는 경우
상태가 변경되지 않는 경우
//함수 class Circle(private val radius: Double) { fun getArea(): Double { return Math.PI * radius * radius } } //프로퍼티 class Circle(private val radius: Double) { val area: Double get() = Math.PI * radius * radius }
Kotlin
복사

확장 함수

확장 함수를 적극적으로 사용하라.
주로 객체에서 작동하는 함수가 있을 때마다 해당 객체를 수신자로 허용하는 확장 함수로 만드는 것을 고려하라.
API 오염을 최소화하려면 확장 함수의 가시성을 합리적인 한에서 제한하라.
필요에 따라 로컬 확장 함수, 멤버 확장 함수 또는 비공개 가시성이 있는 최상위 확장 함수를 사용하라.
//로컬 확장 함수 fun someFunction() { fun String.localReverse(): String { return this.reversed() } val result = "Kotlin".localReverse() } //멤버 확장 함수 class Example { fun String.memberReverse(): String { return this.reversed() } } //최상위 확장 함수 private fun String.topLevelReverse(): String { return this.reversed() }
Kotlin
복사

중위 함수

비슷한 역할을 하는 두 객체가 있을 땐 infix 키워드로 함수를 정의하라.
좋은 예 : and, to, zip
나쁜 예 : add
infix 메서드가 수신 객체를 수정한다면 정의하지마라.
infix fun Int.isEqualTo(other: Int): Boolean { return this == other } fun main() { val result = 5 isEqualTo 5 println(result) // 출력: true val result2 = 5 isEqualTo 10 println(result2) // 출력: false }
Kotlin
복사

팩토리 함수

클래스에 팩토리 함수를 선언하는 경우 클래스 자체와 동일한 이름을 지정하지 마라.
고유한 이름을 사용하여 팩토리 함수의 동작이 특별한 이유를 명확히 하는 것이 좋다.
특별한 의미가 없는 경우에만 클래스와 동일한 이름을 사용할 수 있다.
class Point(val x: Double, val y: Double) { companion object { fun fromPolar(angle: Double, radius: Double) = Point(...) } }
Kotlin
복사
서로 다른 슈퍼클래스 생성자를 호출하지 않고 기본 인수 값을 가진 단일 생성자로 줄일 수 없는 여러 개의 오버로드된 생성자가 있는 객체인 경우 오버로드된 생성자를 팩토리 함수로 대체하는 것이 좋다.

플랫폼 타입

플랫폼 타입의 표현식을 반환하는 공개 함수/메서드는 Kotlin 타입을 명시적으로 선언해야 한다.
fun apiCall(): String = MyJavaApi.getProperty("name")
Kotlin
복사
플랫폼 타입의 표현식으로 초기화된 모든 프로퍼티(패키지 수준 또는 클래스 수준)은 해당 Kotlin 타입을 명시적으로 선언해야 한다.
class Person { val name: String = MyJavaApi.getProperty("name") }
Kotlin
복사
플랫폼 타입의 표현식으로 초기화된 로컬 변수는 타입 선언이 있을 수도 있고 없을 수도 있다.
fun main() { val name = MyJavaApi.getProperty("name") println(name) }
Kotlin
복사

스코프 함수

Kotlin은 주어진 객체의 컨텍스트에서 코드 블록을 실행하는 함수 집합을 제공한다.
// let fun main() { val name: String? = "Kotlin" name?.let { println("The name is $it") } } // run fun main() { val result = "Kotlin".run { length * 2 } println("The result is $result") } // with fun main() { val person = Person("Alice", 30) val description = with(person) { "$name is $age years old" } println(description) } data class Person(val name: String, val age: Int) // apply fun main() { val person = Person("Alice", 30).apply { name = "Bob" age = 25 } println(person) } data class Person(var name: String, var age: Int) // also fun main() { val number = 10.also { println("The number is $it") } println("The final number is $number") }
Kotlin
복사

라이브러리에 대한 코딩 규칙

라이브러리를 작성할 때 API 안정성을 보장하기 위해 다음과 같은 추가 규칙을 따르는 것이 좋다.
항상 멤버 가시성을 명시적으로 지정하라. (실수로 선언을 공개 API로 노출하는 것을 방지하기 위해)
항상 함수 반환 타입과 프로퍼티 타입을 명시적으로 지정하라. (구현이 변경될 때 반환 타입이 실수로 변경되는 것을 방지하기 위해)
새로운 문서가 필요하지 않은 오버라이드를 제외한 모든 공개 멤버에 대해 KDoc 주석을 제공한다. (라이브러리에 대한 문서 생성을 지원하기 위함)