This is a collection of basic syntax elements with examples. At the end of every section, you'll find a link to a detailed description of the related topic.
You can also learn all the Kotlin essentials with the free Kotlin Basics track on JetBrains Academy.
Package specification should be at the top of the source file.
package my.demo
import kotlin.text.*
// ...
It is not required to match directories and packages: source files can be placed arbitrarily in the file system.
See Packages.
An entry point of a Kotlin application is the main
function.
fun main() {
println("Hello world!")
}
{kotlin-runnable="true" kotlin-min-compiler-version="1.3"}
Another form of main
accepts a variable number of String
arguments.
fun main(args: Array<String>) {
println(args.contentToString())
}
{kotlin-runnable="true" kotlin-min-compiler-version="1.3"}
print
prints its argument to the standard output.
fun main() {
//sampleStart
print("Hello ")
print("world!")
//sampleEnd
}
{kotlin-runnable="true" kotlin-min-compiler-version="1.3"}
println
prints its arguments and adds a line break, so that the next thing you print appears on the next line.
fun main() {
//sampleStart
println("Hello world!")
println(42)
//sampleEnd
}
{kotlin-runnable="true" kotlin-min-compiler-version="1.3"}
A function with two Int
parameters and Int
return type.
//sampleStart
fun sum(a: Int, b: Int): Int {
return a + b
}
//sampleEnd
fun main() {
print("sum of 3 and 5 is ")
println(sum(3, 5))
}
{kotlin-runnable="true" kotlin-min-compiler-version="1.3"}
A function body can be an expression. Its return type is inferred.
//sampleStart
fun sum(a: Int, b: Int) = a + b
//sampleEnd
fun main() {
println("sum of 19 and 23 is ${sum(19, 23)}")
}
{kotlin-runnable="true" kotlin-min-compiler-version="1.3"}
A function that returns no meaningful value.
//sampleStart
fun printSum(a: Int, b: Int): Unit {
println("sum of $a and $b is ${a + b}")
}
//sampleEnd
fun main() {
printSum(-1, 8)
}
{kotlin-runnable="true" kotlin-min-compiler-version="1.3"}
Unit
return type can be omitted.
//sampleStart
fun printSum(a: Int, b: Int) {
println("sum of $a and $b is ${a + b}")
}
//sampleEnd
fun main() {
printSum(-1, 8)
}
{kotlin-runnable="true" kotlin-min-compiler-version="1.3"}
See Functions.
Read-only local variables are defined using the keyword val
. They can be assigned a value only once.
fun main() {
//sampleStart
val a: Int = 1 // immediate assignment
val b = 2 // `Int` type is inferred
val c: Int // Type required when no initializer is provided
c = 3 // deferred assignment
//sampleEnd
println("a = $a, b = $b, c = $c")
}
{kotlin-runnable="true" kotlin-min-compiler-version="1.3"}
Variables that can be reassigned use the var
keyword.
fun main() {
//sampleStart
var x = 5 // `Int` type is inferred
x += 1
//sampleEnd
println("x = $x")
}
{kotlin-runnable="true" kotlin-min-compiler-version="1.3"}
You can declare variables at the top level.
//sampleStart
val PI = 3.14
var x = 0
fun incrementX() {
x += 1
}
//sampleEnd
fun main() {
println("x = $x; PI = $PI")
incrementX()
println("incrementX()")
println("x = $x; PI = $PI")
}
{kotlin-runnable="true" kotlin-min-compiler-version="1.3"}
See also Properties.
To define a class, use the class
keyword.
class Shape
Properties of a class can be listed in its declaration or body.
class Rectangle(var height: Double, var length: Double) {
var perimeter = (height + length) * 2
}
The default constructor with parameters listed in the class declaration is available automatically.
class Rectangle(var height: Double, var length: Double) {
var perimeter = (height + length) * 2
}
fun main() {
//sampleStart
val rectangle = Rectangle(5.0, 2.0)
println("The perimeter is ${rectangle.perimeter}")
//sampleEnd
}
{kotlin-runnable="true" kotlin-min-compiler-version="1.3"}
Inheritance between classes is declared by a colon (:
). Classes are final by default; to make a class inheritable,
mark it as open
.
open class Shape
class Rectangle(var height: Double, var length: Double): Shape() {
var perimeter = (height + length) * 2
}
See classes and objects and instances.
Just like most modern languages, Kotlin supports single-line (or end-of-line) and multi-line (block) comments.
// This is an end-of-line comment
/* This is a block comment
on multiple lines. */
Block comments in Kotlin can be nested.
/* The comment starts here
/* contains a nested comment *⁠/
and ends here. */
See Documenting Kotlin Code for information on the documentation comment syntax.
fun main() {
//sampleStart
var a = 1
// simple name in template:
val s1 = "a is $a"
a = 2
// arbitrary expression in template:
val s2 = "${s1.replace("is", "was")}, but now is $a"
//sampleEnd
println(s2)
}
{kotlin-runnable="true" kotlin-min-compiler-version="1.3"}
See String templates for details.
//sampleStart
fun maxOf(a: Int, b: Int): Int {
if (a > b) {
return a
} else {
return b
}
}
//sampleEnd
fun main() {
println("max of 0 and 42 is ${maxOf(0, 42)}")
}
{kotlin-runnable="true" kotlin-min-compiler-version="1.3"}
In Kotlin, if
can also be used as an expression.
//sampleStart
fun maxOf(a: Int, b: Int) = if (a > b) a else b
//sampleEnd
fun main() {
println("max of 0 and 42 is ${maxOf(0, 42)}")
}
{kotlin-runnable="true" kotlin-min-compiler-version="1.3"}
See if
-expressions.
fun main() {
//sampleStart
val items = listOf("apple", "banana", "kiwifruit")
for (item in items) {
println(item)
}
//sampleEnd
}
{kotlin-runnable="true" kotlin-min-compiler-version="1.3"}
or
fun main() {
//sampleStart
val items = listOf("apple", "banana", "kiwifruit")
for (index in items.indices) {
println("item at $index is ${items[index]}")
}
//sampleEnd
}
{kotlin-runnable="true" kotlin-min-compiler-version="1.3"}
See for loop.
fun main() {
//sampleStart
val items = listOf("apple", "banana", "kiwifruit")
var index = 0
while (index < items.size) {
println("item at $index is ${items[index]}")
index++
}
//sampleEnd
}
{kotlin-runnable="true" kotlin-min-compiler-version="1.3"}
See while loop.
//sampleStart
fun describe(obj: Any): String =
when (obj) {
1 -> "One"
"Hello" -> "Greeting"
is Long -> "Long"
!is String -> "Not a string"
else -> "Unknown"
}
//sampleEnd
fun main() {
println(describe(1))
println(describe("Hello"))
println(describe(1000L))
println(describe(2))
println(describe("other"))
}
{kotlin-runnable="true" kotlin-min-compiler-version="1.3"}
See when expression.
Check if a number is within a range using in
operator.
fun main() {
//sampleStart
val x = 10
val y = 9
if (x in 1..y+1) {
println("fits in range")
}
//sampleEnd
}
{kotlin-runnable="true" kotlin-min-compiler-version="1.3"}
Check if a number is out of range.
fun main() {
//sampleStart
val list = listOf("a", "b", "c")
if (-1 !in 0..list.lastIndex) {
println("-1 is out of range")
}
if (list.size !in list.indices) {
println("list size is out of valid list indices range, too")
}
//sampleEnd
}
{kotlin-runnable="true" kotlin-min-compiler-version="1.3"}
Iterate over a range.
fun main() {
//sampleStart
for (x in 1..5) {
print(x)
}
//sampleEnd
}
{kotlin-runnable="true" kotlin-min-compiler-version="1.3"}
Or over a progression.
fun main() {
//sampleStart
for (x in 1..10 step 2) {
print(x)
}
println()
for (x in 9 downTo 0 step 3) {
print(x)
}
//sampleEnd
}
{kotlin-runnable="true" kotlin-min-compiler-version="1.3"}
Iterate over a collection.
fun main() {
val items = listOf("apple", "banana", "kiwifruit")
//sampleStart
for (item in items) {
println(item)
}
//sampleEnd
}
{kotlin-runnable="true" kotlin-min-compiler-version="1.3"}
Check if a collection contains an object using in
operator.
fun main() {
val items = setOf("apple", "banana", "kiwifruit")
//sampleStart
when {
"orange" in items -> println("juicy")
"apple" in items -> println("apple is fine too")
}
//sampleEnd
}
{kotlin-runnable="true" kotlin-min-compiler-version="1.3"}
Using lambda expressions to filter and map collections:
fun main() {
//sampleStart
val fruits = listOf("banana", "avocado", "apple", "kiwifruit")
fruits
.filter { it.startsWith("a") }
.sortedBy { it }
.map { it.uppercase() }
.forEach { println(it) }
//sampleEnd
}
{kotlin-runnable="true" kotlin-min-compiler-version="1.3"}
See Collections overview.
A reference must be explicitly marked as nullable when null
value is possible. Nullable type names have ?
at the end.
Return null
if str
does not hold an integer:
fun parseInt(str: String): Int? {
// ...
}
Use a function returning nullable value:
fun parseInt(str: String): Int? {
return str.toIntOrNull()
}
//sampleStart
fun printProduct(arg1: String, arg2: String) {
val x = parseInt(arg1)
val y = parseInt(arg2)
// Using `x * y` yields error because they may hold nulls.
if (x != null && y != null) {
// x and y are automatically cast to non-nullable after null check
println(x * y)
}
else {
println("'$arg1' or '$arg2' is not a number")
}
}
//sampleEnd
fun main() {
printProduct("6", "7")
printProduct("a", "7")
printProduct("a", "b")
}
{kotlin-runnable="true" kotlin-min-compiler-version="1.3"}
or
fun parseInt(str: String): Int? {
return str.toIntOrNull()
}
fun printProduct(arg1: String, arg2: String) {
val x = parseInt(arg1)
val y = parseInt(arg2)
//sampleStart
// ...
if (x == null) {
println("Wrong number format in arg1: '$arg1'")
return
}
if (y == null) {
println("Wrong number format in arg2: '$arg2'")
return
}
// x and y are automatically cast to non-nullable after null check
println(x * y)
//sampleEnd
}
fun main() {
printProduct("6", "7")
printProduct("a", "7")
printProduct("99", "b")
}
{kotlin-runnable="true" kotlin-min-compiler-version="1.3"}
See Null-safety.
The is
operator checks if an expression is an instance of a type.
If an immutable local variable or property is checked for a specific type, there's no need to cast it explicitly:
//sampleStart
fun getStringLength(obj: Any): Int? {
if (obj is String) {
// `obj` is automatically cast to `String` in this branch
return obj.length
}
// `obj` is still of type `Any` outside of the type-checked branch
return null
}
//sampleEnd
fun main() {
fun printLength(obj: Any) {
println("Getting the length of '$obj'. Result: ${getStringLength(obj) ?: "Error: The object is not a string"} ")
}
printLength("Incomprehensibilities")
printLength(1000)
printLength(listOf(Any()))
}
{kotlin-runnable="true" kotlin-min-compiler-version="1.3"}
or
//sampleStart
fun getStringLength(obj: Any): Int? {
if (obj !is String) return null
// `obj` is automatically cast to `String` in this branch
return obj.length
}
//sampleEnd
fun main() {
fun printLength(obj: Any) {
println("Getting the length of '$obj'. Result: ${getStringLength(obj) ?: "Error: The object is not a string"} ")
}
printLength("Incomprehensibilities")
printLength(1000)
printLength(listOf(Any()))
}
{kotlin-runnable="true" kotlin-min-compiler-version="1.3"}
or even
//sampleStart
fun getStringLength(obj: Any): Int? {
// `obj` is automatically cast to `String` on the right-hand side of `&&`
if (obj is String && obj.length > 0) {
return obj.length
}
return null
}
//sampleEnd
fun main() {
fun printLength(obj: Any) {
println("Getting the length of '$obj'. Result: ${getStringLength(obj) ?: "Error: The object is not a string"} ")
}
printLength("Incomprehensibilities")
printLength("")
printLength(1000)
}
{kotlin-runnable="true" kotlin-min-compiler-version="1.3"}
See Classes and Type casts.