Movatterモバイル変換


[0]ホーム

URL:


Kotlin Help

Coding conventions

Commonly known and easy-to-follow coding conventions are vital for any programming language. Here we provide guidelines on the code style and code organization for projects that use Kotlin.

Configure style in IDE

Two most popular IDEs for Kotlin -IntelliJ IDEA andAndroid Studio provide powerful support for code styling. You can configure them to automatically format your code in consistence with the given code style.

Apply the style guide

  1. Go toSettings/Preferences | Editor | Code Style | Kotlin.

  2. ClickSet from....

  3. SelectKotlin style guide.

Verify that your code follows the style guide

  1. Go toSettings/Preferences | Editor | Inspections | General.

  2. Switch onIncorrect formatting inspection. Additional inspections that verify other issues described in the style guide (such as naming conventions) are enabled by default.

Source code organization

Directory structure

In pure Kotlin projects, the recommended directory structure follows the package structure with the common root package omitted. For example, if all the code in the project is in theorg.example.kotlin package and its subpackages, files with theorg.example.kotlin package should be placed directly under the source root, and files inorg.example.kotlin.network.socket should be in thenetwork/socket subdirectory of the source root.

On JVM: In projects where Kotlin is used together with Java, Kotlin source files should reside in the same source root as the Java source files, and follow the same directory structure: each file should be stored in the directory corresponding to each package statement.

Source file names

If a Kotlin file contains a single class or interface (potentially with related top-level declarations), its name should be the same as the name of the class, with the.kt extension appended. It applies to all types of classes and interfaces. If a file contains multiple classes, or only top-level declarations, choose a name describing what the file contains, and name the file accordingly. Useupper camel case, where the first letter of each word is capitalized. For example,ProcessDeclarations.kt.

The name of the file should describe what the code in the file does. Therefore, you should avoid using meaningless words such asUtil in file names.

Multiplatform projects

In multiplatform projects, files with top-level declarations in platform-specific source sets should have a suffix associated with the name of the source set. For example:

  • jvmMain/kotlin/Platform.jvm .kt

  • androidMain/kotlin/Platform.android .kt

  • iosMain/kotlin/Platform.ios .kt

As for the common source set, files with top-level declarations should not have a suffix. For example,commonMain/kotlin/Platform.kt.

Technical details

We recommend following this file naming scheme in multiplatform projects due to JVM limitations: it doesn't allow top-level members (functions, properties).

To work around this, the Kotlin JVM compiler creates wrapper classes (so-called "file facades") that contain top-level member declarations. File facades have an internal name derived from the file name.

In turn, JVM doesn't allow several classes with the same fully qualified name (FQN). This might lead to situations when a Kotlin project cannot be compiled to JVM:

root|- commonMain/kotlin/myPackage/Platform.kt // contains 'fun count() { }'|- jvmMain/kotlin/myPackage/Platform.kt // contains 'fun multiply() { }'

Here bothPlatform.kt files are in the same package, so the Kotlin JVM compiler produces two file facades, both of which have FQNmyPackage.PlatformKt. This produces the "Duplicate JVM classes" error.

The simplest way to avoid that is renaming one of the files according to the guideline above. This naming scheme helps avoid clashes while retaining code readability.

There are two scenarios where these recommendations may seem redundant, but we still advise to follow them:

  • Non-JVM platforms don't have issues with duplicating file facades. However, this naming scheme can help you keep file naming consistent.

  • On JVM, if source files don't have top-level declarations, the file facades aren't generated, and you won't face naming clashes.

    However, this naming scheme can help you avoid situations when a simple refactoring or an addition could include a top-level function and result in the same "Duplicate JVM classes" error.

Source file organization

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.

Class layout

The contents of a class should go in the following order:

  1. Property declarations and initializer blocks

  2. Secondary constructors

  3. Method declarations

  4. 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. Choose an order (either higher-level stuff first, or vice versa) and stick to it.

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.

