5.8 KiB
Кotlin
Based on Kotlin Coding Conventions
This document supplements and also redefines certain provisions of these standards. In case of conflict follow this document.
General points
- 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.
Naming
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 |
Imports
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.
Formatting
Line length
Maximum line length - 120 characters.
Vertical indentation
Methods must be separated from each other by one empty line.
Curly braces
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() {
}
Expression bodies
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
}
Return types
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
Comments must be written only in English.
Idiomatic use of language features
public lateinit
Don't use lateinit modifier for public properties.
Bad:
lateinit var someString: String
Nullability
- Unsafe operator
!!is not allowed. - Elvis operator is preferred.
Good:
optional?.doSomething()
Bad:
if (optional != null) {
optional.doSomething()
}
optional!!.doSomething()
Named arguments
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)
Extension functions
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)
Enum vs @IntDef/@StringDef
In all cases, the use of enum class or sealed class is recommended instead of @IntDef/@StringDef annotations.
Scope functions apply/with/run/also/let
It is recommended to:
- Use
applyto 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).