Hello Readers, CoolMonkTechie heartily welcomes you in this article (Understanding Kotlin Style Guide).
In this article, We will learn about the Kotlin Style Guide. This article serves as the complete definition of Google’s Android coding standards for source code in the Kotlin Programming Language. 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 article 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).
A famous quote about learning is :
” We now accept the fact that learning is a lifelong process of keeping abreast of change. And the most pressing task is to teach people how to learn. “
So Let’s begin.
1. Source Files
All source files must be encoded as UTF-8.
1.1. Naming
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, and append the .kt
extension.
// 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> = // …
1.2. Special Characters
1.2.1. Whitespace Characters
Aside from the line terminator sequence, the ASCII horizontal space character (0x20) is the only whitespace character that appears anywhere in a source file. This implies that:
- All other whitespace characters in string and character literals are escaped.
- Tab characters are not used for indentation.
1.2.2. Special Escape Sequences
For any character that has a special escape sequence (\b
, \n
, \r
, \t
, \'
, \"
, \\
, and \$
), that sequence is used rather than the corresponding Unicode (e.g., \u000a
) escape.
1.2.3. Non-ASCII Characters
For the remaining non-ASCII characters, either the actual Unicode character (e.g., ∞
) or the equivalent Unicode escape (e.g., \u221e
) is used. The choice depends only on which makes the code easier to read and understand. Unicode escapes are discouraged for printable characters at any location and are strongly discouraged outside of string literals and comments.
Example | Discussion |
---|---|
val unitAbbrev = "μs" | Best: perfectly clear even without a comment. |
val unitAbbrev = "\u03bcs" // μs | Poor: there’s no reason to use an escape with a printable character. |
val unitAbbrev = “\u03bcs”` | Poor: the reader has no idea what this is. |
return "\ufeff" + content | Good: use escapes for non-printable characters, and comment if necessary. |
1.3. Structure
A .kt
file comprises the following, in order:
- Copyright and/or license header (optional)
- File-level annotations
- Package statement
- Import statements
- Top-level declarations
Exactly one blank line separates each of these sections.
1.3.1. Copyright / License
If a copyright or license header belongs in the file it should be placed at the immediate top in a multi-line comment.
/*
* Copyright 2017 Google, Inc.
*
* ...
*/
Do not use a KDoc-style or single-line-style comment.
/**
* Copyright 2017 Google, Inc.
*
* ...
*/
// Copyright 2017 Google, Inc.
//
// ...
1.3.2. File-level Annotations
Annotations with the “file” use-site target are placed between any header comment and the package declaration.
1.3.3. Package Statement
The package statement is not subject to any column limit and is never line-wrapped.
1.3.4. Import Statements
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.
1.3.5. Top-level Declarations
A .kt
file can declare one or more types, functions, properties, or type aliases at the top-level.
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.
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.
What is important is that each class 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 class, as that would yield “chronological by date added” ordering, which is not a logical ordering.
1.3.6. Class Member Ordering
The order of members within a class follow the same rules as the top-level declarations.
2. Formatting
2.1. Braces
Braces are not required for when
branches and if
statement bodies which have no else if/else
branches and which fit on a single line.
if (string.isEmpty()) return
when (value) {
0 -> return
// …
}
Braces are otherwise required for any if
, for
, when
branch, do
, and while
statements, even when the body is empty or contains only a single statement.
if (string.isEmpty())
return // WRONG!
if (string.isEmpty()) {
return // Okay
}
2.1.1. Non-empty Blocks
The braces follow the Kernighan and Ritchie style (“Egyptian brackets”) for nonempty blocks and block-like constructs:
- Firstly, No line break before the opening brace.
- Secondly, Line break after the opening brace.
- Thirdly, Line break before the closing brace.
- And finally, Line break after the closing brace, only if that brace terminates a statement or terminates the body of a function, constructor, or named class. For example, there is no line break after the brace if it is followed by
else
or a comma.
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()
}
}
}
2.1.2. Empty Blocks
An empty block or block-like construct must be in K&R style.
try {
doSomething()
} catch (e: Exception) {} // WRONG!
try {
doSomething()
} catch (e: Exception) {
} // Okay
2.1.3. Expressions
An if/else
conditional that is used as an expression may omit braces only if the entire expression fits on one line.
val value = if (string.isEmpty()) 0 else 1 // Okay
val value = if (string.isEmpty()) // WRONG!
0
else
1
val value = if (string.isEmpty()) { // Okay
0
} else {
1
}
2.1.4. Indentation
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.
2.1.5. One Statement Per Line
Each statement is followed by a line break. Semicolons are not used.
2.1.6. Line Wrapping
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:
- Lines where obeying the column limit is not possible (for example, a long URL in KDoc)
package
andimport
statements- Command lines in a comment that may be cut-and-pasted into a shell
2.1.7. Where to break
The prime directive of line-wrapping is: prefer to break at a higher syntactic level. Also:
- When a line is broken at an operator or infix function name, the break comes after the operator or infix function name.
- When a line is broken at the following “operator-like” symbols, the break comes before the symbol:
- The dot separator (
.
,?.
). - The two colons of a member reference (
::
).
- The dot separator (
- A method or constructor name stays attached to the open parenthesis (
(
) that follows it. - A comma (
,
) stays attached to the token that precedes it. - A lambda arrow (
->
) stays attached to the argument list that precedes it.
2.1.8. Functions
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.
fun <T> Iterable<T>.joinToString(
separator: CharSequence = ", ",
prefix: CharSequence = "",
postfix: CharSequence = ""
): String {
// …
}
2.1.9. Expression Functions
When a function contains only a single expression it can be represented as an expression function.
override fun toString(): String {
return "Hey"
}
override fun toString(): String = "Hey"
The only time an expression function should wrap to multiple lines is when it opens a block.
fun main() = runBlocking {
// …
}
Otherwise, if an expression function grows to require wrapping, use a normal function body, a return
declaration, and normal expression wrapping rules instead.
2.1.10. Properties
When a property initializer does not fit on a single line, break after the equals sign (=
) and use an indent.
private val defaultCharset: Charset? =
EncodingRegistry.getInstance().getDefaultCharsetForPropertiesFiles(file)
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.
var directory: File? = null
set(value) {
// …
}
Read-only properties can use a shorter syntax which fits on a single line.
val defaultExtension: String get() = "kt"
2.2. Whitespace
2.2.1. Vertical
A single blank line appears:
- Between consecutive members of a class: properties, constructors, functions, nested classes, etc.
- Exception: A blank line between two consecutive properties (having no other code between them) is optional. Such blank lines are used as needed to create logical groupings of properties and associate properties with their backing property, if present.
- Exception: Blank lines between enum constants are covered below.
- Between statements, as needed to organize the code into logical subsections.
- Optionally before the first statement in a function, before the first member of a class, or after the last member of a class (neither encouraged nor discouraged).
Multiple consecutive blank lines are permitted, but not encouraged or ever required.
2.2.2. Horizontal
Beyond where required by the language or other style rules, and apart from literals, comments, and KDoc, a single ASCII space also appears in the following places only:
- Separating any reserved word, such as
if
,for
, orcatch
from an open parenthesis ((
) that follows it on that line.
// WRONG!
for(i in 0..1) {
}
// Okay
for (i in 0..1) {
}
- Separating any reserved word, such as
else
orcatch
, from a closing curly brace (}
) that precedes it on that line.
// WRONG!
}else {
}
// Okay
} else {
}
- Before any open curly brace (
{
).
// WRONG!
if (list.isEmpty()){
}
// Okay
if (list.isEmpty()) {
}
- Before a colon (
:
) only if used in a class declaration for specifying a base class or interfaces, or when used in awhere
clause for generic constraints.
// WRONG!
class Foo: Runnable
// Okay
class Foo : Runnable
// WRONG
fun <T: Comparable> max(a: T, b: T)
// Okay
fun <T : Comparable> max(a: T, b: T)
// WRONG
fun <T> max(a: T, b: T) where T: Comparable<T>
// Okay
fun <T> max(a: T, b: T) where T : Comparable<T>
- After a comma (
,
) or colon (:
).
// WRONG!
val oneAndTwo = listOf(1,2)
// Okay
val oneAndTwo = listOf(1, 2)
// WRONG!
class Foo :Runnable
// Okay
class Foo : Runnable
- On both sides of the double slash (
//
) that begins an end-of-line comment. Here, multiple spaces are allowed, but not required.
// WRONG!
var debugging = false//disabled by default
// Okay
var debugging = false // disabled by default
- On both sides of any binary operator.
// WRONG!
val two = 1+1
// Okay
val two = 1 + 1
This also applies to the following “operator-like” symbols:
- the arrow in a lambda expression (
->
).
// WRONG!
ints.map { value->value.toString() }
// Okay
ints.map { value -> value.toString() }
But not:
- the two colons (
::
) of a member reference.
// WRONG!
val toString = Any :: toString
// Okay
val toString = Any::toString
- the dot separator (
.
).
// WRONG
it . toString()
// Okay
it.toString()
- the range operator (
..
).
// WRONG
for (i in 1 .. 4) print(i)
// Okay
for (i in 1..4) print(i)
This rule is never interpreted as requiring or forbidding additional space at the start or end of a line; it addresses only interior space.
2.3. Specific Constructs
2.3.1. Enum Classes
An enum with no functions and no documentation on its constants may optionally be formatted as a single line.
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.
enum class Answer {
YES,
NO,
MAYBE {
override fun toString() = """¯\_(ツ)_/¯"""
}
}
Since enum classes are classes, all other rules for formatting classes apply.
2.3.2. Annotations
Member or type annotations are placed on separate lines immediately prior to the annotated construct.
@Retention(SOURCE)
@Target(FUNCTION, PROPERTY_SETTER, FIELD)
annotation class Global
Annotations without arguments can be placed on a single line.
@JvmField @Volatile
var disposable: Disposable? = null
When only a single annotation without arguments is present, it may be placed on the same line as the declaration.
@Volatile var disposable: Disposable? = null
@Test fun selectAll() {
// …
}
@[...]
syntax may only be used with an explicit use-site target, and only for combining 2 or more annotations without arguments on a single line.
@field:[JvmStatic Volatile]
var disposable: Disposable? = null
2.3.3. Implicit Return/Property Types
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.
override fun toString(): String = "Hey"
// becomes
override fun toString() = "Hey"
private val ICON: Icon = IconLoader.getIcon("/icons/kotlin.png")
// becomes
private val ICON = IconLoader.getIcon("/icons/kotlin.png")
When writing a library, retain the explicit type declaration when it is part of the public API.
2.4. Naming
Identifiers use only ASCII letters and digits, and, in a small number of cases noted below, underscores. Thus each valid identifier name is matched by the regular expression \w+
.
Special prefixes or suffixes, like those seen in the examples name_
, mName
, s_name
, and kName
, are not used except in the case of backing properties.
2.4.1. Package Names
Package names are all lowercase, with consecutive words simply concatenated together (no underscores).
// Okay
package com.example.deepspace
// WRONG!
package com.example.deepSpace
// WRONG!
package com.example.deep_space
2.4.2. Type Names
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
).
Test classes are named starting with the name of the class they are testing, and ending with Test
. For example, HashTest
or HashIntegrationTest
.
2.4.3. Function Names
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.
@Test fun pop_emptyStack() {
// …
}
Functions annotated with @Composable
that return Unit
are PascalCased and named as nouns, as if they were types.
@Composable
fun NameTag(name: String) {
// …
}
2.4.4. Constant Names
Constant names use UPPER_SNAKE_CASE: all uppercase letters, with words separated by underscores. But what is a constant, exactly?
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.
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 = arrayOf()
These 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.
2.4.5. Non-constant Names
Non-constant names are written in camelCase. These apply to instance properties, local properties, and parameter names.
val variable = "var"
val nonConstScalar = "non-const"
val mutableCollection: MutableSet = HashSet()
val mutableElements = listOf(mutableInstance)
val mutableValues = mapOf("Alice" to mutableInstance, "Bob" to mutableInstance2)
val logger = Logger.getLogger(MyClass::class.java.name)
val nonEmptyArray = arrayOf("these", "can", "change")
These names are typically nouns or noun phrases.
2.4.6. Backing Properties
When a backing property is needed, its name should exactly match that of the real property except prefixed with an underscore.
private var _table: Map? = null
val table: Map
get() {
if (_table == null) {
_table = HashMap()
}
return _table ?: throw AssertionError()
}
2.4.7. Type Variable Names
Each type variable is named in one of two styles:
- A single capital letter, optionally followed by a single numeral (such as
E
,T
,X
,T2
). - A name in the form used for classes, followed by the capital letter
T
(such asRequestT
,FooBarT
).
2.4.8. Camel Case
Sometimes there is more than one reasonable way to convert an English phrase into camel case, such as when acronyms or unusual constructs like “IPv6” or “iOS” are present. To improve predictability, use the following scheme.
Beginning with the prose form of the name:
- Convert the phrase to plain ASCII and remove any apostrophes. For example, “Müller’s algorithm” might become “Muellers algorithm”.
- Divide this result into words, splitting on spaces and any remaining punctuation (typically hyphens). Recommended: if any word already has a conventional camel-case appearance in common usage, split this into its constituent parts (e.g., “AdWords” becomes “ad words”). Note that a word such as “iOS” is not really in camel case per se; it defies any convention, so this recommendation does not apply.
- Now lowercase everything (including acronyms), then do one of the following:
- Uppercase the first character of each word to yield pascal case.
- Uppercase the first character of each word except the first to yield camel case.
- Finally, join all the words into a single identifier.
We note that the casing of the original words is almost entirely disregarded.
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 * |
(* Acceptable, but not recommended.)
2.5. Documentation
2.5.1. Formatting
The basic formatting of KDoc blocks is seen in this example:
/**
* Multiple lines of KDoc text are written here,
* wrapped normally…
*/
fun method(arg: String) {
// …
}
…or in this single-line example:
/** An especially short bit of KDoc. */
The basic form is always acceptable. The single-line form may be substituted when the entirety of the KDoc block (including comment markers) can fit on a single line. Note that this only applies when there are no block tags such as @return
.
2.5.2. Paragraphs
One blank line—that is, a line containing only the aligned leading asterisk (*
)—appears between paragraphs, and before the group of block tags if present.
2.5.3. Block Tags
Any of the standard “block tags” that are used appear in the order @constructor
, @receiver
, @param
, @property
, @return
, @throws
, @see
, and these never appear with an empty description. When a block tag doesn’t fit on a single line, continuation lines are indented 4 spaces from the position of the @
.
2.5.4. Summary Fragment
Each KDoc block begins with a brief summary fragment. This fragment is very important: it is the only part of the text that appears in certain contexts such as class and method indexes.
This is a fragment–a noun phrase or verb phrase, not a complete sentence. It does not begin with “A `Foo` is a...
“, or “This method returns...
“, nor does it have to form a complete imperative sentence like “Save the record.
“. However, the fragment is capitalized and punctuated as if it were a complete sentence.
2.5.5. Usage
At the minimum, KDoc is present for every public
type, and every public
or protected
member of such a type, with a few exceptions noted below.
2.5.5.1. Exception: Self-explanatory Functions
KDoc is optional for “simple, obvious” functions like getFoo
and properties like foo
, in cases where there really and truly is nothing else worthwhile to say but “Returns the foo”.
It is not appropriate to cite this exception to justify omitting relevant information that a typical reader might need to know. For example, for a function named getCanonicalName
or property named canonicalName
, don’t omit its documentation (with the rationale that it would say only /** Returns the canonical name. */
) if a typical reader may have no idea what the term “canonical name” means!
2.5.5.2. Exception: Overrides
KDoc is not always present on a method that overrides a supertype method.
That’s all about in this article.
Conclusion
In this article, We understood about Kotlin Style Guide for Android application development. This article served as the complete definition of Google’s Android coding standards for source code in the Kotlin Programming Language. We discussed about Source code and formatting style guideline standard for Kotlin which is used in android application development.
Thanks for reading ! I hope you enjoyed and learned about Kotlin Style Guide concepts in Android. Reading is one thing, but the only way to master it is to do it yourself.
Please follow and subscribe to the blog and support us in any way possible. Also like and share the article with others for spread valuable knowledge.
You can find Other articles of CoolMonkTechie as below link :
You can also follow official website and tutorials of Android as below links :
If you have any comments, questions, or think I missed something, feel free to leave them below in the comment box.
Thanks again Reading. HAPPY READING !!???
I like the helpful info you provide in your articles.
I will bookmark your blog and check again here frequently.
I am quite certain I will learn many new stuff right here!
Best of luck for the next!
I think this is among the most important info for me. And i am glad reading your article. But want to remark on some general things, The website style is wonderful, the articles is really nice : D. Good job, cheers
Thank you, I really appreciate you taking the time to express that !!
I truly enjoy examining on this website, it has superb posts. “And all the winds go sighing, For sweet things dying.” by Christina Georgina Rossetti.