Based on Kotlin Coding Conventions
This document supplements and also redefines certain provisions of these standards. In case of conflict follow this document.
- The principle of consistency should be used: new (or fixed) code should follow the style of the code written around it. Since different variations of text layout are allowed, it is necessary to adhere to the same approach and style within the same file.
- You should not use Java-familiar approaches when alternative Kotlin-style approaches are available. In other words, don't try to write Kotlin like Java.
Names of classes, fields, variables and parameters should be chosen from English words (transliteration is not allowed) or established abbreviations (abbreviations should be used as words). Unknown abbreviations should not be used.
Good | Bad |
---|---|
Separator | Razdelitel |
XmlHttpRequest | XMLHTTPRequest |
getId | getID |
class Html | class HTML |
url: String | URL: String |
id: Long | ID: Long |
JustOneNewAcro | JONA |
Each import
statement must be written on one line without breaks. The list of expressions should be sorted alphabetically and should not contain unused imports.
Wildcards are forbidden.
Maximum line length - 120 characters.
Methods must be separated from each other by one empty line.
Don't use curly braces in single-line if
statement. In multiline if
statements curly braces must be used.
Good:
val myVal = if (condition) 1 else 0
if (condition) doSomething()
if (condition1) {
doSomething1()
doSomething2()
doSomething3()
}
if (condition2) {
value = Value.builder()
.someThing1(someThing1)
.someThing2(someThing2)
.someThing3(someThing3)
.build()
}
In methods with an empty implementation, curly braces should be replaced with the Unit
expression.
Good:
override fun empty() = Unit
Bad:
override fun empty() {
}
Always use expression body of functions in case of trivial expressions.
Good:
fun sum(a: Int, b: Int) = a + b
Bad:
fun sum(a: Int, b: Int): Int {
return a + b
}
For more complex expressions, you can use the expression body in case of single-line statement, including the situation with line wrapping to the next 1 (according to the rules for wrapping long statements)
Good:
// 1 line
fun doPerform() = actionFactory.createPerformer.perform()
// 1 line with a break
fun dispatchNextState(mode: CaptureMode = null): Unit =
fallbackStateDispatcher.dispatchByMode(captureMode = mode ?: CaptureMode.DEFAULT, oldState = currentState)
Bad:
fun doEither(condition: Boolean): Result =
if (condition) {
myPerformer.doActual()
} else {
Result.FAIL
}
fun doEither(condition: Boolean?): Result =
when (condition) {
true -> Result.SUCCESS
null -> Result.UNKNOWN
false -> Result.FAIL
}
Declare type explicitly if:
- function is a part of public api
- it's not clear what will be returned
- should pay attention to the type
- platform type is used
Good:
fun method(a: Type1, b: Type2): Type3 = a.doA(b.getB())
fun sum(a: Int, b: Int): Float = а * b.toFloat()
fun toast(text: String): Toast = Toast.makeText(activity, text, Toast.LENGTH_LONG)
Bad:
fun method(a: Type1, b: Type2) = a.doA(b.getB())
fun sum(a: Int, b: Int) = а * b.toFloat()
fun toast(text: String) = Toast.makeText(activity, text, Toast.LENGTH_LONG)
Don't specify return type if it is obvious.
Good:
fun sum(a: Int, b: Int) = a + b
Bad:
fun sum(a: Int, b: Int): Int = а + b
Comments must be written only in English.
Don't use lateinit
modifier for public properties.
Bad:
lateinit var someString: String
- Unsafe operator
!!
is not allowed. - Elvis operator is preferred.
Good:
optional?.doSomething()
Bad:
if (optional != null) {
optional.doSomething()
}
optional!!.doSomething()
Use the named argument syntax for complex functions with many arguments. If the arguments contain Boolean
and/or primitives, the use of a named call is mandatory. Use of positional parameters only if their meaning is absolutely clear from the context.
Good:
drawSquare(x = 10, y = 10, width = 100, height = 100, fill = true)
Use extension functions instead of utility functions.
Good:
fun String.removeFirstLastChar() = substring(1, length - 1)
Bad:
fun removeFirstLastChar(string: String) = string.substring(1, string.length - 1)
In all cases, the use of enum class
or sealed class
is recommended instead of @IntDef
/@StringDef
annotations.
It is recommended to:
- Use
apply
to set up or initialize an object and avoid using it for logic. - Don't overuse this API and try to keep it readable in natural English style.
- Avoid excessive nesting.
- Do not use nested
with
/run
/apply
. In case of nestedalso
/let
, naming of the argument is required (you can't useit
).