Interface implementation layout

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).

Overload layout

Always put overloads next to each other in a class.

Naming rules

Package and class naming rules in Kotlin are quite simple:

Function names

Names of functions, properties and local variables start with a lowercase letter and use camel case with no underscores:

Exception: factory functions used to create instances of classes can have the same name as the abstract return type:

Names for test methods

In tests (andonly 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.

Property names

Names of constants (properties marked withconst, or top-level or objectval properties with no customget function that hold deeply immutable data) should use all uppercase, underscore-separated names following thescreaming snake case convention:

const val MAX_COUNT = 8val USER_NAME_FIELD = "UserName"

Names of top-level or object properties which hold objects with behavior or mutable data should use camel case names:

val mutableCollection: MutableSet<String> = HashSet()

Names of properties holding references to singleton objects can use the same naming style asobject declarations:

val PersonComparator: Comparator<Person> = /*...*/

For enum constants, it's OK to use either all uppercase, underscore-separated (screaming snake case) names (enum class Color { RED, GREEN }) or upper camel case names, depending on the usage.

Names for backing properties

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}

Choose good names

The name of a class is usually a noun or a noun phrase explaining what the classis:List,PersonReader.

The name of a method is usually a verb or a verb phrase saying what the methoddoes:close,readPersons. The name should also suggest if the method is mutating the object or returning a new one. For instancesort is sorting a collection in place, whilesorted 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, follow these rules:

  • For two-letter acronyms, use uppercase for both letters. For example,IOStream.

  • For acronyms longer than two letters, capitalize only the first letter. For example,XmlFormatter orHttpInputStream.

Formatting

Indentation

Use four spaces for indentation. Do not use tabs.

For curly braces, put the opening brace at the end of the line where the construct begins, and the closing brace on a separate line aligned horizontally with the opening construct.

