Ali Ahmadabadiha
Placing multiple declarations (classes, top-level functions or properties) in the same Kotlin source file is encouraged as long as these declarations are closely related to each other semantically, and the file size remains reasonable (not exceeding a few hundred lines).
In particular, when defining extension functions for a class which are relevant for all clients of this class, put them in the same file with the class itself. When defining extension functions that make sense only for a specific client, put them next to the code of that client. Avoid creating files just to hold all extensions of some class.
The contents of a class should go in the following order:
Property declarations and initializer blocks
Secondary constructors
Method declarations
Companion object
Do not sort the method declarations alphabetically or by visibility, and do not separate regular methods from extension methods. Instead, put related stuff together, so that someone reading the class from top to bottom can follow the logic of what's happening.
Put nested classes next to the code that uses those classes. If the classes are intended to be used externally and aren't referenced inside the class, put them in the end, after the companion object.
When implementing an interface, keep the implementing members in the same order as members of the interface (if necessary, interspersed with additional private methods used for the implementation).
Always put overloads next to each other in a class.
Always put overloads next to each other in a class.
Names of packages are always lowercase and do not use underscores (org.example.project). Using multi-word names is generally discouraged, but if you do need to use multiple words, you can either just concatenate them together or use the camel case (org.example.myProject).
Names of functions, properties and local variables start with a lowercase letter and use the camel case and no underscores.
Exception: factory functions used to create instances of classes can have the same name as the abstract return type:
Exception: factory functions used to create instances of classes can have the same name as the abstract return type:
interface Foo { /*...*/ }
class FooImpl : Foo { /*...*/ }
fun Foo(): Foo { return FooImpl() }In tests (and only in tests), you can use method names with spaces enclosed in backticks. Note that such method names are only supported by Android runtime from API level 30. Underscores in method names are also allowed in test code.
In tests (and only in tests), you can use method names with spaces enclosed in backticks. Note that such method names are only supported by Android runtime from API level 30. Underscores in method names are also allowed in test code.
class MyTestCase {
@Test fun `ensure everything works`() { /*...*/ }
@Test fun ensureEverythingWorks_onAndroid() { /*...*/ }
}Names of constants (properties marked with const, or top-level or object val properties with no custom get function that hold deeply immutable data) should use uppercase underscore-separated (screaming snake case) names.
For enum constants, it's OK to use either uppercase underscore-separated names (screaming snake case) (enum class Color { RED, GREEN }) or upper camel case names, depending on the usage.
If a class has two properties which are conceptually the same but one is part of a public API and another is an implementation detail, use an underscore as the prefix for the name of the private property.
If a class has two properties which are conceptually the same but one is part of a public API and another is an implementation detail, use an underscore as the prefix for the name of the private property.
class C {
private val _elementList = mutableListOf<Element>()
val elementList: List<Element>
get() = _elementList
}The name of a class is usually a noun or a noun phrase explaining what the class is: List, PersonReader.
The name of a method is usually a verb or a verb phrase saying what the method does: close, readPersons. The name should also suggest if the method is mutating the object or returning a new one. For instance sort is sorting a collection in place, while sorted is returning a sorted copy of the collection.
The names should make it clear what the purpose of the entity is, so it's best to avoid using meaningless words (Manager, Wrapper) in names.
When using an acronym as part of a declaration name, capitalize it if it consists of two letters (IOStream); capitalize only the first letter if it is longer (XmlFormatter, HttpInputStream).
Place annotations on separate lines before the declaration to which they are attached, and with the same indentation:
Place annotations on separate lines before the declaration to which they are attached, and with the same indentation:
@Target(AnnotationTarget.PROPERTY)
annotation class JsonExcludeAnnotations without arguments may be placed on the same line:
Annotations without arguments may be placed on the same line:
@JsonExclude @JvmField
var x: StringA single annotation without arguments may be placed on the same line as the corresponding declaration:
A single annotation without arguments may be placed on the same line as the corresponding declaration:
@Test fun foo() { /*...*/ }File annotations are placed after the file comment (if any), before the package statement, and are separated from package with a blank line (to emphasize the fact that they target the file and not the package).
File annotations are placed after the file comment (if any), before the package statement, and are separated from package with a blank line (to emphasize the fact that they target the file and not the package).
/** License, copyright and whatever */
@file:JvmName("FooBar")
package foo.barPrefer using an expression body for functions with the body consisting of a single expression.
If the function has an expression body whose first line doesn't fit on the same line as the declaration, put the = sign on the first line and indent the expression body by four spaces.
If the function has an expression body whose first line doesn't fit on the same line as the declaration, put the = sign on the first line and indent the expression body by four spaces.
fun f(x: String, y: String, z: String) =
veryLongFunctionCallWithManyWords(andLongParametersToo(), x, y, z)If the condition of an if or when statement is multiline, always use curly braces around the body of the statement. Indent each subsequent line of the condition by four spaces relative to the statement start. Put the closing parentheses of the condition together with the opening curly brace on a separate line:
if (!component.isSyncing &&
!hasAnyKotlinRuntimeInScope(module)
) {
return createKotlinNotConfiguredPanel(module)
}In a when statement, if a branch is more than a single line, consider separating it from adjacent case blocks with a blank line:
In a when statement, if a branch is more than a single line, consider separating it from adjacent case blocks with a blank line:
private fun parsePropertyValue(propName: String, token: Token) {
when (token) {
is Token.ValueToken ->
callback.visitValue(propName, token.value)
Token.LBRACE -> { // ...
}
}
}Put short branches on the same line as the condition, without braces.
Put short branches on the same line as the condition, without braces.
when (foo) {
true -> bar() // good
false -> { baz() } // bad
}In long argument lists, put a line break after the opening parenthesis. Indent arguments by four spaces. Group multiple closely related arguments on the same line.
In long argument lists, put a line break after the opening parenthesis. Indent arguments by four spaces. Group multiple closely related arguments on the same line.
drawSquare(
x = 10, y = 10,
width = 100, height = 100,
fill = true
)When wrapping chained calls, put the . character or the ?. operator on the next line, with a single indent:
When wrapping chained calls, put the . character or the ?. operator on the next line, with a single indent:
val anchor = owner
?.firstChild!!
.siblings(forward = true)
.dropWhile { it is PsiComment || it is PsiWhiteSpace }When declaring parameter names in a multiline lambda, put the names on the first line, followed by the arrow and the newline:
When declaring parameter names in a multiline lambda, put the names on the first line, followed by the arrow and the newline:
appendCommaSeparated(properties) { prop ->
val propertyValue = prop.get(obj) // ...
}If the parameter list is too long to fit on a line, put the arrow on a separate line:
If the parameter list is too long to fit on a line, put the arrow on a separate line:
foo {
context: Context,
environment: Env
->
context.configureEnv(environment)
}A trailing comma is a comma symbol after the last item in a series of elements:
class Person(
val firstName: String,
val lastName: String,
val age: Int, // trailing comma
)Using trailing commas has several benefits:
It makes version-control diffs cleaner – as all the focus is on the changed value.
It makes it easy to add and reorder elements – there is no need to add or delete the comma if you manipulate elements.
It simplifies code generation, for example, for object initializers. The last element can also have a comma.
Trailing commas are entirely optional – your code will still work without them. The Kotlin style guide encourages the use of trailing commas at the declaration site and leaves it at your discretion for the call site.
For longer documentation comments, place the opening /** on a separate line and begin each subsequent line with an asterisk:
For longer documentation comments, place the opening /** on a separate line and begin each subsequent line with an asterisk:
/**
* This is a documentation comment
* on multiple lines.
*/Short comments can be placed on a single line:
/** This is a short documentation comment. */Generally, avoid using @param and @return tags. Instead, incorporate the description of parameters and return values directly into the documentation comment, and add links to parameters wherever they are mentioned. Use @param and @return only when a lengthy description is required which doesn't fit into the flow of the main text.
// 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 { /*...*/ }Prefer using immutable data to mutable. Always declare local variables and properties as val rather than var if they are not modified after initialization.
Always use immutable collection interfaces (Collection, List, Set, Map) to declare collections which are not mutated. When using factory functions to create collection instances, always use functions that return immutable collection types when possible:
// 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")Prefer declaring functions with default parameter values to declaring overloaded functions.
Prefer declaring functions with default parameter values to declaring overloaded functions.
// Bad
fun foo() = foo("a")
fun foo(a: String) { /*...*/ }
// Good
fun foo(a: String = "a") { /*...*/ }In lambdas which are short and not nested, it's recommended to use the it convention instead of declaring the parameter explicitly. In nested lambdas with parameters, always declare parameters explicitly.
Avoid using multiple labeled returns in a lambda. Consider restructuring the lambda so that it will have a single exit point. If that's not possible or not clear enough, consider converting the lambda into an anonymous function.
Do not use a labeled return for the last statement in a lambda.
Use the named argument syntax when a method takes multiple parameters of the same primitive type, or for parameters of Boolean type, unless the meaning of all parameters is absolutely clear from context.
drawSquare(x = 10, y = 10, width = 100, height = 100, fill = true)If you need to use a nullable Boolean in a conditional statement, use if (value == true) or if (value == false) checks.
Prefer using higher-order functions (filter, map etc.) to loops. Exception: forEach (prefer using a regular for loop instead, unless the receiver of forEach is nullable or forEach is used as part of a longer call chain).
When making a choice between a complex expression using multiple higher-order functions and a loop, understand the cost of the operations being performed in each case and keep performance considerations in mind.
Prefer string templates to string concatenation.
Prefer multiline strings to embedding \n escape sequences into regular string literals.
To maintain indentation in multiline strings, use trimIndent when the resulting string does not require any internal indentation, or trimMargin when internal indentation is required:
println("""
Not
trimmed
text
"""
)
println("""
Trimmed
text
""".trimIndent()
)
println()
val a = """Trimmed to margin text:
|if(a > 1) {
| return a
|}""".trimMargin()
println(a)println("""
Not
trimmed
text
"""
)
println("""
Trimmed
text
""".trimIndent()
)
println()
val a = """Trimmed to margin text:
|if(a > 1) {
| return a
|}""".trimMargin()
println(a)
Not
trimmed
text
Trimmed
text
Trimmed to margin text:
if(a > 1) {
return a
}
Use extension functions liberally. Every time you have a function that works primarily on an object, consider making it an extension function accepting that object as a receiver. To minimize API pollution, restrict the visibility of extension functions as much as it makes sense. As necessary, use local extension functions, member extension functions, or top-level extension functions with private visibility.
If you declare a factory function for a class, avoid giving it the same name as the class itself. Prefer using a distinct name, making it clear why the behavior of the factory function is special. Only if there is really no special semantics, you can use the same name as the class.
If you declare a factory function for a class, avoid giving it the same name as the class itself. Prefer using a distinct name, making it clear why the behavior of the factory function is special. Only if there is really no special semantics, you can use the same name as the class.
class Point(val x: Double, val y: Double) {
companion object {
fun fromPolar(angle: Double, radius: Double) = Point(...)
}
}If you have an object with multiple overloaded constructors that don't call different superclass constructors and can't be reduced to a single constructor with default argument values, prefer to replace the overloaded constructors with factory functions.
When writing libraries, it's recommended to follow an additional set of rules to ensure API stability:
Always explicitly specify member visibility (to avoid accidentally exposing declarations as public API)
Always explicitly specify function return types and property types (to avoid accidentally changing the return type when the implementation changes)
Provide KDoc comments for all public members, except for overrides that do not require any new documentation (to support generating documentation for the library)
class Point(val x: Double, val y: Double) {
companion object {
fun fromPolar(angle: Double, radius: Double) = Point(...)
}
}class Point(val x: Double, val y: Double) {
companion object {
fun fromPolar(angle: Double, radius: Double) = Point(...)
}
}A Kotlin source file is described as being in Google Android Style if and only if it adheres to the rules herein.
Like other programming style guides, the issues covered span not only aesthetic issues of formatting, but other types of conventions or coding standards as well. However, this document focuses primarily on the hard-and-fast rules that we follow universally, and avoids giving advice that isn’t clearly enforceable (whether by human or tool).
class Point(val x: Double, val y: Double) {
companion object {
fun fromPolar(angle: Double, radius: Double) = Point(...)
}
}If a source file contains only a single top-level class, the file name should reflect the case-sensitive name plus the .kt extension. Otherwise, if a source file contains multiple top-level declarations, choose a name that describes the contents of the file, apply PascalCase (camelCase is acceptable if the filename is plural), and append the .kt extension.
class Point(val x: Double, val y: Double) {
companion object {
fun fromPolar(angle: Double, radius: Double) = Point(...)
}
}class Point(val x: Double, val y: Double) {
companion object {
fun fromPolar(angle: Double, radius: Double) = Point(...)
}
}// MyClass.kt
class MyClass { }// Bar.kt
class Bar { }
fun Runnable.toBar(): Bar = // …// Map.kt
fun <T, O> Set<T>.map(func: (T) -> O): List<O> = // …
fun <T, O> List<T>.map(func: (T) -> O): List<O> = // …// extensions.kt
fun MyClass.process() = // …
fun MyResult.print() = // …A .kt file comprises the following, in order:
Exactly one blank line separates each of these sections.
class Point(val x: Double, val y: Double) {
companion object {
fun fromPolar(angle: Double, radius: Double) = Point(...)
}
}A .kt file comprises the following, in order:
Exactly one blank line separates each of these sections.
class Point(val x: Double, val y: Double) {
companion object {
fun fromPolar(angle: Double, radius: Double) = Point(...)
}
}Annotations with the "file" use-site target are placed between any header comment and the package declaration.
class Point(val x: Double, val y: Double) {
companion object {
fun fromPolar(angle: Double, radius: Double) = Point(...)
}
}The package statement is not subject to any column limit and is never line-wrapped.
class Point(val x: Double, val y: Double) {
companion object {
fun fromPolar(angle: Double, radius: Double) = Point(...)
}
}Import statements for classes, functions, and properties are grouped together in a single list and ASCII sorted.
Wildcard imports (of any type) are not allowed.
Similar to the package statement, import statements are not subject to a column limit and they are never line-wrapped.
class Point(val x: Double, val y: Double) {
companion object {
fun fromPolar(angle: Double, radius: Double) = Point(...)
}
}The contents of a file should be focused on a single theme. Examples of this would be a single public type or a set of extension functions performing the same operation on multiple receiver types. Unrelated declarations should be separated into their own files and public declarations within a single file should be minimized.
class Point(val x: Double, val y: Double) {
companion object {
fun fromPolar(angle: Double, radius: Double) = Point(...)
}
}No explicit restriction is placed on the number nor order of the contents of a file.
Source files are usually read from top-to-bottom meaning that the order, in general, should reflect that the declarations higher up will inform understanding of those farther down. Different files may choose to order their contents differently. Similarly, one file may contain 100 properties, another 10 functions, and yet another a single class.
class Point(val x: Double, val y: Double) {
companion object {
fun fromPolar(angle: Double, radius: Double) = Point(...)
}
}What is important is that each file uses some logical order, which its maintainer could explain if asked. For example, new functions are not just habitually added to the end of the file, as that would yield “chronological by date added” ordering, which is not a logical ordering.
class Point(val x: Double, val y: Double) {
companion object {
fun fromPolar(angle: Double, radius: Double) = Point(...)
}
}The order of members within a class follow the same rules as the top-level declarations.
class Point(val x: Double, val y: Double) {
companion object {
fun fromPolar(angle: Double, radius: Double) = Point(...)
}
}Braces are not required for when branches and if expressions which have no more than one else branch and which fit on a single line.
class Point(val x: Double, val y: Double) {
companion object {
fun fromPolar(angle: Double, radius: Double) = Point(...)
}
}Braces are not required for when branches and if expressions which have no more than one else branch and which fit on a single line.
class Point(val x: Double, val y: Double) {
companion object {
fun fromPolar(angle: Double, radius: Double) = Point(...)
}
}if (string.isEmpty()) return
val result =
if (string.isEmpty()) DEFAULT_VALUE else string
when (value) {
0 -> return
// …
}Braces are otherwise required for any if, for, when branch, do, and while statements and expressions, even when the body is empty or contains only a single statement.
class Point(val x: Double, val y: Double) {
companion object {
fun fromPolar(angle: Double, radius: Double) = Point(...)
}
}if (string.isEmpty())
return // WRONG!
if (string.isEmpty()) {
return // Okay
}
if (string.isEmpty()) return // WRONG
else doLotsOfProcessingOn(string, otherParametersHere)
if (string.isEmpty()) {
return // Okay
} else {
doLotsOfProcessingOn(string, otherParametersHere)
}Braces follow the Kernighan and Ritchie style ("Egyptian brackets") for nonempty blocks and block-like constructs:
class Point(val x: Double, val y: Double) {
companion object {
fun fromPolar(angle: Double, radius: Double) = Point(...)
}
}else or a comma.A few exceptions for enum classes are given later.
class Point(val x: Double, val y: Double) {
companion object {
fun fromPolar(angle: Double, radius: Double) = Point(...)
}
}class Point(val x: Double, val y: Double) {
companion object {
fun fromPolar(angle: Double, radius: Double) = Point(...)
}
}return Runnable {
while (condition()) {
foo()
}
}
return object : MyClass() {
override fun foo() {
if (condition()) {
try {
something()
} catch (e: ProblemException) {
recover()
}
} else if (otherCondition()) {
somethingElse()
} else {
lastThing()
}
}
}An empty block or block-like construct must be in K&R style.
class Point(val x: Double, val y: Double) {
companion object {
fun fromPolar(angle: Double, radius: Double) = Point(...)
}
}try {
doSomething()
} catch (e: Exception) {} // WRONG!try {
doSomething()
} catch (e: Exception) {
} // OkayAn if/else conditional that is used as an expression may omit braces only if the entire expression fits on one line.
class Point(val x: Double, val y: Double) {
companion object {
fun fromPolar(angle: Double, radius: Double) = Point(...)
}
}An if/else conditional that is used as an expression may omit braces only if the entire expression fits on one line.
class Point(val x: Double, val y: Double) {
companion object {
fun fromPolar(angle: Double, radius: Double) = Point(...)
}
}val value = if (string.isEmpty()) 0 else 1 // Okayval value = if (string.isEmpty()) // WRONG!
0
else
1val value = if (string.isEmpty()) { // Okay
0
} else {
1
}Each time a new block or block-like construct is opened, the indent increases by four spaces. When the block ends, the indent returns to the previous indent level. The indent level applies to both code and comments throughout the block.
class Point(val x: Double, val y: Double) {
companion object {
fun fromPolar(angle: Double, radius: Double) = Point(...)
}
}Each statement is followed by a line break. Semicolons are not used.
class Point(val x: Double, val y: Double) {
companion object {
fun fromPolar(angle: Double, radius: Double) = Point(...)
}
}Code has a column limit of 100 characters. Except as noted below, any line that would exceed this limit must be line-wrapped, as explained below.
Exceptions:
package and import statementsclass Point(val x: Double, val y: Double) {
companion object {
fun fromPolar(angle: Double, radius: Double) = Point(...)
}
}The prime directive of line-wrapping is: prefer to break at a higher syntactic level. Also:
., ?.).::).class Point(val x: Double, val y: Double) {
companion object {
fun fromPolar(angle: Double, radius: Double) = Point(...)
}
}() that follows it.,) stays attached to the token that precedes it.->) stays attached to the argument list that precedes it.class Point(val x: Double, val y: Double) {
companion object {
fun fromPolar(angle: Double, radius: Double) = Point(...)
}
}When a function signature does not fit on a single line, break each parameter declaration onto its own line. Parameters defined in this format should use a single indent (+4). The closing parenthesis ()) and return type are placed on their own line with no additional indent.
class Point(val x: Double, val y: Double) {
companion object {
fun fromPolar(angle: Double, radius: Double) = Point(...)
}
}class Point(val x: Double, val y: Double) {
companion object {
fun fromPolar(angle: Double, radius: Double) = Point(...)
}
}fun <T> Iterable<T>.joinToString(
separator: CharSequence = ", ",
prefix: CharSequence = "",
postfix: CharSequence = ""
): String {
// …
}When a function contains only a single expression it can be represented as an expression function.
class Point(val x: Double, val y: Double) {
companion object {
fun fromPolar(angle: Double, radius: Double) = Point(...)
}
}override fun toString(): String {
return "Hey"
}override fun toString(): String = "Hey"
Properties declaring a get and/or set function should place each on their own line with a normal indent (+4). Format them using the same rules as functions.
class Point(val x: Double, val y: Double) {
companion object {
fun fromPolar(angle: Double, radius: Double) = Point(...)
}
}var directory: File? = null
set(value) {
// …
}
Read-only properties can use a shorter syntax which fits on a single line.
class Point(val x: Double, val y: Double) {
companion object {
fun fromPolar(angle: Double, radius: Double) = Point(...)
}
}val defaultExtension: String get() = "kt"
Read-only properties can use a shorter syntax which fits on a single line.
class Point(val x: Double, val y: Double) {
companion object {
fun fromPolar(angle: Double, radius: Double) = Point(...)
}
}val defaultExtension: String get() = "kt"
A single blank line appears:
class Point(val x: Double, val y: Double) {
companion object {
fun fromPolar(angle: Double, radius: Double) = Point(...)
}
}class Point(val x: Double, val y: Double) {
companion object {
fun fromPolar(angle: Double, radius: Double) = Point(...)
}
}class Point(val x: Double, val y: Double) {
companion object {
fun fromPolar(angle: Double, radius: Double) = Point(...)
}
}Multiple consecutive blank lines are permitted, but not encouraged or ever required.
class Point(val x: Double, val y: Double) {
companion object {
fun fromPolar(angle: Double, radius: Double) = Point(...)
}
}An enum with no functions and no documentation on its constants may optionally be formatted as a single line.
class Point(val x: Double, val y: Double) {
companion object {
fun fromPolar(angle: Double, radius: Double) = Point(...)
}
}enum class Answer { YES, NO, MAYBE }
When the constants in an enum are placed on separate lines, a blank line is not required between them except in the case where they define a body.
class Point(val x: Double, val y: Double) {
companion object {
fun fromPolar(angle: Double, radius: Double) = Point(...)
}
}enum class Answer {
YES,
NO,
MAYBE {
override fun toString() = """¯\_(ツ)_/¯"""
}
}
Member or type annotations are placed on separate lines immediately prior to the annotated construct.
class Point(val x: Double, val y: Double) {
companion object {
fun fromPolar(angle: Double, radius: Double) = Point(...)
}
}@Retention(SOURCE)
@Target(FUNCTION, PROPERTY_SETTER, FIELD)
annotation class GlobalAnnotations without arguments can be placed on a single line.
class Point(val x: Double, val y: Double) {
companion object {
fun fromPolar(angle: Double, radius: Double) = Point(...)
}
}@JvmField @Volatile
var disposable: Disposable? = nullWhen only a single annotation without arguments is present, it may be placed on the same line as the declaration.
class Point(val x: Double, val y: Double) {
companion object {
fun fromPolar(angle: Double, radius: Double) = Point(...)
}
}@Volatile var disposable: Disposable? = null
@Test fun selectAll() {
// …
}When only a single annotation without arguments is present, it may be placed on the same line as the declaration.
class Point(val x: Double, val y: Double) {
companion object {
fun fromPolar(angle: Double, radius: Double) = Point(...)
}
}@Volatile var disposable: Disposable? = null
@Test fun selectAll() {
// …
}If an expression function body or a property initializer is a scalar value or the return type can be clearly inferred from the body then it can be omitted.
class Point(val x: Double, val y: Double) {
companion object {
fun fromPolar(angle: Double, radius: Double) = Point(...)
}
}override fun toString(): String = "Hey"
// becomes
override fun toString() = "Hey"When writing a library, retain the explicit type declaration when it is part of the public API.
class Point(val x: Double, val y: Double) {
companion object {
fun fromPolar(angle: Double, radius: Double) = Point(...)
}
}Package names are all lowercase, with consecutive words simply concatenated together (no underscores).
class Point(val x: Double, val y: Double) {
companion object {
fun fromPolar(angle: Double, radius: Double) = Point(...)
}
}Class names are written in PascalCase and are typically nouns or noun phrases. For example, Character or ImmutableList. Interface names may also be nouns or noun phrases (for example, List), but may sometimes be adjectives or adjective phrases instead (for example Readable).
class Point(val x: Double, val y: Double) {
companion object {
fun fromPolar(angle: Double, radius: Double) = Point(...)
}
}Test classes are named starting with the name of the class they are testing, and ending with Test. For example, HashTest or HashIntegrationTest.
class Point(val x: Double, val y: Double) {
companion object {
fun fromPolar(angle: Double, radius: Double) = Point(...)
}
}Function names are written in camelCase and are typically verbs or verb phrases. For example, sendMessage or stop.
Underscores are permitted to appear in test function names to separate logical components of the name.
class Point(val x: Double, val y: Double) {
companion object {
fun fromPolar(angle: Double, radius: Double) = Point(...)
}
}Functions annotated with @Composable that return Unit are PascalCased and named as nouns, as if they were types.
class Point(val x: Double, val y: Double) {
companion object {
fun fromPolar(angle: Double, radius: Double) = Point(...)
}
}Constant names use UPPER_SNAKE_CASE: all uppercase letters, with words separated by underscores. But what is a constant, exactly?
class Point(val x: Double, val y: Double) {
companion object {
fun fromPolar(angle: Double, radius: Double) = Point(...)
}
}Constants are val properties with no custom get function, whose contents are deeply immutable, and whose functions have no detectable side-effects. This includes immutable types and immutable collections of immutable types as well as scalars and string if marked as const. If any of an instance’s observable state can change, it is not a constant. Merely intending to never mutate the object is not enough.
class Point(val x: Double, val y: Double) {
companion object {
fun fromPolar(angle: Double, radius: Double) = Point(...)
}
}class Point(val x: Double, val y: Double) {
companion object {
fun fromPolar(angle: Double, radius: Double) = Point(...)
}
}const val NUMBER = 5
val NAMES = listOf("Alice", "Bob")
val AGES = mapOf("Alice" to 35, "Bob" to 32)
val COMMA_JOINER = Joiner.on(',') // Joiner is immutable
val EMPTY_ARRAY = arrayOfThese names are typically nouns or noun phrases.
Constant values can only be defined inside of an object or as a top-level declaration. Values otherwise meeting the requirement of a constant but defined inside of a class must use a non-constant name.
Constants which are scalar values must use the const modifier.
class Point(val x: Double, val y: Double) {
companion object {
fun fromPolar(angle: Double, radius: Double) = Point(...)
}
}Non-constant names are written in camelCase. These apply to instance properties, local properties, and parameter names.
These names are typically nouns or noun phrases.
class Point(val x: Double, val y: Double) {
companion object {
fun fromPolar(angle: Double, radius: Double) = Point(...)
}
}When a backing property is needed, its name should exactly match that of the real property except prefixed with an underscore.
class Point(val x: Double, val y: Double) {
companion object {
fun fromPolar(angle: Double, radius: Double) = Point(...)
}
}Each type variable is named in one of two styles:
E, T, X, T2)T (such as RequestT, FooBarT)class Point(val x: Double, val y: Double) {
companion object {
fun fromPolar(angle: Double, radius: Double) = Point(...)
}
}Prose form Correct Incorrect
| "XML Http Request" | XmlHttpRequest |
XMLHTTPRequest |
| "new customer ID" | newCustomerId |
newCustomerID |
| "inner stopwatch" | innerStopwatch |
innerStopWatch |
| "supports IPv6 on iOS" | supportsIpv6OnIos |
supportsIPv6OnIOS |
| "YouTube importer" | YouTubeImporter |
YoutubeImporter |
class Point(val x: Double, val y: Double) {
companion object {
fun fromPolar(angle: Double, radius: Double) = Point(...)
}
}Prose form Correct Incorrect
| "XML Http Request" | XmlHttpRequest |
XMLHTTPRequest |
| "new customer ID" | newCustomerId |
newCustomerID |
| "inner stopwatch" | innerStopwatch |
innerStopWatch |
| "supports IPv6 on iOS" | supportsIpv6OnIos |
supportsIPv6OnIOS |
| "YouTube importer" | YouTubeImporter |
YoutubeImporter |
class Point(val x: Double, val y: Double) {
companion object {
fun fromPolar(angle: Double, radius: Double) = Point(...)
}
}https://kotlinlang.org/docs/coding-conventions.html
https://developer.android.com/kotlin/style-guide
class Point(val x: Double, val y: Double) {
companion object {
fun fromPolar(angle: Double, radius: Double) = Point(...)
}
}