if (elements != null) { for (element in elements) { // ... }}

In Kotlin, semicolons are optional, and therefore line breaks are significant. The language design assumes Java-style braces, and you may encounter surprising behavior if you try to use a different formatting style.

Horizontal whitespace

As a general rule, avoid horizontal alignment of any kind. Renaming an identifier to a name with a different length should not affect the formatting of either the declaration or any of the usages.

Colon

Put a space before: in the following scenarios:

Don't put a space before: when it separates a declaration and its type.

Always put a space after:.

Class headers

Classes with a few primary constructor parameters can be written in a single line:

Classes with longer headers should be formatted so that each primary constructor parameter is in a separate line with indentation. Also, the closing parenthesis should be on a new line. If you use inheritance, the superclass constructor call, or the list of implemented interfaces should be located on the same line as the parenthesis:

For multiple interfaces, the superclass constructor call should be located first and then each interface should be located in a different line:

For classes with a long supertype list, put a line break after the colon and align all supertype names horizontally:

To clearly separate the class header and body when the class header is long, either put a blank line following the class header (as in the example above), or put the opening curly brace on a separate line:

Use regular indent (four spaces) for constructor parameters. This ensures that properties declared in the primary constructor have the same indentation as properties declared in the body of a class.

Modifiers order

If a declaration has multiple modifiers, always put them in the following order:

Place all annotations before modifiers:

Unless you're working on a library, omit redundant modifiers (for example,public).

Annotations

Place annotations on separate lines before the declaration to which they are attached, and with the same indentation:

Annotations without arguments may be placed on the same line:

A single annotation without arguments may be placed on the same line as the corresponding declaration:

File annotations

File annotations are placed after the file comment (if any), before thepackage statement, and are separated frompackage with a blank line (to emphasize the fact that they target the file and not the package).

Functions

If the function signature doesn't fit on a single line, use the following syntax:

Use regular indent (four spaces) for function parameters. It helps ensure consistency with constructor parameters.

Prefer using an expression body for functions with the body consisting of a single expression.

Expression bodies

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.

Properties

For very simple read-only properties, consider one-line formatting:

For more complex properties, always putget andset keywords on separate lines:

For properties with an initializer, if the initializer is long, add a line break after the= sign and indent the initializer by four spaces:

Control flow statements

If the condition of anif orwhen 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:

This helps align the condition and statement bodies.

Put theelse,catch,finally keywords, as well as thewhile keyword of ado-while loop, on the same line as the preceding curly brace:

In awhen statement, if a branch is more than a single line, consider separating it from adjacent case blocks with a blank line:

Put short branches on the same line as the condition, without braces.

Method calls

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.

Put spaces around the= sign separating the argument name and value.

Wrap chained calls

When wrapping chained calls, put the. character or the?. operator on the next line, with a single indent:

The first call in the chain should usually have a line break before it, but it's OK to omit it if the code makes more sense that way.

Lambdas

In lambda expressions, spaces should be used around the curly braces, as well as around the arrow which separates the parameters from the body. If a call takes a single lambda, pass it outside parentheses whenever possible.

If assigning a label for a lambda, do not put a space between the label and the opening curly brace:

When declaring parameter names in a multiline lambda, put the names on the first line, followed by the arrow and the newline:

If the parameter list is too long to fit on a line, put the arrow on a separate line:

Trailing commas

A trailing comma is a comma symbol after the last item in a series of elements:

Using trailing commas has several benefits:

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.

To enable trailing commas in the IntelliJ IDEA formatter, go toSettings/Preferences | Editor | Code Style | Kotlin, open theOther tab and select theUse trailing comma option.

Documentation comments

For longer documentation comments, place the opening/** on a separate line and begin each subsequent line with an asterisk:

Short comments can be placed on a single line:

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 redundant constructs

In general, if a certain syntactic construction in Kotlin is optional and highlighted by the IDE as redundant, you should omit it in your code. Do not leave unnecessary syntactic elements in code just "for clarity".

Unit return type

If a function returns Unit, the return type should be omitted:

Semicolons

Omit semicolons whenever possible.

String templates

Don't use curly braces when inserting a simple variable into a string template. Use curly braces only for longer expressions:

Usemulti-dollar string interpolation to treat the dollar sign chars$ as string literals:

val KClass<*>.jsonSchema : Stringget() = $$""" { "$schema": "https://json-schema.org/draft/2020-12/schema", "$id": "https://example.com/product.schema.json", "$dynamicAnchor": "meta", "title": "$${simpleName ?: qualifiedName ?: "unknown"}", "type": "object" } """

Idiomatic use of language features

Immutability

Prefer using immutable data to mutable. Always declare local variables and properties asval rather thanvar 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 mutatedfun validateValue(actualValue: String, allowedValues: HashSet<String>) { ... }// Good: immutable collection type used insteadfun validateValue(actualValue: String, allowedValues: Set<String>) { ... }// Bad: arrayListOf() returns ArrayList<T>, which is a mutable collection typeval allowedValues = arrayListOf("a", "b", "c")// Good: listOf() returns List<T>val allowedValues = listOf("a", "b", "c")

Default parameter values

Prefer declaring functions with default parameter values to declaring overloaded functions.

// Badfun foo() = foo("a")fun foo(a: String) { /*...*/ }// Goodfun foo(a: String = "a") { /*...*/ }

Type aliases

If you have a functional type or a type with type parameters which is used multiple times in a codebase, prefer defining a type alias for it:

typealias MouseClickHandler = (Any, MouseEvent) -> Unittypealias PersonIndex = Map<String, Person>

If you use a private or internal type alias for avoiding name collision, prefer theimport ... as ... mentioned inPackages and Imports.

Lambda parameters

In lambdas which are short and not nested, it's recommended to use theit convention instead of declaring the parameter explicitly. In nested lambdas with parameters, always declare parameters explicitly.

Returns in a lambda

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.

Named arguments

Use the named argument syntax when a method takes multiple parameters of the same primitive type, or for parameters ofBoolean type, unless the meaning of all parameters is absolutely clear from context.

drawSquare(x = 10, y = 10, width = 100, height = 100, fill = true)

Conditional statements

Prefer using the expression form oftry,if, andwhen.

return if (x) foo() else bar()
return when(x) { 0 -> "zero" else -> "nonzero"}

The above is preferable to:

if (x) return foo()else return bar()
when(x) { 0 -> return "zero" else -> return "nonzero"}

if versus when

Prefer usingif for binary conditions instead ofwhen. For example, use this syntax withif:

if (x == null) ... else ...

Instead of this one withwhen:

when (x) { null -> // ... else -> // ...}

Prefer usingwhen if there are three or more options.

Guard conditions in when expression

Use parentheses when combining multiple boolean expressions inwhen expressions or statements withguard conditions:

when (status) { is Status.Ok if (status.info.isEmpty() || status.info.id == null) -> "no information"}

Instead of:

when (status) { is Status.Ok if status.info.isEmpty() || status.info.id == null -> "no information"}

Nullable Boolean values in conditions

If you need to use a nullableBoolean in a conditional statement, useif (value == true) orif (value == false) checks.

Loops

Prefer using higher-order functions (filter,map etc.) to loops. Exception:forEach (prefer using a regularfor loop instead, unless the receiver offorEach is nullable orforEach 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.

Loops on ranges

Use the..< operator to loop over an open-ended range:

for (i in 0..n - 1) { /*...*/ } // badfor (i in 0..<n) { /*...*/ } // good

Strings

Prefer string templates to string concatenation.

Prefer multiline strings to embedding\n escape sequences into regular string literals.

To maintain indentation in multiline strings, usetrimIndent when the resulting string does not require any internal indentation, ortrimMargin when internal indentation is required:

fun main() {//sampleStart println(""" Not trimmed text """ ) println(""" Trimmed text """.trimIndent() ) println() val a = """Trimmed to margin text: |if(a > 1) { | return a |}""".trimMargin() println(a)//sampleEnd}

Learn the difference betweenJava and Kotlin multiline strings.

Functions vs properties

In some scenarios, functions with no arguments might be interchangeable with read-only properties. Although the semantics are similar, there are some stylistic conventions on when to prefer one to another.

Prefer a property over a function when the underlying algorithm:

  • Does not throw.

  • Is cheap to calculate (or cached on the first run).

  • Returns the same result over invocations if the object state hasn't changed.

Extension functions

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.

Infix functions

Declare a function asinfix only when it works on two objects which play a similar role. Good examples:and,to,zip. Bad example:add.

Do not declare a method asinfix if it mutates the receiver object.

Factory functions

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 including parameters with default values, prefer to replace the overloaded constructors with factory functions.

Platform types

A public function/method returning an expression of a platform type must declare its Kotlin type explicitly:

fun apiCall(): String = MyJavaApi.getProperty("name")

Any property (package-level or class-level) initialized with an expression of a platform type must declare its Kotlin type explicitly:

class Person { val name: String = MyJavaApi.getProperty("name")}

A local value initialized with an expression of a platform type may or may not have a type declaration:

fun main() { val name = MyJavaApi.getProperty("name") println(name)}

Scope functions apply/with/run/also/let

Kotlin provides a set of functions to execute a block of code in the context of a given object:let,run,with,apply, andalso. For the guidance on choosing the right scope function for your case, refer toScope Functions.

Coding conventions for libraries

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).

  • ProvideKDoc comments for all public members, except for overrides that do not require any new documentation (to support generating documentation for the library).

Learn more about best practices and ideas to consider when writing an API for your library in theLibrary authors' guidelines.

Last modified: 04 July 2025
IdiomsBasic types

[8]ページ先頭

©2009-2025 Movatter.jp