# Kotlin Documentation This file contains the complete content of all Kotlin documentation pages, optimized for large language models (LLMs). --- # Kotlin Docs Kotlin docs Latest stable version: 2.4.20 # Get started with Kotlin Latest Kotlin release: [2.4.20](whatsnew2420.html) Kotlin is a modern language that's concise, multiplatform, and interoperable with Java and other languages. New to Kotlin? Take our tour to learn the fundamentals directly in your browser. [Start the Kotlin tour](kotlin-tour-welcome.html) ## Install Kotlin Kotlin is included in each [IntelliJ IDEA](https://www.jetbrains.com/idea/download/) and [Android Studio](https://developer.android.com/studio) release. Download and install one of these IDEs to start using Kotlin. ## Choose your Kotlin use case Console: Here you'll learn how to develop a console application and create unit tests with Kotlin. 1. [Create a basic JVM application with the IntelliJ IDEA project wizard](jvm-get-started.html). 2. [Write your first unit test](jvm-test-using-junit.html). Backend: Here you'll learn how to develop a backend application with Kotlin server-side. * Introduce Kotlin to your Java project: * [Configure a Java project to work with Kotlin](mixing-java-kotlin-intellij.html) * [Add Kotlin tests to your Java Maven project](jvm-test-using-junit.html) * Create a backend app from scratch with Kotlin: * [Create a RESTful web service with Spring Boot](jvm-get-started-spring-boot.html) * [Create HTTP APIs with Ktor](https://ktor.io/docs/creating-http-apis.html) Cross-platform: Here you'll learn how to develop a cross-platform application using [Kotlin Multiplatform](https://kotlinlang.org/docs/multiplatform/get-started.html). 1. [Set up your environment for cross-platform development](https://kotlinlang.org/docs/multiplatform/quickstart.html). 2. Create your first application for iOS and Android: * Create a cross-platform application from scratch and: * [Share business logic while keeping the UI native](https://kotlinlang.org/docs/multiplatform/multiplatform-create-first-app.html) * [Share business logic and UI](https://kotlinlang.org/docs/multiplatform/compose-multiplatform-create-first-app.html) * [Make your existing Android application work on iOS](https://kotlinlang.org/docs/multiplatform/multiplatform-integrate-in-existing-app.html) * [Create a cross-platform application using Ktor and SQLdelight](https://kotlinlang.org/docs/multiplatform/multiplatform-ktor-sqldelight.html) 3. Explore [sample projects](https://kotlinlang.org/docs/multiplatform/multiplatform-samples.html). Android: To start using Kotlin for Android development, read [Google's recommendation for getting started with Kotlin on Android](https://developer.android.com/kotlin/get-started). Data analysis: From building data pipelines to productionizing machine learning models, Kotlin is a great choice for working with data and getting the most out of it. 1. Explore and experiment with your data: * [DataFrame](https://kotlin.github.io/dataframe/overview.html) – a library for data analysis and manipulation. * [Kandy](https://kotlin.github.io/kandy/welcome.html) – a plotting tool for data visualization. 2. Follow Kotlin for Data Analysis on Twitter: [KotlinForData](http://twitter.com/KotlinForData). ## Get support If you encounter any difficulties or problems, ask for help in ![Slack](images/slack.svg) Slack: [get an invite](https://surveys.jetbrains.com/s3/kotlin-slack-sign-up) or report an issue in our [issue tracker](https://youtrack.jetbrains.com/issues/KT). If anything is missing or seems confusing on this page, please [share your feedback](https://surveys.hotjar.com/d82e82b0-00d9-44a7-b793-0611bf6189df). # Welcome to our tour of Kotlin! Note: These tours can be completed entirely within your browser. There is no installation required. Quickly learn the essentials of the Kotlin programming language through our tours. ### Beginner Grasp the fundamentals. [Start](kotlin-tour-hello-world.html) ### Intermediate Take your understanding of Kotlin to the next level. [Start](kotlin-tour-intermediate-extension-functions.html) # Hello world Here is a simple program that prints "Hello, world!": ```KOTLIN fun main() { println("Hello, world!") // Hello, world! } ``` In Kotlin: * `fun` is used to declare a function * The `main()` function is where your program starts from * The body of a function is written within curly braces `{}` * [println()](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.io/println.html) and [print()](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.io/print.html) functions print their arguments to standard output A function is a set of instructions that performs a specific task. Once you create a function, you can use it whenever you need to perform that task, without having to write the instructions all over again. Functions are discussed in more detail in a couple of chapters. Until then, all examples use the `main()` function. ## Variables All programs need to be able to store data, and variables help you to do just that. In Kotlin, you can declare: * Read-only variables with `val` * Mutable variables with `var` Note: You can't change a read-only variable once you have given it a value. To assign a value, use the assignment operator `=`. For example: ```KOTLIN fun main() { //sampleStart val popcorn = 5 // There are 5 boxes of popcorn val hotdog = 7 // There are 7 hotdogs var customers = 10 // There are 10 customers in the queue // Some customers leave the queue customers = 8 println(customers) // 8 //sampleEnd } ``` Tip: Variables can be declared outside the `main()` function at the beginning of your program. Variables declared in this way are said to be declared at top level. As `customers` is a mutable variable, its value can be reassigned after declaration. Note: We recommend declaring all variables as read-only (`val`) by default. Only use mutable variables (`var`) if you really need to. That way, you're less likely to accidentally change something that wasn't meant to change. ## String templates It's useful to know how to print the contents of variables to standard output. You can do this with string templates. You can use template expressions to access data stored in variables and other objects, and convert them into strings. A string value is a sequence of characters in double quotes `"`. Template expressions always start with a dollar sign `$`. To evaluate a piece of code in a template expression, place the code within curly braces `{}` after the dollar sign `$`. For example: ```KOTLIN fun main() { //sampleStart val customers = 10 println("There are $customers customers") // There are 10 customers println("There are ${customers + 1} customers") // There are 11 customers //sampleEnd } ``` For more information, see [String templates](strings.html#string-templates). You will notice that there aren't any types declared for variables. Kotlin has inferred the type itself: `Int`. This tour explains the different Kotlin basic types and how to declare them in the [next chapter](kotlin-tour-basic-types.html). ## Practice ### Exercise Complete the code to make the program print `"Mary is 20 years old"` to standard output: ```KOTLIN fun main() { val name = "Mary" val age = 20 // Write your code here } ``` ```KOTLIN fun main() { val name = "Mary" val age = 20 println("$name is $age years old") } ``` ## See also * [Next step](kotlin-tour-basic-types.html) # Basic types Every variable and data structure in Kotlin has a type. Types are important because they tell the compiler what you are allowed to do with that variable or data structure. In other words, what functions and properties it has. In the last chapter, Kotlin was able to tell in the previous example that `customers` has type [Int](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-int/). Kotlin's ability to infer the type is called type inference. `customers` is assigned an integer value. From this, Kotlin infers that `customers` has a numerical type `Int`. As a result, the compiler knows that you can perform arithmetic operations with `customers`: ```KOTLIN fun main() { //sampleStart var customers = 10 // Some customers leave the queue customers = 8 customers = customers + 3 // Example of addition: 11 customers += 7 // Example of addition: 18 customers -= 3 // Example of subtraction: 15 customers *= 2 // Example of multiplication: 30 customers /= 3 // Example of division: 10 println(customers) // 10 //sampleEnd } ``` Tip: `+=`, `-=`, `*=`, `/=`, and `%=` are augmented assignment operators. For more information, see [Augmented assignments](operator-overloading.html#augmented-assignments). In total, Kotlin has the following basic types: | Category |Basic types |Example code | --------------------------------------- | [Integers](numbers.html#integer-types) |`Byte`, `Short`, `Int`, `Long` |`val year: Int = 2020` `val amount: Long = 350_000_000` | | [Unsigned integers](unsigned-integer-types.html) |`UByte`, `UShort`, `UInt`, `ULong` |`val score: UInt = 100u` | | [Floating-point numbers](numbers.html#floating-point-types) |`Float`, `Double` |`val currentTemp: Float = 24.5f` `val price: Double = 19.99` | | [Booleans](booleans.html) |`Boolean` |`val isEnabled: Boolean = true` | | [Characters](characters.html) |`Char` |`val separator: Char = ','` | | [Strings](strings.html) |`String` |`val message: String = "Hello, world!"` | For more information on basic types and their properties, see [Types overview](types-overview.html). With this knowledge, you can declare variables and initialize them later. Kotlin can manage this as long as variables are initialized before the first read. To declare a variable without initializing it, specify its type with `:`. For example: ```KOTLIN fun main() { //sampleStart // Variable declared without initialization val d: Int // Variable initialized d = 3 // Variable explicitly typed and initialized val e: String = "hello" // Variables can be read because they have been initialized println(d) // 3 println(e) // hello //sampleEnd } ``` If you don't initialize a variable before it is read, you see an error: ```KOTLIN fun main() { //sampleStart // Variable declared without initialization val d: Int // Triggers an error println(d) // Variable 'd' must be initialized //sampleEnd } ``` Now that you know how to declare basic types, it's time to learn about [collections](kotlin-tour-collections.html). ## Practice ### Exercise Explicitly declare the correct type for each variable: ```KOTLIN fun main() { val a: Int = 1000 val b = "log message" val c = 3.14 val d = 100_000_000_000_000 val e = false val f = '\n' } ``` ```KOTLIN fun main() { val a: Int = 1000 val b: String = "log message" val c: Double = 3.14 val d: Long = 100_000_000_000_000 val e: Boolean = false val f: Char = '\n' } ``` ## See also * [Previous step](kotlin-tour-hello-world.html) * [Next step](kotlin-tour-collections.html) # Collections When programming, it is useful to be able to group data into structures for later processing. Kotlin provides collections for exactly this purpose. Kotlin has the following collections for grouping items: | Collection type |Description | -------------------------------- | Lists |Ordered collections of items | | Sets |Unique unordered collections of items | | Maps |Sets of key-value pairs where keys are unique and map to only one value | Each collection type can be mutable or read only. ## List Lists store items in the order that they are added, and allow for duplicate items. To create a read-only list ([List](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.collections/-list/)), use the [listOf()](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.collections/list-of.html) function. To create a mutable list ([MutableList](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.collections/-mutable-list.html)), use the [mutableListOf()](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.collections/mutable-list-of.html) function. When creating lists, Kotlin can infer the type of items stored. To declare the type explicitly, add the type within angled brackets `<>` after the list declaration: ```KOTLIN fun main() { //sampleStart // Read only list val readOnlyShapes = listOf("triangle", "square", "circle") println(readOnlyShapes) // [triangle, square, circle] // Mutable list with explicit type declaration val shapes: MutableList = mutableListOf("triangle", "square", "circle") println(shapes) // [triangle, square, circle] //sampleEnd } ``` Tip: To prevent unwanted modifications, you can create a read-only view of a mutable list by assigning it to a `List`: ```KOTLIN val shapes: MutableList = mutableListOf("triangle", "square", "circle") val shapesLocked: List = shapes ``` This is also called casting. Lists are ordered so to access an item in a list, use the [indexed access operator](operator-overloading.html#indexed-access-operator) `[]`: ```KOTLIN fun main() { //sampleStart val readOnlyShapes = listOf("triangle", "square", "circle") println("The first item in the list is: ${readOnlyShapes[0]}") // The first item in the list is: triangle //sampleEnd } ``` To get the first or last item in a list, use [.first()](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.collections/first.html) and [.last()](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.collections/last.html) functions respectively: ```KOTLIN fun main() { //sampleStart val readOnlyShapes = listOf("triangle", "square", "circle") println("The first item in the list is: ${readOnlyShapes.first()}") // The first item in the list is: triangle //sampleEnd } ``` Note: [.first()](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.collections/first.html) and [.last()](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.collections/last.html) functions are examples of extension functions. To call an extension function on an object, write the function name after the object appended with a period `.` Extension functions are covered in detail [in the intermediate tour](kotlin-tour-intermediate-extension-functions.html#extension-functions). For now, you only need to know how to call them. To get the number of items in a list, use the [.count()](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.collections/count.html) function: ```KOTLIN fun main() { //sampleStart val readOnlyShapes = listOf("triangle", "square", "circle") println("This list has ${readOnlyShapes.count()} items") // This list has 3 items //sampleEnd } ``` To check that an item is in a list, use the [in operator](operator-overloading.html#in-operator): ```KOTLIN fun main() { //sampleStart val readOnlyShapes = listOf("triangle", "square", "circle") println("circle" in readOnlyShapes) // true //sampleEnd } ``` To add or remove items from a mutable list, use [.add()](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.collections/-mutable-list/add.html) and [.remove()](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.collections/remove.html) functions respectively: ```KOTLIN fun main() { //sampleStart val shapes: MutableList = mutableListOf("triangle", "square", "circle") // Add "pentagon" to the list shapes.add("pentagon") println(shapes) // [triangle, square, circle, pentagon] // Remove the first "pentagon" from the list shapes.remove("pentagon") println(shapes) // [triangle, square, circle] //sampleEnd } ``` ## Set Whereas lists are ordered and allow duplicate items, sets are unordered and only store unique items. To create a read-only set ([Set](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.collections/-set/)), use the [setOf()](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.collections/set-of.html) function. To create a mutable set ([MutableSet](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.collections/-mutable-set/)), use the [mutableSetOf()](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.collections/mutable-set-of.html) function. When creating sets, Kotlin can infer the type of items stored. To declare the type explicitly, add the type within angled brackets `<>` after the set declaration: ```KOTLIN fun main() { //sampleStart // Read-only set val readOnlyFruit = setOf("apple", "banana", "cherry", "cherry") // Mutable set with explicit type declaration val fruit: MutableSet = mutableSetOf("apple", "banana", "cherry", "cherry") println(readOnlyFruit) // [apple, banana, cherry] //sampleEnd } ``` You can see in the previous example that because sets only contain unique elements, the duplicate `"cherry"` item is dropped. Tip: To prevent unwanted modifications, you can create a read-only view of a mutable set by assigning it to a `Set`: ```KOTLIN val fruit: MutableSet = mutableSetOf("apple", "banana", "cherry", "cherry") val fruitLocked: Set = fruit ``` Note: As sets are unordered, you can't access an item at a particular index. To get the number of items in a set, use the [.count()](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.collections/count.html) function: ```KOTLIN fun main() { //sampleStart val readOnlyFruit = setOf("apple", "banana", "cherry", "cherry") println("This set has ${readOnlyFruit.count()} items") // This set has 3 items //sampleEnd } ``` To check that an item is in a set, use the [in operator](operator-overloading.html#in-operator): ```KOTLIN fun main() { //sampleStart val readOnlyFruit = setOf("apple", "banana", "cherry", "cherry") println("banana" in readOnlyFruit) // true //sampleEnd } ``` To add or remove items from a mutable set, use [.add()](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.collections/-mutable-set/add.html) and [.remove()](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.collections/remove.html) functions respectively: ```KOTLIN fun main() { //sampleStart val fruit: MutableSet = mutableSetOf("apple", "banana", "cherry", "cherry") fruit.add("dragonfruit") // Add "dragonfruit" to the set println(fruit) // [apple, banana, cherry, dragonfruit] fruit.remove("dragonfruit") // Remove "dragonfruit" from the set println(fruit) // [apple, banana, cherry] //sampleEnd } ``` ## Map Maps store items as key-value pairs. You access the value by referencing the key. You can imagine a map like a food menu. You can find the price (value), by finding the food (key) you want to eat. Maps are useful if you want to look up a value without using a numbered index, like in a list. Note: * Every key in a map must be unique so that Kotlin can understand which value you want to get. * You can have duplicate values in a map. To create a read-only map ([Map](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.collections/-map/)), use the [mapOf()](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.collections/map-of.html) function. To create a mutable map ([MutableMap](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.collections/-mutable-map/)), use the [mutableMapOf()](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.collections/mutable-map-of.html) function. When creating maps, Kotlin can infer the type of items stored. To declare the type explicitly, add the types of the keys and values within angled brackets `<>` after the map declaration. For example: `MutableMap`. The keys have type `String` and the values have type `Int`. The easiest way to create maps is to use [to](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/to.html) between each key and its related value: ```KOTLIN fun main() { //sampleStart // Read-only map val readOnlyJuiceMenu = mapOf("apple" to 100, "kiwi" to 190, "orange" to 100) println(readOnlyJuiceMenu) // {apple=100, kiwi=190, orange=100} // Mutable map with explicit type declaration val juiceMenu: MutableMap = mutableMapOf("apple" to 100, "kiwi" to 190, "orange" to 100) println(juiceMenu) // {apple=100, kiwi=190, orange=100} //sampleEnd } ``` Tip: To prevent unwanted modifications, you can create a read-only view of a mutable map by assigning it to a `Map`: ```KOTLIN val juiceMenu: MutableMap = mutableMapOf("apple" to 100, "kiwi" to 190, "orange" to 100) val juiceMenuLocked: Map = juiceMenu ``` To access a value in a map, use the [indexed access operator](operator-overloading.html#indexed-access-operator) `[]` with its key: ```KOTLIN fun main() { //sampleStart // Read-only map val readOnlyJuiceMenu = mapOf("apple" to 100, "kiwi" to 190, "orange" to 100) println("The value of apple juice is: ${readOnlyJuiceMenu["apple"]}") // The value of apple juice is: 100 //sampleEnd } ``` Note: If you try to access a key-value pair with a key that doesn't exist in a map, you see a `null` value: ```KOTLIN fun main() { //sampleStart // Read-only map val readOnlyJuiceMenu = mapOf("apple" to 100, "kiwi" to 190, "orange" to 100) println("The value of pineapple juice is: ${readOnlyJuiceMenu["pineapple"]}") // The value of pineapple juice is: null //sampleEnd } ``` This tour explains null values later in the [Null safety](kotlin-tour-null-safety.html) chapter. You can also use the [indexed access operator](operator-overloading.html#indexed-access-operator) `[]` to add items to a mutable map: ```KOTLIN fun main() { //sampleStart val juiceMenu: MutableMap = mutableMapOf("apple" to 100, "kiwi" to 190, "orange" to 100) juiceMenu["coconut"] = 150 // Add key "coconut" with value 150 to the map println(juiceMenu) // {apple=100, kiwi=190, orange=100, coconut=150} //sampleEnd } ``` To remove items from a mutable map, use the [.remove()](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.collections/remove.html) function: ```KOTLIN fun main() { //sampleStart val juiceMenu: MutableMap = mutableMapOf("apple" to 100, "kiwi" to 190, "orange" to 100) juiceMenu.remove("orange") // Remove key "orange" from the map println(juiceMenu) // {apple=100, kiwi=190} //sampleEnd } ``` To get the number of items in a map, use the [.count()](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.collections/count.html) function: ```KOTLIN fun main() { //sampleStart // Read-only map val readOnlyJuiceMenu = mapOf("apple" to 100, "kiwi" to 190, "orange" to 100) println("This map has ${readOnlyJuiceMenu.count()} key-value pairs") // This map has 3 key-value pairs //sampleEnd } ``` To check if a specific key is already included in a map, use the [.containsKey()](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.collections/contains-key.html) function: ```KOTLIN fun main() { //sampleStart val readOnlyJuiceMenu = mapOf("apple" to 100, "kiwi" to 190, "orange" to 100) println(readOnlyJuiceMenu.containsKey("kiwi")) // true //sampleEnd } ``` To obtain a collection of the keys or values of a map, use the [keys](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.collections/-map/keys.html) and [values](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.collections/-map/values.html) properties respectively: ```KOTLIN fun main() { //sampleStart val readOnlyJuiceMenu = mapOf("apple" to 100, "kiwi" to 190, "orange" to 100) println(readOnlyJuiceMenu.keys) // [apple, kiwi, orange] println(readOnlyJuiceMenu.values) // [100, 190, 100] //sampleEnd } ``` Note: [keys](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.collections/-map/keys.html) and [values](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.collections/-map/values.html) are examples of properties of an object. To access the property of an object, write the property name after the object appended with a period `.` Properties are discussed in more detail in the [Classes](kotlin-tour-classes.html) chapter. At this point in the tour, you only need to know how to access them. To check that a key or value is in a map, use the [in operator](operator-overloading.html#in-operator): ```KOTLIN fun main() { //sampleStart val readOnlyJuiceMenu = mapOf("apple" to 100, "kiwi" to 190, "orange" to 100) println("orange" in readOnlyJuiceMenu.keys) // true // Alternatively, you don't need to use the keys property println("orange" in readOnlyJuiceMenu) // true println(200 in readOnlyJuiceMenu.values) // false //sampleEnd } ``` For more information on what you can do with collections, see [Collections](collections-overview.html). Now that you know about basic types and how to manage collections, it's time to explore the [control flow](kotlin-tour-control-flow.html) that you can use in your programs. ## Practice ### Exercise 1 You have a list of “green” numbers and a list of “red” numbers. Complete the code to print how many numbers there are in total. ```KOTLIN fun main() { val greenNumbers = listOf(1, 4, 23) val redNumbers = listOf(17, 2) // Write your code here } ``` ```KOTLIN fun main() { val greenNumbers = listOf(1, 4, 23) val redNumbers = listOf(17, 2) val totalCount = greenNumbers.count() + redNumbers.count() println(totalCount) } ``` ### Exercise 2 You have a set of protocols supported by your server. A user requests to use a particular protocol. Complete the program to check whether the requested protocol is supported or not (`isSupported` must be a Boolean value). ```KOTLIN fun main() { val SUPPORTED = setOf("HTTP", "HTTPS", "FTP") val requested = "smtp" val isSupported = // Write your code here println("Support for $requested: $isSupported") } ``` Hint : Make sure that you check the requested protocol in upper case. You can use the : [.uppercase()](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.text/uppercase.html) : function to help you with this. ```KOTLIN fun main() { val SUPPORTED = setOf("HTTP", "HTTPS", "FTP") val requested = "smtp" val isSupported = requested.uppercase() in SUPPORTED println("Support for $requested: $isSupported") } ``` ### Exercise 3 Define a map that relates integer numbers from 1 to 3 to their corresponding spelling. Use this map to spell the given number. ```KOTLIN fun main() { val number2word = // Write your code here val n = 2 println("$n is spelled as '${}'") } ``` ```KOTLIN fun main() { val number2word = mapOf(1 to "one", 2 to "two", 3 to "three") val n = 2 println("$n is spelled as '${number2word[n]}'") } ``` ## See also * [Previous step](kotlin-tour-basic-types.html) * [Next step](kotlin-tour-control-flow.html) # Control flow Like other programming languages, Kotlin is capable of making decisions based on whether a piece of code is evaluated to be true. Such pieces of code are called conditional expressions. Kotlin is also able to create and iterate through loops. ## Conditional expressions Kotlin provides `if` and `when` for checking conditional expressions. Note: If you have to choose between `if` and `when`, we recommend using `when` because it: * Makes your code easier to read. * Makes it easier to add another branch. * Leads to fewer mistakes in your code. ### If To use `if`, add the conditional expression within parentheses `()` and the action to take if the result is true within curly braces `{}`: ```KOTLIN fun main() { //sampleStart val d: Int val check = true if (check) { d = 1 } else { d = 2 } println(d) // 1 //sampleEnd } ``` There is no ternary operator `condition ? then : else` in Kotlin. Instead, `if` can be used as an expression. If there is only one line of code per action, the curly braces `{}` are optional: ```KOTLIN fun main() { //sampleStart val a = 1 val b = 2 println(if (a > b) a else b) // Returns a value: 2 //sampleEnd } ``` ### When Use `when` when you have a conditional expression with multiple branches. To use `when`: * Place the value you want to evaluate within parentheses `()`. * Place the branches within curly braces `{}`. * Use `->` in each branch to separate each check from the action to take if the check is successful. `when` can be used either as a statement or as an expression. A statement doesn't return anything but performs actions instead. Here is an example of using `when` as a statement: ```KOTLIN fun main() { //sampleStart val obj = "Hello" when (obj) { // Checks whether obj equals to "1" "1" -> println("One") // Checks whether obj equals to "Hello" "Hello" -> println("Greeting") // Default statement else -> println("Unknown") } // Greeting //sampleEnd } ``` Note: Note that all branch conditions are checked sequentially until one of them is satisfied. So only the first suitable branch is executed. An expression returns a value that can be used later in your code. Here is an example of using `when` as an expression. The `when` expression is assigned immediately to a variable which is later used with the `println()` function: ```KOTLIN fun main() { //sampleStart val obj = "Hello" val result = when (obj) { // If obj equals "1", sets result to "one" "1" -> "One" // If obj equals "Hello", sets result to "Greeting" "Hello" -> "Greeting" // Sets result to "Unknown" if no previous condition is satisfied else -> "Unknown" } println(result) // Greeting //sampleEnd } ``` The examples of `when` that you've seen so far both had a subject: `obj`. But `when` can also be used without a subject. This example uses a `when` expression without a subject to check a chain of Boolean expressions: ```KOTLIN fun main() { val trafficLightState = "Red" // This can be "Green", "Yellow", or "Red" val trafficAction = when { trafficLightState == "Green" -> "Go" trafficLightState == "Yellow" -> "Slow down" trafficLightState == "Red" -> "Stop" else -> "Malfunction" } println(trafficAction) // Stop } ``` However, you can have the same code but with `trafficLightState` as the subject: ```KOTLIN fun main() { val trafficLightState = "Red" // This can be "Green", "Yellow", or "Red" val trafficAction = when (trafficLightState) { "Green" -> "Go" "Yellow" -> "Slow down" "Red" -> "Stop" else -> "Malfunction" } println(trafficAction) // Stop } ``` Using `when` with a subject makes your code easier to read and maintain. When you use a subject with a `when` expression, it also helps Kotlin check that all possible cases are covered. Otherwise, if you don't use a subject with a `when` expression, you need to provide an else branch. ## Conditional expressions practice ### Exercise 1 Create a simple game where you win if throwing two dice results in the same number. Use `if` to print `You win :)` if the dice match or `You lose :(` otherwise. Tip: In this exercise, you import a package so that you can use the `Random.nextInt()` function to give you a random `Int`. For more information about importing packages, see [Packages and imports](packages.html). Hint : Use the : [equality operator](operator-overloading.html#equality-and-inequality-operators) : ( : `==` : ) to compare the dice results. ```KOTLIN import kotlin.random.Random fun main() { val firstResult = Random.nextInt(6) val secondResult = Random.nextInt(6) // Write your code here } ``` ```KOTLIN import kotlin.random.Random fun main() { val firstResult = Random.nextInt(6) val secondResult = Random.nextInt(6) if (firstResult == secondResult) println("You win :)") else println("You lose :(") } ``` ### Exercise 2 Using a `when` expression, update the following program so that it prints the corresponding actions when you input the names of game console buttons. | Button |Action | ------------------ | A |Yes | | B |No | | X |Menu | | Y |Nothing | | Other |There is no such button | ```KOTLIN fun main() { val button = "A" println( // Write your code here ) } ``` ```KOTLIN fun main() { val button = "A" println( when (button) { "A" -> "Yes" "B" -> "No" "X" -> "Menu" "Y" -> "Nothing" else -> "There is no such button" } ) } ``` ## Ranges Before talking about loops, it's useful to know how to construct ranges for loops to iterate over. The most common way to create a range in Kotlin is to use the `..` operator. For example, `1..4` is equivalent to `1, 2, 3, 4`. To declare a range that doesn't include the end value, use the `..<` operator. For example, `1..<4` is equivalent to `1, 2, 3`. To declare a range in reverse order, use [downTo](https://kotlinlang.org/api/core/kotlin-stdlib/kotlin.ranges/down-to.html). For example, `4 downTo 1` is equivalent to `4, 3, 2, 1`. To declare a range that increments in a step that isn't 1, use [step](https://kotlinlang.org/api/core/kotlin-stdlib/kotlin.ranges/step.html) and your desired increment value. For example, `1..5 step 2` is equivalent to `1, 3, 5`. You can also do the same with `Char` ranges: * `'a'..'d'` is equivalent to `'a', 'b', 'c', 'd'` * `'z' downTo 's' step 2` is equivalent to `'z', 'x', 'v', 't'` ## Loops The two most common loop structures in programming are `for` and `while`. Use `for` to iterate over a range of values and perform an action. Use `while` to continue an action until a particular condition is satisfied. ### For Using your new knowledge of ranges, you can create a `for` loop that iterates over numbers 1 to 5 and prints the number each time. Place the iterator and range within parentheses `()` with keyword `in`. Add the action you want to complete within curly braces `{}`: ```KOTLIN fun main() { //sampleStart for (number in 1..5) { // number is the iterator and 1..5 is the range print(number) } // 12345 //sampleEnd } ``` Collections can also be iterated over by loops: ```KOTLIN fun main() { //sampleStart val cakes = listOf("carrot", "cheese", "chocolate") for (cake in cakes) { println("Yummy, it's a $cake cake!") } // Yummy, it's a carrot cake! // Yummy, it's a cheese cake! // Yummy, it's a chocolate cake! //sampleEnd } ``` ### While `while` can be used in two ways: * To execute a code block while a conditional expression is true. (`while`) * To execute the code block first and then check the conditional expression. (`do-while`) In the first use case (`while`): * Declare the conditional expression for your while loop to continue within parentheses `()`. * Add the action you want to complete within curly braces `{}`. Tip: The following examples use the [increment operator](operator-overloading.html#increments-and-decrements) `++` to increment the value of the `cakesEaten` variable. ```KOTLIN fun main() { //sampleStart var cakesEaten = 0 while (cakesEaten < 3) { println("Eat a cake") cakesEaten++ } // Eat a cake // Eat a cake // Eat a cake //sampleEnd } ``` In the second use case (`do-while`): * Declare the conditional expression for your while loop to continue within parentheses `()`. * Define the action you want to complete within curly braces `{}` with the keyword `do`. ```KOTLIN fun main() { //sampleStart var cakesEaten = 0 var cakesBaked = 0 while (cakesEaten < 3) { println("Eat a cake") cakesEaten++ } do { println("Bake a cake") cakesBaked++ } while (cakesBaked < cakesEaten) // Eat a cake // Eat a cake // Eat a cake // Bake a cake // Bake a cake // Bake a cake //sampleEnd } ``` For more information and examples of conditional expressions and loops, see [Conditions and loops](control-flow.html). Now that you know the fundamentals of Kotlin control flow, it's time to learn how to write your own [functions](kotlin-tour-functions.html). ## Loops practice ### Exercise 1 You have a program that counts pizza slices until there's a whole pizza with 8 slices. Refactor this program in two ways: * Use a `while` loop. * Use a `do-while` loop. ```KOTLIN fun main() { var pizzaSlices = 0 // Start refactoring here pizzaSlices++ println("There's only $pizzaSlices slice/s of pizza :(") pizzaSlices++ println("There's only $pizzaSlices slice/s of pizza :(") pizzaSlices++ println("There's only $pizzaSlices slice/s of pizza :(") pizzaSlices++ println("There's only $pizzaSlices slice/s of pizza :(") pizzaSlices++ println("There's only $pizzaSlices slice/s of pizza :(") pizzaSlices++ println("There's only $pizzaSlices slice/s of pizza :(") pizzaSlices++ println("There's only $pizzaSlices slice/s of pizza :(") pizzaSlices++ // End refactoring here println("There are $pizzaSlices slices of pizza. Hooray! We have a whole pizza! :D") } ``` ```KOTLIN fun main() { var pizzaSlices = 0 while ( pizzaSlices < 7 ) { pizzaSlices++ println("There's only $pizzaSlices slice/s of pizza :(") } pizzaSlices++ println("There are $pizzaSlices slices of pizza. Hooray! We have a whole pizza! :D") } ``` ```KOTLIN fun main() { var pizzaSlices = 0 pizzaSlices++ do { println("There's only $pizzaSlices slice/s of pizza :(") pizzaSlices++ } while ( pizzaSlices < 8 ) println("There are $pizzaSlices slices of pizza. Hooray! We have a whole pizza! :D") } ``` ### Exercise 2 Write a program that simulates the [Fizz buzz](https://en.wikipedia.org/wiki/Fizz_buzz) game. Your task is to print numbers from 1 to 100 incrementally, replacing any number divisible by three with the word "fizz", and any number divisible by five with the word "buzz". Any number divisible by both 3 and 5 must be replaced with the word "fizzbuzz". Hint 1 : Use a : `for` : loop to count numbers and a : `when` : expression to decide what to print at each step. Hint 2 : Use the modulo operator ( : `%` : ) to return the remainder of a number being divided. Use the : [equality operator](operator-overloading.html#equality-and-inequality-operators) : ( : `==` : ) to check if the remainder equals zero. ```KOTLIN fun main() { // Write your code here } ``` ```KOTLIN fun main() { for (number in 1..100) { println( when { number % 15 == 0 -> "fizzbuzz" number % 3 == 0 -> "fizz" number % 5 == 0 -> "buzz" else -> "$number" } ) } } ``` ### Exercise 3 You have a list of words. Use `for` and `if` to print only the words that start with the letter `l`. Hint : Use the : [.startsWith()](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.text/starts-with.html) : function for : `String` : type. ```KOTLIN fun main() { val words = listOf("dinosaur", "limousine", "magazine", "language") // Write your code here } ``` ```KOTLIN fun main() { val words = listOf("dinosaur", "limousine", "magazine", "language") for (w in words) { if (w.startsWith("l")) println(w) } } ``` ## See also * [Previous step](kotlin-tour-collections.html) * [Next step](kotlin-tour-functions.html) # Functions You can declare your own functions in Kotlin using the `fun` keyword. ```KOTLIN fun hello() { return println("Hello, world!") } fun main() { hello() // Hello, world! } ``` In Kotlin: * Function parameters are written within parentheses `()`. * Each parameter must have a type, and multiple parameters must be separated by commas `,`. * The return type is written after the function's parentheses `()`, separated by a colon `:`. * The body of a function is written within curly braces `{}`. * The `return` keyword is used to exit or return something from a function. Note: If a function doesn't return anything useful, the return type and `return` keyword can be omitted. Learn more about this in [Functions without return](#functions-without-return). In the following example: * `x` and `y` are function parameters. * `x` and `y` have type `Int`. * The function's return type is `Int`. * The function returns a sum of `x` and `y` when called. ```KOTLIN fun sum(x: Int, y: Int): Int { return x + y } fun main() { println(sum(1, 2)) // 3 } ``` Note: We recommend in our [coding conventions](coding-conventions.html#function-names) that you name functions starting with a lowercase letter and use camel case with no underscores. ## Named arguments For concise code, when calling your function, you don't have to include parameter names. However, including parameter names does make your code easier to read. This is called using named arguments. If you do include parameter names, then you can write the parameters in any order. Tip: In the following example, [string templates](strings.html#string-templates) (`$`) are used to access the parameter values, convert them to `String` type, and then concatenate them into a string for printing. ```KOTLIN fun printMessageWithPrefix(message: String, prefix: String) { println("[$prefix] $message") } fun main() { // Uses named arguments with swapped parameter order printMessageWithPrefix(prefix = "Log", message = "Hello") // [Log] Hello } ``` ## Default parameter values You can define default values for your function parameters. Any parameter with a default value can be omitted when calling your function. To declare a default value, use the assignment operator `=` after the type: ```KOTLIN fun printMessageWithPrefix(message: String, prefix: String = "Info") { println("[$prefix] $message") } fun main() { // Function called with both parameters printMessageWithPrefix("Hello", "Log") // [Log] Hello // Function called only with message parameter printMessageWithPrefix("Hello") // [Info] Hello printMessageWithPrefix(prefix = "Log", message = "Hello") // [Log] Hello } ``` Note: You can skip specific parameters with default values, rather than omitting them all. However, after the first skipped parameter, you must name all subsequent parameters. ## Functions without return If your function doesn't return a useful value, then its return type is `Unit`. `Unit` is a type with only one value – `Unit`. You don't have to declare that `Unit` is returned explicitly in your function body. This means that you don't have to use the `return` keyword or declare a return type: ```KOTLIN fun printMessage(message: String) { println(message) // `return Unit` or `return` is optional } fun main() { printMessage("Hello") // Hello } ``` ## Single-expression functions To make your code more concise, you can use single-expression functions. For example, the `sum()` function can be shortened: ```KOTLIN fun sum(x: Int, y: Int): Int { return x + y } fun main() { println(sum(1, 2)) // 3 } ``` You can remove the curly braces `{}` and declare the function body using the assignment operator `=`. When you use the assignment operator `=`, Kotlin uses type inference, so you can also omit the return type. The `sum()` function then becomes one line: ```KOTLIN fun sum(x: Int, y: Int) = x + y fun main() { println(sum(1, 2)) // 3 } ``` However, if you want your code to be quickly understood by other developers, it's a good idea to explicitly define the return type even when using the assignment operator `=`. Note: If you use `{}` curly braces to declare your function body, you must declare the return type unless it is the `Unit` type. ## Early returns in functions To stop the code in your function from being processed further than a certain point, use the `return` keyword. This example uses `if` to return from a function early if the conditional expression is found to be true: ```KOTLIN // A list of registered usernames val registeredUsernames = mutableListOf("john_doe", "jane_smith") // A list of registered emails val registeredEmails = mutableListOf("john@example.com", "jane@example.com") fun registerUser(username: String, email: String): String { // Early return if the username is already taken if (username in registeredUsernames) { return "Username already taken. Please choose a different username." } // Early return if the email is already registered if (email in registeredEmails) { return "Email already registered. Please use a different email." } // Proceed with the registration if the username and email are not taken registeredUsernames.add(username) registeredEmails.add(email) return "User registered successfully: $username" } fun main() { println(registerUser("john_doe", "newjohn@example.com")) // Username already taken. Please choose a different username. println(registerUser("new_user", "newuser@example.com")) // User registered successfully: new_user } ``` ## Functions practice ### Exercise 1 Write a function called `circleArea` that takes the radius of a circle in integer format as a parameter and outputs the area of that circle. Tip: In this exercise, you import a package so that you can access the value of $π$ via `PI`. For more information about importing packages, see [Packages and imports](packages.html). Hint : The formula for calculating the area of a circle is : $πr^2$ : , where : $r$ : is the radius. ```KOTLIN import kotlin.math.PI // Write your code here fun main() { println(circleArea(2)) } ``` ```KOTLIN import kotlin.math.PI fun circleArea(radius: Int): Double { return PI * radius * radius } fun main() { println(circleArea(2)) // 12.566370614359172 } ``` ### Exercise 2 Rewrite the `circleArea` function from the previous exercise as a single-expression function. ```KOTLIN import kotlin.math.PI // Write your code here fun main() { println(circleArea(2)) } ``` ```KOTLIN import kotlin.math.PI fun circleArea(radius: Int): Double = PI * radius * radius fun main() { println(circleArea(2)) // 12.566370614359172 } ``` ### Exercise 3 You have a function that translates a time interval given in hours, minutes, and seconds into seconds. In most cases, you need to pass only one or two function parameters while the rest are equal to 0. Improve the function and the code that calls it by using default parameter values and named arguments so that the code is easier to read. ```KOTLIN fun intervalInSeconds(hours: Int, minutes: Int, seconds: Int) = ((hours * 60) + minutes) * 60 + seconds fun main() { println(intervalInSeconds(1, 20, 15)) println(intervalInSeconds(0, 1, 25)) println(intervalInSeconds(2, 0, 0)) println(intervalInSeconds(0, 10, 0)) println(intervalInSeconds(1, 0, 1)) } ``` ```KOTLIN fun intervalInSeconds(hours: Int = 0, minutes: Int = 0, seconds: Int = 0) = ((hours * 60) + minutes) * 60 + seconds fun main() { println(intervalInSeconds(1, 20, 15)) println(intervalInSeconds(minutes = 1, seconds = 25)) println(intervalInSeconds(hours = 2)) println(intervalInSeconds(minutes = 10)) println(intervalInSeconds(hours = 1, seconds = 1)) } ``` ## Lambda expressions Kotlin allows you to write even more concise code for functions by using lambda expressions. For example, the following `uppercaseString()` function: ```KOTLIN fun uppercaseString(text: String): String { return text.uppercase() } fun main() { println(uppercaseString("hello")) // HELLO } ``` Can also be written as a lambda expression: ```KOTLIN fun main() { val upperCaseString = { text: String -> text.uppercase() } println(upperCaseString("hello")) // HELLO } ``` Lambda expressions can be hard to understand at first glance, so let's break it down. Lambda expressions are written within curly braces `{}`. Within the lambda expression, you write: * The parameters followed by an `->`. * The function body after the `->`. In the previous example: * `text` is a function parameter. * `text` has type `String`. * The function returns the result of the [.uppercase()](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.text/uppercase.html) function called on `text`. * The entire lambda expression is assigned to the `upperCaseString` variable with the assignment operator `=`. * The lambda expression is called by using the variable `upperCaseString` like a function and the string `"hello"` as a parameter. * The `println()` function prints the result. Note: If you declare a lambda without parameters, then there is no need to use `->`. For example: ```KOTLIN { println("Log message") } ``` Lambda expressions can be used in a number of ways. You can: * [Pass a lambda expression as a parameter to another function](#pass-to-another-function) * [Return a lambda expression from a function](#return-from-a-function) * [Invoke a lambda expression on its own](#invoke-separately) ### Pass to another function A great example of when it is useful to pass a lambda expression to a function, is using the [.filter()](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.collections/filter.html) function on collections: ```KOTLIN fun main() { //sampleStart val numbers = listOf(1, -2, 3, -4, 5, -6) val positives = numbers.filter ({ x -> x > 0 }) val isNegative = { x: Int -> x < 0 } val negatives = numbers.filter(isNegative) println(positives) // [1, 3, 5] println(negatives) // [-2, -4, -6] //sampleEnd } ``` The `.filter()` function accepts a lambda expression as a predicate and applies it to each element of the list. The function keeps an element only if the predicate returns `true`: * `{ x -> x > 0 }` returns `true` if the element is positive. * `{ x -> x < 0 }` returns `true` if the element is negative. This example demonstrates two ways of passing a lambda expression to a function: * For positive numbers, the example adds the lambda expression directly in the `.filter()` function. * For negative numbers, the example assigns the lambda expression to the `isNegative` variable. Then the `isNegative` variable is used as a function parameter in the `.filter()` function. In this case, you have to specify the type of function parameters (`x`) in the lambda expression. Note: If a lambda expression is the only function parameter, you can drop the function parentheses `()`: ```KOTLIN val positives = numbers.filter { x -> x > 0 } ``` This is an example of a [trailing lambda](#trailing-lambdas), which is discussed in more detail at the end of this chapter. Another good example is using the [.map()](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.collections/map.html) function to transform items in a collection: ```KOTLIN fun main() { //sampleStart val numbers = listOf(1, -2, 3, -4, 5, -6) val doubled = numbers.map { x -> x * 2 } val isTripled = { x: Int -> x * 3 } val tripled = numbers.map(isTripled) println(doubled) // [2, -4, 6, -8, 10, -12] println(tripled) // [3, -6, 9, -12, 15, -18] //sampleEnd } ``` The `.map()` function accepts a lambda expression as a transform function: * `{ x -> x * 2 }` takes each element of the list and returns that element multiplied by 2. * `{ x -> x * 3 }` takes each element of the list and returns that element multiplied by 3. ### Function types Before you can return a lambda expression from a function, you first need to understand function types. You have already learned about basic types but functions themselves also have a type. Kotlin's type inference can infer a function's type from the parameter type. But there may be times when you need to explicitly specify the function type. The compiler needs the function type so that it knows what is and isn't allowed for that function. The syntax for a function type has: * Each parameter's type written within parentheses `()` and separated by commas `,`. * The return type written after `->`. For example: `(String) -> String` or `(Int, Int) -> Int`. This is what a lambda expression looks like if a function type for `upperCaseString()` is defined: ```KOTLIN val upperCaseString: (String) -> String = { text -> text.uppercase() } fun main() { println(upperCaseString("hello")) // HELLO } ``` If your lambda expression has no parameters, then the parentheses `()` are left empty. For example: `() -> Unit` Note: You must declare parameter and return types either in the lambda expression or as a function type. Otherwise, the compiler won't be able to know what type your lambda expression is. For example, the following won't work: `val upperCaseString = { str -> str.uppercase() }` ### Return from a function Lambda expressions can be returned from a function. So that the compiler understands what type the lambda expression returned is, you must declare a function type. In the following example, the `toSeconds()` function has function type `(Int) -> Int` because it always returns a lambda expression that takes a parameter of type `Int` and returns an `Int` value. This example uses a `when` expression to determine which lambda expression is returned when `toSeconds()` is called: ```KOTLIN fun toSeconds(time: String): (Int) -> Int = when (time) { "hour" -> { value -> value * 60 * 60 } "minute" -> { value -> value * 60 } "second" -> { value -> value } else -> { value -> value } } fun main() { val timesInMinutes = listOf(2, 10, 15, 1) val min2sec = toSeconds("minute") val totalTimeInSeconds = timesInMinutes.map(min2sec).sum() println("Total time is $totalTimeInSeconds secs") // Total time is 1680 secs } ``` ### Invoke separately Lambda expressions can be invoked on their own by adding parentheses `()` after the curly braces `{}` and including any parameters within the parentheses: ```KOTLIN fun main() { //sampleStart println({ text: String -> text.uppercase() }("hello")) // HELLO //sampleEnd } ``` ### Trailing lambdas As you have already seen, if a lambda expression is the only function parameter, you can drop the function parentheses `()`. If a lambda expression is passed as the last parameter of a function, then the expression can be written outside the function parentheses `()`. In both cases, this syntax is called a trailing lambda. For example, the [.fold()](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.sequences/fold.html) function accepts an initial value and an operation: ```KOTLIN fun main() { //sampleStart // The initial value is zero. // The operation sums the initial value with every item in the list cumulatively. println(listOf(1, 2, 3).fold(0, { x, item -> x + item })) // 6 // Alternatively, in the form of a trailing lambda println(listOf(1, 2, 3).fold(0) { x, item -> x + item }) // 6 //sampleEnd } ``` For more information on lambda expressions, see [Lambda expressions and anonymous functions](lambdas.html#lambda-expressions-and-anonymous-functions). The next step in our tour is to learn about [classes](kotlin-tour-classes.html) in Kotlin. ## Lambda expressions practice ### Exercise 1 You have a list of actions supported by a web service, a common prefix for all requests, and an ID of a particular resource. To request an action `title` over the resource with ID: 5, you need to create the following URL: `https://example.com/book-info/5/title`. Use a lambda expression to create a list of URLs from the list of actions. ```KOTLIN fun main() { val actions = listOf("title", "year", "author") val prefix = "https://example.com/book-info" val id = 5 val urls = // Write your code here println(urls) } ``` ```KOTLIN fun main() { val actions = listOf("title", "year", "author") val prefix = "https://example.com/book-info" val id = 5 val urls = actions.map { action -> "$prefix/$id/$action" } println(urls) } ``` ### Exercise 2 Write a function that takes an `Int` value and an action (a function with type `() -> Unit`) which then repeats the action the given number of times. Then use this function to print “Hello” 5 times. ```KOTLIN fun repeatN(n: Int, action: () -> Unit) { // Write your code here } fun main() { // Write your code here } ``` ```KOTLIN fun repeatN(n: Int, action: () -> Unit) { for (i in 1..n) { action() } } fun main() { repeatN(5) { println("Hello") } } ``` ## See also * [Previous step](kotlin-tour-control-flow.html) * [Next step](kotlin-tour-classes.html) # Classes Kotlin supports object-oriented programming with classes and objects. Objects are useful for storing data in your program. Classes allow you to declare a set of characteristics for an object. When you create objects from a class, you can save time and effort because you don't have to declare these characteristics every time. To declare a class, use the `class` keyword: ```KOTLIN class Customer ``` ## Properties Characteristics of a class's object can be declared in properties. You can declare properties for a class: * Within parentheses `()` after the class name. ```KOTLIN class Contact(val id: Int, var email: String) ``` * Within the class body defined by curly braces `{}`. ```KOTLIN class Contact(val id: Int, var email: String) { val category: String = "" } ``` We recommend that you declare properties as read-only (`val`) unless they need to be changed after an instance of the class is created. You can declare properties without `val` or `var` within parentheses but these properties are not accessible after an instance has been created. Note: * The content contained within parentheses `()` is called the class header. * You can use a [trailing comma](coding-conventions.html#trailing-commas) when declaring class properties. Just like with function parameters, class properties can have default values: ```KOTLIN class Contact(val id: Int, var email: String = "example@gmail.com") { val category: String = "work" } ``` ## Create instance To create an object from a class, you declare a class instance using a constructor. By default, Kotlin automatically creates a constructor with the parameters declared in the class header. For example: ```KOTLIN class Contact(val id: Int, var email: String) fun main() { val contact = Contact(1, "mary@gmail.com") } ``` In the example: * `Contact` is a class. * `contact` is an instance of the `Contact` class. * `id` and `email` are properties. * `id` and `email` are used with the default constructor to create `contact`. Kotlin classes can have many constructors, including ones that you define yourself. To learn more about how to declare multiple constructors, see [Constructors](classes.html#constructors-and-initializer-blocks). ## Access properties To access a property of an instance, write the name of the property after the instance name appended with a period `.`: ```KOTLIN class Contact(val id: Int, var email: String) fun main() { val contact = Contact(1, "mary@gmail.com") // Prints the value of the property: email println(contact.email) // mary@gmail.com // Updates the value of the property: email contact.email = "jane@gmail.com" // Prints the new value of the property: email println(contact.email) // jane@gmail.com } ``` Tip: To concatenate the value of a property as part of a string, you can use string templates (`$`). For example: ```KOTLIN println("Their email address is: ${contact.email}") ``` ## Member functions In addition to declaring properties as part of an object's characteristics, you can also define an object's behavior with member functions. In Kotlin, member functions must be declared within the class body. To call a member function on an instance, write the function name after the instance name appended with a period `.`. For example: ```KOTLIN class Contact(val id: Int, var email: String) { fun printId() { println(id) } } fun main() { val contact = Contact(1, "mary@gmail.com") // Calls member function printId() contact.printId() // 1 } ``` ## Data classes Kotlin has data classes which are particularly useful for storing data. Data classes have the same functionality as classes, but they come automatically with additional member functions. These member functions allow you to easily print the instance to readable output, compare instances of a class, copy instances, and more. As these functions are automatically available, you don't have to spend time writing the same boilerplate code for each of your classes. To declare a data class, use the keyword `data`: ```KOTLIN data class User(val name: String, val id: Int) ``` The Kotlin compiler only uses the properties defined inside the [primary constructor](classes.html#primary-constructor) when generating member functions. If you declare properties in the data class body, they aren't included in the output of the generated functions. The most useful predefined member functions of data classes are: | Function |Description | ------------------------- | `toString()` |Prints a readable string of the class instance and its properties. | | `equals()` or `==` |Compares instances of a class. | | `copy()` |Creates a class instance by copying another, potentially with some different properties. | See the following sections for examples of how to use each function: * [Print as string](#print-as-string) * [Compare instances](#compare-instances) * [Copy instance](#copy-instance) ### Print as string To print a readable string of a class instance, you can explicitly call the `toString()` function, or use print functions (`println()` and `print()`) which automatically call `toString()` for you: ```KOTLIN data class User(val name: String, val id: Int) fun main() { //sampleStart val user = User("Alex", 1) // Automatically uses toString() function so that output is easy to read println(user) // User(name=Alex, id=1) //sampleEnd } ``` This is particularly useful when debugging or creating logs. ### Compare instances To compare data class instances, use the equality operator `==`: ```KOTLIN data class User(val name: String, val id: Int) fun main() { //sampleStart val user = User("Alex", 1) val secondUser = User("Alex", 1) val thirdUser = User("Max", 2) // Compares user to second user println("user == secondUser: ${user == secondUser}") // user == secondUser: true // Compares user to third user println("user == thirdUser: ${user == thirdUser}") // user == thirdUser: false //sampleEnd } ``` ### Copy instance To create an exact copy of a data class instance, call the `copy()` function on the instance. To create a copy of a data class instance and change some properties, call the `copy()` function on the instance and add replacement values for properties as function parameters. For example: ```KOTLIN data class User(val name: String, val id: Int) fun main() { //sampleStart val user = User("Alex", 1) // Creates an exact copy of user println(user.copy()) // User(name=Alex, id=1) // Creates a copy of user with name: "Max" println(user.copy("Max")) // User(name=Max, id=1) // Creates a copy of user with id: 3 println(user.copy(id = 3)) // User(name=Alex, id=3) //sampleEnd } ``` Creating a copy of an instance is safer than modifying the original instance because any code that relies on the original instance isn't affected by the copy and what you do with it. For more information about data classes, see [Data classes](data-classes.html). The last chapter of this tour is about Kotlin's [null safety](kotlin-tour-null-safety.html). ## Practice ### Exercise 1 Define a data class `Employee` with two properties: one for a name, and another for a salary. Make sure that the property for salary is mutable, otherwise you won't get a salary boost at the end of the year! The main function demonstrates how you can use this data class. ```KOTLIN // Write your code here fun main() { val emp = Employee("Mary", 20) println(emp) emp.salary += 10 println(emp) } ``` ```KOTLIN data class Employee(val name: String, var salary: Int) fun main() { val emp = Employee("Mary", 20) println(emp) emp.salary += 10 println(emp) } ``` ### Exercise 2 Declare the additional data classes that are needed for this code to compile. ```KOTLIN data class Person(val name: Name, val address: Address, val ownsAPet: Boolean = true) // Write your code here // data class Name(...) fun main() { val person = Person( Name("John", "Smith"), Address("123 Fake Street", City("Springfield", "US")), ownsAPet = false ) } ``` ```KOTLIN data class Person(val name: Name, val address: Address, val ownsAPet: Boolean = true) data class Name(val first: String, val last: String) data class Address(val street: String, val city: City) data class City(val name: String, val countryCode: String) fun main() { val person = Person( Name("John", "Smith"), Address("123 Fake Street", City("Springfield", "US")), ownsAPet = false ) } ``` ### Exercise 3 To test your code, you need a generator that can create random employees. Define a `RandomEmployeeGenerator` class with a fixed list of potential names (inside the class body). Configure the class with a minimum and maximum salary (inside the class header). In the class body, define the `generateEmployee()` function. Once again, the main function demonstrates how you can use this class. Tip: In this exercise, you import a package so that you can use the [Random.nextInt()](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.random/-random/next-int.html) function. For more information about importing packages, see [Packages and imports](packages.html). Hint 1 : Lists have an extension function called : [.random()](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.collections/random.html) : that returns a random item within a list. Hint 2 : `Random.nextInt(from = ..., until = ...)` : gives you a random : `Int` : number within specified limits. ```KOTLIN import kotlin.random.Random data class Employee(val name: String, var salary: Int) // Write your code here fun main() { val empGen = RandomEmployeeGenerator(10, 30) println(empGen.generateEmployee()) println(empGen.generateEmployee()) println(empGen.generateEmployee()) empGen.minSalary = 50 empGen.maxSalary = 100 println(empGen.generateEmployee()) } ``` ```KOTLIN import kotlin.random.Random data class Employee(val name: String, var salary: Int) class RandomEmployeeGenerator(var minSalary: Int, var maxSalary: Int) { val names = listOf("John", "Mary", "Ann", "Paul", "Jack", "Elizabeth") fun generateEmployee() = Employee(names.random(), Random.nextInt(from = minSalary, until = maxSalary)) } fun main() { val empGen = RandomEmployeeGenerator(10, 30) println(empGen.generateEmployee()) println(empGen.generateEmployee()) println(empGen.generateEmployee()) empGen.minSalary = 50 empGen.maxSalary = 100 println(empGen.generateEmployee()) } ``` ## See also * [Previous step](kotlin-tour-functions.html) * [Next step](kotlin-tour-null-safety.html) # Null safety In Kotlin, it's possible to have a `null` value. Kotlin uses `null` values when something is missing or not yet set. You've already seen an example of Kotlin returning a `null` value in the [Collections](kotlin-tour-collections.html#kotlin-tour-map-no-key) chapter when you tried to access a key-value pair with a key that doesn't exist in the map. Although it's useful to use `null` values in this way, you might run into problems if your code isn't prepared to handle them. To help prevent issues with `null` values in your programs, Kotlin has null safety in place. Null safety detects potential problems with `null` values at compile time, rather than at run time. Null safety is a combination of features that allow you to: * Explicitly declare when `null` values are allowed in your program. * Check for `null` values. * Use safe calls to properties or functions that may contain `null` values. * Declare actions to take if `null` values are detected. ## Nullable types Kotlin supports nullable types which allows the possibility for the declared type to have `null` values. By default, a type is not allowed to accept `null` values. Nullable types are declared by explicitly adding `?` after the type declaration. For example: ```KOTLIN fun main() { // neverNull has String type var neverNull: String = "This can't be null" // Throws a compiler error neverNull = null // nullable has nullable String type var nullable: String? = "You can keep a null here" // This is OK nullable = null // By default, null values aren't accepted var inferredNonNull = "The compiler assumes non-nullable" // Throws a compiler error inferredNonNull = null // notNull doesn't accept null values fun strLength(notNull: String): Int { return notNull.length } println(strLength(neverNull)) // 18 println(strLength(nullable)) // Throws a compiler error } ``` Tip: `length` is a property of the [String](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-string/) class that contains the number of characters within a string. ## Check for null values You can check for the presence of `null` values within conditional expressions. In the following example, the `describeString()` function has an `if` statement that checks whether `maybeString` is not `null` and if its `length` is greater than zero: ```KOTLIN fun describeString(maybeString: String?): String { if (maybeString != null && maybeString.length > 0) { return "String of length ${maybeString.length}" } else { return "Empty or null string" } } fun main() { val nullString: String? = null println(describeString(nullString)) // Empty or null string } ``` ## Use safe calls To safely access properties of an object that might contain a `null` value, use the safe call operator `?.`. The safe call operator returns `null` if either the object or one of its accessed properties is `null`. This is useful if you want to avoid the presence of `null` values triggering errors in your code. In the following example, the `lengthString()` function uses a safe call to return either the length of the string or `null`: ```KOTLIN fun lengthString(maybeString: String?): Int? = maybeString?.length fun main() { val nullString: String? = null println(lengthString(nullString)) // null } ``` Tip: Safe calls can be chained so that if any property of an object contains a `null` value, then `null` is returned without an error being thrown. For example: ```KOTLIN person.company?.address?.country ``` The safe call operator can also be used to safely call an extension or member function. In this case, a null check is performed before the function is called. If the check detects a `null` value, then the call is skipped and `null` is returned. In the following example, `nullString` is `null` so the invocation of [.uppercase()](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.text/uppercase.html) is skipped and `null` is returned: ```KOTLIN fun main() { val nullString: String? = null println(nullString?.uppercase()) // null } ``` ## Use Elvis operator You can provide a default value to return if a `null` value is detected by using the Elvis operator `?:`. Write on the left-hand side of the Elvis operator what should be checked for a `null` value. Write on the right-hand side of the Elvis operator what should be returned if a `null` value is detected. In the following example, `nullString` is `null` so the safe call to access the `length` property returns a `null` value. As a result, the Elvis operator returns `0`: ```KOTLIN fun main() { val nullString: String? = null println(nullString?.length ?: 0) // 0 } ``` For more information about null safety in Kotlin, see [Null safety](null-safety.html). ## Practice ### Exercise You have the `employeeById` function that gives you access to a database of employees of a company. Unfortunately, this function returns a value of the `Employee?` type, so the result can be `null`. Your goal is to write a function that returns the salary of an employee when their `id` is provided, or `0` if the employee is missing from the database. ```KOTLIN data class Employee (val name: String, var salary: Int) fun employeeById(id: Int) = when(id) { 1 -> Employee("Mary", 20) 2 -> null 3 -> Employee("John", 21) 4 -> Employee("Ann", 23) else -> null } fun salaryById(id: Int) = // Write your code here fun main() { println((1..5).sumOf { id -> salaryById(id) }) } ``` ```KOTLIN data class Employee (val name: String, var salary: Int) fun employeeById(id: Int) = when(id) { 1 -> Employee("Mary", 20) 2 -> null 3 -> Employee("John", 21) 4 -> Employee("Ann", 23) else -> null } fun salaryById(id: Int) = employeeById(id)?.salary ?: 0 fun main() { println((1..5).sumOf { id -> salaryById(id) }) } ``` ## What's next? Congratulations! Now that you have completed the beginner tour, take your understanding of Kotlin to the next level with our intermediate tour: ## See also * [Previous step](kotlin-tour-classes.html) * [Start intermediate Kotlin tour](kotlin-tour-intermediate-extension-functions.html) # Extension functions In this chapter, you'll explore special Kotlin functions that make your code more concise and readable. Learn how they can help you use efficient design patterns to take your projects to the next level. ## Extension functions In software development, you often need to modify a program's behavior without changing the original source code. For example, you might want to add extra functionality to a class from a third-party library. You can do this by adding extension functions to extend a class. You call extension functions the same way you call member functions of a class, using a period `.`. Before introducing the complete syntax for extension functions, you need to understand what a receiver is. The receiver is what the function is called on. In other words, the receiver is where or with whom the information is shared. ![An example of sender and receiver](images/receiver-highlight.png) In this example, the `main()` function calls the [.first()](https://kotlinlang.org/api/core/kotlin-stdlib/kotlin.collections/first.html) function to return the first element in a list. The `.first()` function is called on the `readOnlyShapes` variable, so the `readOnlyShapes` variable is the receiver. To create an extension function, write the name of the class that you want to extend followed by a `.` and the name of your function. Continue with the rest of the function declaration, including its parameters and return type. For example: ```KOTLIN fun String.bold(): String = "$this" fun main() { // "hello" is the receiver println("hello".bold()) // hello } ``` In this example: * `String` is the extended class. * `bold` is the name of the extension function. * The `.bold()` extension function's return type is `String`. * `"hello"`, an instance of `String`, as the receiver. * The receiver is accessed inside the body by the [keyword](keyword-reference.html): `this`. * A string template (`$`) is used to access the value of `this`. * The `.bold()` extension function takes a string and returns it in a `` HTML element for bold text. ## Extension-oriented design You can define extension functions anywhere, which enables you to create extension-oriented designs. These designs separate core functionality from useful but non-essential features, making your code easier to read and maintain. A good example is the [HttpClient](https://api.ktor.io/ktor-client-core/io.ktor.client/-http-client/index.html) class from the Ktor library, which helps perform network requests. The core of its functionality is a single function `request()`, which takes all the information needed for an HTTP request: ```KOTLIN class HttpClient { fun request(method: String, url: String, headers: Map): HttpResponse { // Network code } } ``` In practice, the most popular HTTP requests are GET or POST requests. It makes sense for the library to provide shorter names for these common use cases. However, these don't require writing new network code, only a specific request call. In other words, they are perfect candidates to be defined as separate `.get()` and `.post()` extension functions: ```KOTLIN fun HttpClient.get(url: String): HttpResponse = request("GET", url, emptyMap()) fun HttpClient.post(url: String): HttpResponse = request("POST", url, emptyMap()) ``` These `.get()` and `.post()` functions extend the `HttpClient` class. They can directly use the `request()` function from the `HttpClient` class because they're called on an instance of the `HttpClient` class as the receiver. You can use these extension functions to call the `request()` function with the appropriate HTTP method, which simplifies your code and makes it easier to understand: ```KOTLIN class HttpClient { fun request(method: String, url: String, headers: Map): HttpResponse { println("Requesting $method to $url with headers: $headers") return HttpResponse("Response from $url") } } fun HttpClient.get(url: String): HttpResponse = request("GET", url, emptyMap()) fun main() { val client = HttpClient() // Making a GET request using request() directly val getResponseWithMember = client.request("GET", "https://example.com", emptyMap()) // Making a GET request using the get() extension function // The client instance is the receiver val getResponseWithExtension = client.get("https://example.com") } ``` This extension-oriented approach is widely used in Kotlin's [standard library](https://kotlinlang.org/api/latest/jvm/stdlib/) and other libraries. For example, the `String` class has many [extension functions](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-string/#extension-functions) to help you work with strings. For more information about extension functions, see [Extensions](extensions.html). ## Practice ### Exercise 1 Write an extension function called `isPositive` that takes an integer and checks whether it is positive. ```KOTLIN fun Int.// Write your code here fun main() { println(1.isPositive()) // true } ``` ```KOTLIN fun Int.isPositive(): Boolean = this > 0 fun main() { println(1.isPositive()) // true } ``` ### Exercise 2 Write an extension function called `toLowercaseString` that takes a string and returns a lowercase version. Hint : Use the : [.lowercase()](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.text/lowercase.html) : function for the : `String` : type. ```KOTLIN fun // Write your code here fun main() { println("Hello World!".toLowercaseString()) // hello world! } ``` ```KOTLIN fun String.toLowercaseString(): String = this.lowercase() fun main() { println("Hello World!".toLowercaseString()) // hello world! } ``` ## See also * [Previous step](kotlin-tour-null-safety.html) * [Next step](kotlin-tour-intermediate-scope-functions.html) # Scope functions In this chapter, you'll build on your understanding of extension functions to learn how to use scope functions to write more idiomatic code. ## Scope functions In programming, a scope is the area in which your variable or object is recognized. The most commonly referred to scopes are the global scope and the local scope: * Global scope – a variable or object that is accessible from anywhere in the program. * Local scope – a variable or object that is only accessible within the block or function where it is defined. In Kotlin, there are also scope functions that allow you to create a temporary scope around an object and execute some code. Scope functions make your code more concise because you don't have to refer to the name of your object within the temporary scope. Depending on the scope function, you can access the object either by referencing it via the keyword `this` or using it as an argument via the keyword `it`. Kotlin has five scope functions in total: `let`, `apply`, `run`, `also`, and `with`. Each scope function takes a lambda expression and returns either the object or the result of the lambda expression. In this tour, we explain each scope function and how to use it. Tip: You can also watch the [Back to the Stdlib: Making the Most of Kotlin's Standard Library](https://youtu.be/DdvgvSHrN9g?feature=shared&t=1511) talk on scope functions by Sebastian Aigner, Kotlin developer advocate. ### Let Use the `let` scope function when you want to perform null checks in your code and later perform further actions with the returned object. Consider the example: ```KOTLIN fun sendNotification(recipientAddress: String): String { println("Yo $recipientAddress!") return "Notification sent!" } fun getNextAddress(): String { return "sebastian@jetbrains.com" } fun main() { val address: String? = getNextAddress() sendNotification(address) } ``` The example has two functions: * `sendNotification()`, which has a function parameter `recipientAddress` and returns a string. * `getNextAddress()`, which has no function parameters and returns a string. The example creates a variable `address` that has a nullable `String` type. But this becomes a problem when you call the `sendNotification()` function because this function doesn't expect that `address` could be a `null` value. The compiler reports an error as a result: ```TEXT Argument type mismatch: actual type is 'String?', but 'String' was expected. ``` From the beginner tour, you already know that you can perform a null check with an if condition or use the [Elvis operator ?:](kotlin-tour-null-safety.html#use-elvis-operator). But what if you want to use the returned object later in your code? You could achieve this with an if condition and an else branch: ```KOTLIN fun sendNotification(recipientAddress: String): String { println("Yo $recipientAddress!") return "Notification sent!" } fun getNextAddress(): String { return "sebastian@jetbrains.com" } fun main() { //sampleStart val address: String? = getNextAddress() val confirm = if(address != null) { sendNotification(address) } else { null } //sampleEnd } ``` However, a more concise approach is to use the `let` scope function: ```KOTLIN fun sendNotification(recipientAddress: String): String { println("Yo $recipientAddress!") return "Notification sent!" } fun getNextAddress(): String { return "sebastian@jetbrains.com" } fun main() { //sampleStart val address: String? = getNextAddress() val confirm = address?.let { sendNotification(it) } //sampleEnd } ``` The example: * Creates variables called `address` and `confirm`. * Uses a safe call for the `let` scope function on the `address` variable. * Creates a temporary scope within the `let` scope function. * Passes the `sendNotification()` function as a lambda expression into the `let` scope function. * Refers to the `address` variable via `it`, using the temporary scope. * Assigns the result to the `confirm` variable. With this approach, your code can handle the `address` variable potentially being a `null` value, and you can use the `confirm` variable later in your code. ### Apply Use the `apply` scope function to initialize objects, like a class instance, at the time of creation rather than later on in your code. This approach makes your code easier to read and manage. Consider the example: ```KOTLIN class Client() { var token: String? = null fun connect() = println("connected!") fun authenticate() = println("authenticated!") fun getData() : String { println("getting data!") return "Mock data" } } val client = Client() fun main() { client.token = "asdf" client.connect() // connected! client.authenticate() // authenticated! client.getData() // getting data! } ``` The example has a `Client` class that contains one property called `token` and three member functions: `connect()`, `authenticate()`, and `getData()`. The example creates `client` as an instance of the `Client` class before initializing its `token` property and calling its member functions in the `main()` function. Although this example is compact, in the real world, it can be a while before you can configure and use the class instance (and its member functions) after you've created it. However, if you use the `apply` scope function you can create, configure and use member functions on your class instance all in the same place in your code: ```KOTLIN class Client() { var token: String? = null fun connect() = println("connected!") fun authenticate() = println("authenticated!") fun getData() : String { println("getting data!") return "Mock data" } } //sampleStart val client = Client().apply { token = "asdf" connect() // connected! authenticate() // authenticated! } fun main() { client.getData() // getting data! } //sampleEnd ``` The example: * Creates `client` as an instance of the `Client` class. * Uses the `apply` scope function on the `client` instance. * Creates a temporary scope within the `apply` scope function so that you don't have to explicitly refer to the `client` instance when accessing its properties or functions. * Passes a lambda expression to the `apply` scope function that updates the `token` property and calls the `connect()` and `authenticate()` functions. * Calls the `getData()` member function on the `client` instance in the `main()` function. As you can see, this strategy is convenient when you are working with large pieces of code. ### Run Similar to `apply`, you can use the `run` scope function to initialize an object, but it's better to use `run` to initialize an object at a specific moment in your code and immediately compute a result. Let's continue the previous example for the `apply` function, but this time, you want the `connect()` and `authenticate()` functions to be grouped so that they are called on every request. For example: ```KOTLIN class Client() { var token: String? = null fun connect() = println("connected!") fun authenticate() = println("authenticated!") fun getData() : String { println("getting data!") return "Mock data" } } //sampleStart val client: Client = Client().apply { token = "asdf" } fun main() { val result: String = client.run { connect() // connected! authenticate() // authenticated! getData() // getting data! } } //sampleEnd ``` The example: * Creates `client` as an instance of the `Client` class. * Uses the `apply` scope function on the `client` instance. * Creates a temporary scope within the `apply` scope function so that you don't have to explicitly refer to the `client` instance when accessing its properties or functions. * Passes a lambda expression to the `apply` scope function that updates the `token` property. The `main()` function: * Creates a `result` variable with type `String`. * Uses the `run` scope function on the `client` instance. * Creates a temporary scope within the `run` scope function so that you don't have to explicitly refer to the `client` instance when accessing its properties or functions. * Passes a lambda expression to the `run` scope function that calls the `connect()`, `authenticate()`, and `getData()` functions. * Assigns the result to the `result` variable. Now you can use the returned result further in your code. ### Also Use the `also` scope function to complete an additional action with an object and then return the object to continue using it in your code, like writing a log. Consider the example: ```KOTLIN fun main() { val medals: List = listOf("Gold", "Silver", "Bronze") val reversedLongUppercaseMedals: List = medals .map { it.uppercase() } .filter { it.length > 4 } .reversed() println(reversedLongUppercaseMedals) // [BRONZE, SILVER] } ``` The example: * Creates the `medals` variable that contains a list of strings. * Creates the `reversedLongUpperCaseMedals` variable that has the `List` type. * Uses the `.map()` extension function on the `medals` variable. * Passes a lambda expression to the `.map()` function that refers to `medals` via the `it` keyword and calls the `.uppercase()` extension function on it. * Uses the `.filter()` extension function on the `medals` variable. * Passes a lambda expression as a predicate to the `.filter()` function that refers to `medals` via the `it` keyword and checks if the item in the list has more than 4 characters. * Uses the `.reversed()` extension function on the `medals` variable. * Assigns the result to the `reversedLongUpperCaseMedals` variable. * Prints the list contained in the `reversedLongUpperCaseMedals` variable. It would be useful to add some logging in between the function calls to see what is happening to the `medals` variable. The `also` function helps with that: ```KOTLIN fun main() { val medals: List = listOf("Gold", "Silver", "Bronze") val reversedLongUppercaseMedals: List = medals .map { it.uppercase() } .also { println(it) } // [GOLD, SILVER, BRONZE] .filter { it.length > 4 } .also { println(it) } // [SILVER, BRONZE] .reversed() println(reversedLongUppercaseMedals) // [BRONZE, SILVER] } ``` Now the example: * Uses the `also` scope function on the `medals` variable. * Creates a temporary scope within the `also` scope function so that you don't have to explicitly refer to the `medals` variable when using it as a function parameter. * Passes a lambda expression to the `also` scope function that calls the `println()` function using the `medals` variable as a function parameter via the `it` keyword. Since the `also` function returns the object, it is useful for not only logging but debugging, chaining multiple operations, and performing other side effect operations that don't affect the main flow of your code. ### With Unlike the other scope functions, `with` is not an extension function, so the syntax is different. You pass the receiver object to `with` as an argument. Use the `with` scope function when you want to call multiple functions on an object. Consider this example: ```KOTLIN class Canvas { fun rect(x: Int, y: Int, w: Int, h: Int): Unit = println("$x, $y, $w, $h") fun circ(x: Int, y: Int, rad: Int): Unit = println("$x, $y, $rad") fun text(x: Int, y: Int, str: String): Unit = println("$x, $y, $str") } fun main() { val mainMonitorPrimaryBufferBackedCanvas = Canvas() mainMonitorPrimaryBufferBackedCanvas.text(10, 10, "Foo") mainMonitorPrimaryBufferBackedCanvas.rect(20, 30, 100, 50) mainMonitorPrimaryBufferBackedCanvas.circ(40, 60, 25) mainMonitorPrimaryBufferBackedCanvas.text(15, 45, "Hello") mainMonitorPrimaryBufferBackedCanvas.rect(70, 80, 150, 100) mainMonitorPrimaryBufferBackedCanvas.circ(90, 110, 40) mainMonitorPrimaryBufferBackedCanvas.text(35, 55, "World") mainMonitorPrimaryBufferBackedCanvas.rect(120, 140, 200, 75) mainMonitorPrimaryBufferBackedCanvas.circ(160, 180, 55) mainMonitorPrimaryBufferBackedCanvas.text(50, 70, "Kotlin") } ``` The example creates a `Canvas` class that has three member functions: `rect()`, `circ()`, and `text()`. Each of these member functions prints a statement constructed from the function parameters that you provide. The example creates `mainMonitorPrimaryBufferBackedCanvas` as an instance of the `Canvas` class before calling a sequence of member functions on the instance with different function parameters. You can see that this code is hard to read. If you use the `with` function, the code is streamlined: ```KOTLIN class Canvas { fun rect(x: Int, y: Int, w: Int, h: Int): Unit = println("$x, $y, $w, $h") fun circ(x: Int, y: Int, rad: Int): Unit = println("$x, $y, $rad") fun text(x: Int, y: Int, str: String): Unit = println("$x, $y, $str") } fun main() { //sampleStart val mainMonitorSecondaryBufferBackedCanvas = Canvas() with(mainMonitorSecondaryBufferBackedCanvas) { text(10, 10, "Foo") rect(20, 30, 100, 50) circ(40, 60, 25) text(15, 45, "Hello") rect(70, 80, 150, 100) circ(90, 110, 40) text(35, 55, "World") rect(120, 140, 200, 75) circ(160, 180, 55) text(50, 70, "Kotlin") } //sampleEnd } ``` This example: * Uses the `with` scope function with the `mainMonitorSecondaryBufferBackedCanvas` instance as the receiver. * Creates a temporary scope within the `with` scope function so that you don't have to explicitly refer to the `mainMonitorSecondaryBufferBackedCanvas` instance when calling its member functions. * Passes a lambda expression to the `with` scope function that calls a sequence of member functions with different function parameters. Now that this code is much easier to read, you are less likely to make mistakes. ## Use case overview This section has covered the different scope functions available in Kotlin and their main use cases for making your code more idiomatic. You can use this table as a quick reference. It's important to note that you don't need a complete understanding of how these functions work in order to use them in your code. | Function |Access to `x` via |Return value |Use case | ------------------------------------------------------- | `let` |`it` |Lambda result |Perform null checks in your code and later perform further actions with the returned object. | | `apply` |`this` |`x` |Initialize objects at the time of creation. | | `run` |`this` |Lambda result |Initialize objects at the time of creation AND compute a result. | | `also` |`it` |`x` |Complete additional actions before returning the object. | | `with` |`this` |Lambda result |Call multiple functions on an object. | For more information about scope functions, see [Scope functions](scope-functions.html). ## Practice ### Exercise 1 Rewrite the `.getPriceInEuros()` function as a single-expression function that uses safe call operators `?.` and the `let` scope function. Hint : Use safe call operators : `?.` : to safely access the : `priceInDollars` : property from the : `getProductInfo()` : function. Then, use the : `let` : scope function to convert the value of : `priceInDollars` : into euros. ```KOTLIN data class ProductInfo(val priceInDollars: Double?) class Product { fun getProductInfo(): ProductInfo? { return ProductInfo(100.0) } } // Rewrite this function fun Product.getPriceInEuros(): Double? { val info = getProductInfo() if (info == null) return null val price = info.priceInDollars if (price == null) return null return convertToEuros(price) } fun convertToEuros(dollars: Double): Double { return dollars * 0.85 } fun main() { val product = Product() val priceInEuros = product.getPriceInEuros() if (priceInEuros != null) { println("Price in Euros: €$priceInEuros") // Price in Euros: €85.0 } else { println("Price information is not available.") } } ``` ```KOTLIN data class ProductInfo(val priceInDollars: Double?) class Product { fun getProductInfo(): ProductInfo? { return ProductInfo(100.0) } } fun Product.getPriceInEuros() = getProductInfo()?.priceInDollars?.let { convertToEuros(it) } fun convertToEuros(dollars: Double): Double { return dollars * 0.85 } fun main() { val product = Product() val priceInEuros = product.getPriceInEuros() if (priceInEuros != null) { println("Price in Euros: €$priceInEuros") // Price in Euros: €85.0 } else { println("Price information is not available.") } } ``` ### Exercise 2 You have an `updateEmail()` function that updates the email address of a user. Use the `apply` scope function to update the email address and then the `also` scope function to print a log message: `Updating email for user with ID: ${it.id}`. ```KOTLIN data class User(val id: Int, var email: String) fun updateEmail(user: User, newEmail: String): User = // Write your code here fun main() { val user = User(1, "old_email@example.com") val updatedUser = updateEmail(user, "new_email@example.com") // Updating email for user with ID: 1 println("Updated User: $updatedUser") // Updated User: User(id=1, email=new_email@example.com) } ``` ```KOTLIN data class User(val id: Int, var email: String) fun updateEmail(user: User, newEmail: String): User = user.apply { this.email = newEmail }.also { println("Updating email for user with ID: ${it.id}") } fun main() { val user = User(1, "old_email@example.com") val updatedUser = updateEmail(user, "new_email@example.com") // Updating email for user with ID: 1 println("Updated User: $updatedUser") // Updated User: User(id=1, email=new_email@example.com) } ``` ## See also * [Previous step](kotlin-tour-intermediate-extension-functions.html) * [Next step](kotlin-tour-intermediate-lambdas-receiver.html) # Lambda expressions with receiver In this chapter, you'll learn how to use receivers with another type of function, lambda expressions, and how they can help you create a domain-specific language. ## Lambda expressions with receiver In the beginner tour, you learned how to use [lambda expressions](kotlin-tour-functions.html#lambda-expressions). Lambda expressions can also have a receiver. In this case, lambda expressions can access any member functions or properties of the receiver without having to explicitly specify the receiver each time. Without these additional references, your code is easier to read and maintain. Tip: Lambda expressions with receiver are also known as function literals with receiver. The syntax for a lambda expression with receiver is different when you define the function type. First, write the receiver that you want to extend. Next, put a `.` and then complete the rest of your function type definition. For example: ```KOTLIN MutableList.() -> Unit ``` This function type has: * `MutableList` as the receiver. * No function parameters within the parentheses `()`. * No return value: `Unit`. Consider this example that draws shapes on a canvas: ```KOTLIN class Canvas { fun drawCircle() = println("🟠 Drawing a circle") fun drawSquare() = println("🟥 Drawing a square") } // Lambda expression with receiver definition fun render(block: Canvas.() -> Unit): Canvas { val canvas = Canvas() // Use the lambda expression with receiver canvas.block() return canvas } fun main() { render { drawCircle() // 🟠 Drawing a circle drawSquare() // 🟥 Drawing a square } } ``` In this example: * The `Canvas` class has two functions that simulate drawing a circle or a square. * The `render()` function takes a `block` parameter and returns an instance of the `Canvas` class. * The `block` parameter is a lambda expression with receiver, where the `Canvas` class is the receiver. * The `render()` function creates an instance of the `Canvas` class and calls the `block()` lambda expression on the `canvas` instance, using it as the receiver. * The `main()` function calls the `render()` function with a lambda expression, which is passed to the `block` parameter. * Inside the lambda passed to the `render()` function, the program calls the `drawCircle()` and `drawSquare()` functions on an instance of the `Canvas` class. Because the `drawCircle()` and `drawSquare()` functions are called in the lambda expression with receiver, they can be called directly as if they are inside the `Canvas` class. Lambda expressions with receiver are helpful when you want to create a domain-specific language (DSL). Since you have access to the receiver's member functions and properties without explicitly referencing the receiver, your code becomes leaner. To demonstrate this, consider an example that configures items in a menu. Let's begin with a `MenuItem` class and a `Menu` class that contains a function to add items to the menu called `item()`, as well as a list of all menu items `items`: ```KOTLIN class MenuItem(val name: String) class Menu(val name: String) { val items = mutableListOf() fun item(name: String) { items.add(MenuItem(name)) } } ``` Let's use a lambda expression with receiver passed as a function parameter (`init`) to the `menu()` function that builds a menu as a starting point: ```KOTLIN fun menu(name: String, init: Menu.() -> Unit): Menu { // Creates an instance of the Menu class val menu = Menu(name) // Calls the lambda expression with receiver init() on the class instance menu.init() return menu } ``` Now you can use the DSL to configure a menu and create a `printMenu()` function to print the menu structure to the console: ```KOTLIN class MenuItem(val name: String) class Menu(val name: String) { val items = mutableListOf() fun item(name: String) { items.add(MenuItem(name)) } } fun menu(name: String, init: Menu.() -> Unit): Menu { val menu = Menu(name) menu.init() return menu } //sampleStart fun printMenu(menu: Menu) { println("Menu: ${menu.name}") menu.items.forEach { println(" Item: ${it.name}") } } // Use the DSL fun main() { // Create the menu val mainMenu = menu("Main Menu") { // Add items to the menu item("Home") item("Settings") item("Exit") } // Print the menu printMenu(mainMenu) // Menu: Main Menu // Item: Home // Item: Settings // Item: Exit } //sampleEnd ``` As you can see, using a lambda expression with receiver greatly simplifies the code needed to create your menu. Lambda expressions are not only useful for setup and creation but also for configuration. They are commonly used in building DSLs for APIs, UI frameworks, and configuration builders to produce streamlined code, allowing you to focus more easily on the underlying code structure and logic. Kotlin's ecosystem has many examples of this design pattern, such as in the [buildList()](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.collections/build-list.html) and [buildString()](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.text/build-string.html) functions from the standard library. Tip: Lambda expressions with receivers can be combined with type-safe builders in Kotlin to make DSLs that detect any problems with types at compile time rather than at runtime. To learn more, see [Type-safe builders](type-safe-builders.html). ## Practice ### Exercise 1 You have a `fetchData()` function that accepts a lambda expression with receiver. Update the lambda expression to use the `append()` function so that the output of your code is: `Data received - Processed`. ```KOTLIN fun fetchData(callback: StringBuilder.() -> Unit) { val builder = StringBuilder("Data received") builder.callback() } fun main() { fetchData { // Write your code here // Data received - Processed } } ``` ```KOTLIN fun fetchData(callback: StringBuilder.() -> Unit) { val builder = StringBuilder("Data received") builder.callback() } fun main() { fetchData { append(" - Processed") println(this.toString()) // Data received - Processed } } ``` ### Exercise 2 You have a `Button` class and `ButtonEvent` and `Position` data classes. Write some code that triggers the `onEvent()` member function of the `Button` class to trigger a double-click event. Your code should print `"Double click!"`. ```KOTLIN class Button { fun onEvent(action: ButtonEvent.() -> Unit) { // Simulate a double-click event (not a right-click) val event = ButtonEvent(isRightClick = false, amount = 2, position = Position(100, 200)) event.action() // Trigger the event callback } } data class ButtonEvent( val isRightClick: Boolean, val amount: Int, val position: Position ) data class Position( val x: Int, val y: Int ) fun main() { val button = Button() button.onEvent { // Write your code here // Double click! } } ``` ```KOTLIN class Button { fun onEvent(action: ButtonEvent.() -> Unit) { // Simulate a double-click event (not a right-click) val event = ButtonEvent(isRightClick = false, amount = 2, position = Position(100, 200)) event.action() // Trigger the event callback } } data class ButtonEvent( val isRightClick: Boolean, val amount: Int, val position: Position ) data class Position( val x: Int, val y: Int ) fun main() { val button = Button() button.onEvent { if (!isRightClick && amount == 2) { println("Double click!") // Double click! } } } ``` ### Exercise 3 Write a function that creates a copy of a list of integers where every element is incremented by 1. Use the provided function skeleton that extends `List` with an `incremented` function. ```KOTLIN fun List.incremented(): List { val originalList = this return buildList { // Write your code here } } fun main() { val originalList = listOf(1, 2, 3) val newList = originalList.incremented() println(newList) // [2, 3, 4] } ``` ```KOTLIN fun List.incremented(): List { val originalList = this return buildList { for (n in originalList) add(n + 1) } } fun main() { val originalList = listOf(1, 2, 3) val newList = originalList.incremented() println(newList) // [2, 3, 4] } ``` ## See also * [Previous step](kotlin-tour-intermediate-scope-functions.html) * [Next step](kotlin-tour-intermediate-classes-interfaces.html) # Classes and interfaces In the beginner tour, you learned how to use classes and data classes to store data and maintain a collection of characteristics that can be shared in your code. Eventually, you will want to create a hierarchy to efficiently share code within your projects. This chapter explains the options Kotlin provides for sharing code and how they can make your code safer and easier to maintain. ## Class inheritance In a previous chapter, we covered how you can use extension functions to extend classes without modifying the original source code. But what if you are working on something complex where sharing code between classes would be useful? In such cases, you can use class inheritance. By default, classes in Kotlin can't be inherited. Kotlin is designed this way to prevent unintended inheritance and make your classes easier to maintain. Kotlin classes only support single inheritance, meaning it is only possible to inherit from one class at a time. This class is called the parent. The parent of a class inherits from another class (the grandparent), forming a hierarchy. At the top of Kotlin's class hierarchy is the common parent class: `Any`. All classes ultimately inherit from the `Any` class: ![An example of the class hierarchy with Any type](images/any-type-class.png) The `Any` class provides the `toString()` function as a member function automatically. Therefore, you can use this inherited function in any of your classes. For example: ```KOTLIN class Car(val make: String, val model: String, val numberOfDoors: Int) fun main() { //sampleStart val car1 = Car("Toyota", "Corolla", 4) // Uses the .toString() function via string templates to print class properties println("Car1: make=${car1.make}, model=${car1.model}, numberOfDoors=${car1.numberOfDoors}") // Car1: make=Toyota, model=Corolla, numberOfDoors=4 //sampleEnd } ``` If you want to use inheritance to share some code between classes, first consider using abstract classes. ### Abstract classes Abstract classes can be inherited by default. The purpose of abstract classes is to provide members that other classes inherit or implement. As a result, they have a constructor, but you can't create instances from them. Within the child class, you define the behavior of the parent's properties and functions with the `override` keyword. In this way, you can say that the child class "overrides" the members of the parent class. Tip: When you define the behavior of an inherited function or property, we call that an implementation. Abstract classes can contain both functions and properties with implementation as well as functions and properties without implementation, known as abstract functions and properties. To create an abstract class, use the `abstract` keyword: ```KOTLIN abstract class Animal ``` To declare a function or a property without an implementation, you also use the `abstract` keyword: ```KOTLIN abstract fun makeSound() abstract val sound: String ``` For example, let's say that you want to create an abstract class called `Product` that you can create child classes from to define different product categories: ```KOTLIN abstract class Product(val name: String, var price: Double) { // Abstract property for the product category abstract val category: String // A function that can be shared by all products fun productInfo(): String { return "Product: $name, Category: $category, Price: $price" } } ``` In the abstract class: * The constructor has two parameters for the product's `name` and `price`. * There is an abstract property that contains the product category as a string. * There is a function that prints information about the product. Let's create a child class for electronics. Before you define an implementation for the `category` property in the child class, you must use the `override` keyword: ```KOTLIN class Electronic(name: String, price: Double, val warranty: Int) : Product(name, price) { override val category = "Electronic" } ``` The `Electronic` class: * Inherits from the `Product` abstract class. * Has an additional parameter in the constructor: `warranty`, which is specific to electronics. * Overrides the `category` property to contain the string `"Electronic"`. Now, you can use these classes like this: ```KOTLIN abstract class Product(val name: String, var price: Double) { // Abstract property for the product category abstract val category: String // A function that can be shared by all products fun productInfo(): String { return "Product: $name, Category: $category, Price: $price" } } class Electronic(name: String, price: Double, val warranty: Int) : Product(name, price) { override val category = "Electronic" } //sampleStart fun main() { // Creates an instance of the Electronic class val laptop = Electronic(name = "Laptop", price = 1000.0, warranty = 2) println(laptop.productInfo()) // Product: Laptop, Category: Electronic, Price: 1000.0 } //sampleEnd ``` Although abstract classes are great for sharing code in this way, they are restricted because classes in Kotlin only support single inheritance. If you need to inherit from multiple sources, consider using interfaces. ## Interfaces Interfaces are similar to classes, but they have some differences: * You can't create an instance of an interface. They don't have a constructor or header. * Their functions and properties are implicitly inheritable by default. In Kotlin, we say that they are "open." * You don't need to mark their functions as `abstract` if you don't give them an implementation. Similar to abstract classes, you use interfaces to define a set of functions and properties that classes can inherit and implement later. This approach helps you focus on the abstraction described by the interface, rather than the specific implementation details. Using interfaces makes your code: * More modular, as it isolates different parts, allowing them to evolve independently. * Easier to understand by grouping related functions into a cohesive set. * Easier to test, as you can quickly swap an implementation with a mock for testing. To declare an interface, use the `interface` keyword: ```KOTLIN interface PaymentMethod ``` ### Interface implementation Interfaces support multiple inheritance so a class can implement multiple interfaces at once. First, let's consider the scenario where a class implements one interface. To create a class that implements an interface, add a colon after your class header, followed by the interface name that you want to implement. You don't use parentheses `()` after the interface name because interfaces don't have a constructor: ```KOTLIN class CreditCardPayment : PaymentMethod ``` For example: ```KOTLIN interface PaymentMethod { // Functions are inheritable by default fun initiatePayment(amount: Double): String } class CreditCardPayment(val cardNumber: String, val cardHolderName: String, val expiryDate: String) : PaymentMethod { override fun initiatePayment(amount: Double): String { // Simulate processing payment with credit card return "Payment of $$amount initiated using Credit Card ending in ${cardNumber.takeLast(4)}." } } fun main() { val paymentMethod = CreditCardPayment("1234 5678 9012 3456", "John Doe", "12/25") println(paymentMethod.initiatePayment(100.0)) // Payment of $100.0 initiated using Credit Card ending in 3456. } ``` In the example: * `PaymentMethod` is an interface that has an `initiatePayment()` function without an implementation. * `CreditCardPayment` is a class that implements the `PaymentMethod` interface. * The `CreditCardPayment` class overrides the inherited `initiatePayment()` function. * `paymentMethod` is an instance of the `CreditCardPayment` class. * The overridden `initiatePayment()` function is called on the `paymentMethod` instance with a parameter of `100.0`. To create a class that implements multiple interfaces, add a colon after your class header followed by the name of the interfaces that you want to implement separated by a comma: ```KOTLIN class CreditCardPayment : PaymentMethod, PaymentType ``` For example: ```KOTLIN interface PaymentMethod { fun initiatePayment(amount: Double): String } interface PaymentType { val paymentType: String } class CreditCardPayment(val cardNumber: String, val cardHolderName: String, val expiryDate: String) : PaymentMethod, PaymentType { override fun initiatePayment(amount: Double): String { // Simulate processing payment with credit card return "Payment of $$amount initiated using Credit Card ending in ${cardNumber.takeLast(4)}." } override val paymentType: String = "Credit Card" } fun main() { val paymentMethod = CreditCardPayment("1234 5678 9012 3456", "John Doe", "12/25") println(paymentMethod.initiatePayment(100.0)) // Payment of $100.0 initiated using Credit Card ending in 3456. println("Payment is by ${paymentMethod.paymentType}") // Payment is by Credit Card } ``` In the example: * `PaymentMethod` is an interface that has the `initiatePayment()` function without an implementation. * `PaymentType` is an interface that has the `paymentType` property that isn't initialized. * `CreditCardPayment` is a class that implements the `PaymentMethod` and `PaymentType` interfaces. * The `CreditCardPayment` class overrides the inherited `initiatePayment()` function and the `paymentType` property. * `paymentMethod` is an instance of the `CreditCardPayment` class. * The overridden `initiatePayment()` function is called on the `paymentMethod` instance with a parameter of `100.0`. * The overridden `paymentType` property is accessed on the `paymentMethod` instance. For more information about interfaces and interface inheritance, see [Interfaces](interfaces.html). ## Delegation Interfaces are useful, but if your interface contains many functions, its child classes can end up with a lot of boilerplate code. If you only want to override a small part of a class's behavior, you need to repeat yourself a lot. Tip: Boilerplate code is a chunk of code that is reused with little or no alteration in multiple parts of a software project. For example, let's say that you have an interface called `DrawingTool` that contains a number of functions and one property called `color`: ```KOTLIN interface DrawingTool { val color: String fun draw(shape: String) fun erase(area: String) fun getToolInfo(): String } ``` You create a class called `PenTool` which implements the `DrawingTool` interface and provides implementations for all of its members: ```KOTLIN class PenTool : DrawingTool { override val color: String = "black" override fun draw(shape: String) { println("Drawing $shape using a pen in $color") } override fun erase(area: String) { println("Erasing $area with pen tool") } override fun getToolInfo(): String { return "PenTool(color=$color)" } } ``` You want to create a class like `PenTool` with the same behavior but a different `color` value. One approach is to create a new class that expects an object implementing the `DrawingTool` interface as a parameter, like a `PenTool` class instance. Then, inside the class, you can override the `color` property. But in this scenario, you need to add implementations for each member of the `DrawingTool` interface: ```KOTLIN interface DrawingTool { val color: String fun draw(shape: String) fun erase(area: String) fun getToolInfo(): String } class PenTool : DrawingTool { override val color: String = "black" override fun draw(shape: String) { println("Drawing $shape using a pen in $color") } override fun erase(area: String) { println("Erasing $area with pen tool") } override fun getToolInfo(): String { return "PenTool(color=$color)" } } //sampleStart class CanvasSession(val tool: DrawingTool) : DrawingTool { override val color: String = "blue" override fun draw(shape: String) { tool.draw(shape) } override fun erase(area: String) { tool.erase(area) } override fun getToolInfo(): String { return tool.getToolInfo() } } //sampleEnd fun main() { val pen = PenTool() val session = CanvasSession(pen) println("Pen color: ${pen.color}") // Pen color: black println("Session color: ${session.color}") // Session color: blue session.draw("circle") // Drawing circle with pen in black session.erase("top-left corner") // Erasing top-left corner with pen tool println(session.getToolInfo()) // PenTool(color=black) } ``` You can see that if you have a large number of member functions in the `DrawingTool` interface, the amount of boilerplate code in the `CanvasSession` class can be large. However, there is an alternative. In Kotlin, you can delegate the interface implementation to a class instance using the `by` keyword. For example: ```KOTLIN class CanvasSession(val tool: DrawingTool) : DrawingTool by tool ``` Here, `tool` is the name of the `PenTool` class instance where the implementations of member functions are delegated to. Now you don't have to add implementations for the member functions in the `CanvasSession` class. The compiler does this for you automatically from the `PenTool` class. This saves you from having to write a lot of boilerplate code. Instead, you add code only for the behavior you want to change for your child class. For example, if you want to change the value of the `color` property: ```KOTLIN interface DrawingTool { val color: String fun draw(shape: String) fun erase(area: String) fun getToolInfo(): String } class PenTool : DrawingTool { override val color: String = "black" override fun draw(shape: String) { println("Drawing $shape using a pen in $color") } override fun erase(area: String) { println("Erasing $area with pen tool") } override fun getToolInfo(): String { return "PenTool(color=$color)" } } //sampleStart class CanvasSession(val tool: DrawingTool) : DrawingTool by tool { // No boilerplate code! override val color: String = "blue" } //sampleEnd fun main() { val pen = PenTool() val session = CanvasSession(pen) println("Pen color: ${pen.color}") // Pen color: black println("Session color: ${session.color}") // Session color: blue session.draw("circle") // Drawing circle with pen in black session.erase("top-left corner") // Erasing top-left corner with pen tool println(session.getToolInfo()) // PenTool(color=black) } ``` If you want to, you can also override the behavior of an inherited member function in the `CanvasSession` class, but now you don't have to add new lines of code for every inherited member function. For more information, see [Delegation](delegation.html). ## Practice ### Exercise 1 Imagine you're working on a smart home system. A smart home typically has different types of devices that all have some basic features but also unique behaviors. In the code sample below, complete the `abstract` class called `SmartDevice` so that the child class `SmartLight` can compile successfully. Then, create another child class called `SmartThermostat` that inherits from the `SmartDevice` class and implements `turnOn()` and `turnOff()` functions that return print statements describing which thermostat is heating or turned off. Finally, add another function called `adjustTemperature()` that accepts a temperature measurement as an input and prints: `$name thermostat set to $temperature°C.` Hint : In the : `SmartDevice` : class, add the : `turnOn()` : and : `turnOff()` : functions so that you can override their behavior later in the : `SmartThermostat` : class. ```KOTLIN abstract class // Write your code here class SmartLight(name: String) : SmartDevice(name) { override fun turnOn() { println("$name is now ON.") } override fun turnOff() { println("$name is now OFF.") } fun adjustBrightness(level: Int) { println("Adjusting $name brightness to $level%.") } } class SmartThermostat // Write your code here fun main() { val livingRoomLight = SmartLight("Living Room Light") val bedroomThermostat = SmartThermostat("Bedroom Thermostat") livingRoomLight.turnOn() // Living Room Light is now ON. livingRoomLight.adjustBrightness(10) // Adjusting Living Room Light brightness to 10%. livingRoomLight.turnOff() // Living Room Light is now OFF. bedroomThermostat.turnOn() // Bedroom Thermostat thermostat is now heating. bedroomThermostat.adjustTemperature(5) // Bedroom Thermostat thermostat set to 5°C. bedroomThermostat.turnOff() // Bedroom Thermostat thermostat is now off. } ``` ```KOTLIN abstract class SmartDevice(val name: String) { abstract fun turnOn() abstract fun turnOff() } class SmartLight(name: String) : SmartDevice(name) { override fun turnOn() { println("$name is now ON.") } override fun turnOff() { println("$name is now OFF.") } fun adjustBrightness(level: Int) { println("Adjusting $name brightness to $level%.") } } class SmartThermostat(name: String) : SmartDevice(name) { override fun turnOn() { println("$name thermostat is now heating.") } override fun turnOff() { println("$name thermostat is now off.") } fun adjustTemperature(temperature: Int) { println("$name thermostat set to $temperature°C.") } } fun main() { val livingRoomLight = SmartLight("Living Room Light") val bedroomThermostat = SmartThermostat("Bedroom Thermostat") livingRoomLight.turnOn() // Living Room Light is now ON. livingRoomLight.adjustBrightness(10) // Adjusting Living Room Light brightness to 10%. livingRoomLight.turnOff() // Living Room Light is now OFF. bedroomThermostat.turnOn() // Bedroom Thermostat thermostat is now heating. bedroomThermostat.adjustTemperature(5) // Bedroom Thermostat thermostat set to 5°C. bedroomThermostat.turnOff() // Bedroom Thermostat thermostat is now off. } ``` ### Exercise 2 Create an interface called `Media` that you can use to implement specific media classes like `Audio`, `Video`, or `Podcast`. Your interface must include: * A property called `title` to represent the title of the media. * A function called `play()` to play the media. Then, create a class called `Audio` that implements the `Media` interface. The `Audio` class must use the `title` property in its constructor as well as have an additional property called `composer` that has `String` type. In the class, implement the `play()` function to print the following: `"Playing audio: $title, composed by $composer"`. Hint : You can use the : `override` : keyword in class headers to implement a property from an interface in the constructor. ```KOTLIN interface // Write your code here class // Write your code here fun main() { val audio = Audio("Symphony No. 5", "Beethoven") audio.play() // Playing audio: Symphony No. 5, composed by Beethoven } ``` ```KOTLIN interface Media { val title: String fun play() } class Audio(override val title: String, val composer: String) : Media { override fun play() { println("Playing audio: $title, composed by $composer") } } fun main() { val audio = Audio("Symphony No. 5", "Beethoven") audio.play() // Playing audio: Symphony No. 5, composed by Beethoven } ``` ### Exercise 3 You're building a payment processing system for an e-commerce application. Each payment method needs to be able to authorize a payment and process a transaction. Some payments also need to be able to process refunds. 1. In the `Refundable` interface, add a function called `refund()` to process refunds. 2. In the `PaymentMethod` abstract class: * Add a function called `authorize()` that takes an amount and prints a message containing the amount. * Add an abstract function called `processPayment()` that also takes an amount. 3. Create a class called `CreditCard` that implements the `Refundable` interface and `PaymentMethod` abstract class. In this class, add implementations for the `refund()` and `processPayment()` functions so that they print the following statements: * `"Refunding $amount to the credit card."` * `"Processing credit card payment of $amount."` ```KOTLIN interface Refundable { // Write your code here } abstract class PaymentMethod(val name: String) { // Write your code here } class CreditCard // Write your code here fun main() { val visa = CreditCard("Visa") visa.authorize(100.0) // Authorizing payment of $100.0. visa.processPayment(100.0) // Processing credit card payment of $100.0. visa.refund(50.0) // Refunding $50.0 to the credit card. } ``` ```KOTLIN interface Refundable { fun refund(amount: Double) } abstract class PaymentMethod(val name: String) { fun authorize(amount: Double) { println("Authorizing payment of $$amount.") } abstract fun processPayment(amount: Double) } class CreditCard(name: String) : PaymentMethod(name), Refundable { override fun processPayment(amount: Double) { println("Processing credit card payment of $$amount.") } override fun refund(amount: Double) { println("Refunding $$amount to the credit card.") } } fun main() { val visa = CreditCard("Visa") visa.authorize(100.0) // Authorizing payment of $100.0. visa.processPayment(100.0) // Processing credit card payment of $100.0. visa.refund(50.0) // Refunding $50.0 to the credit card. } ``` ### Exercise 4 You have a simple messaging app that has some basic functionality, but you want to add some functionality for smart messages without significantly duplicating your code. In the code below, define a class called `SmartMessenger` that inherits from the `Messenger` interface but delegates the implementation to an instance of the `BasicMessenger` class. In the `SmartMessenger` class, override the `sendMessage()` function to send smart messages. The function must accept a `message` as an input and return a printed statement: `"Sending a smart message: $message"`. In addition, call the `sendMessage()` function from the `BasicMessenger` class and prefix the message with `[smart]`. Note: You don't need to rewrite the `receiveMessage()` function in the `SmartMessenger` class. ```KOTLIN interface Messenger { fun sendMessage(message: String) fun receiveMessage(): String } class BasicMessenger : Messenger { override fun sendMessage(message: String) { println("Sending message: $message") } override fun receiveMessage(): String { return "You've got a new message!" } } class SmartMessenger // Write your code here fun main() { val basicMessenger = BasicMessenger() val smartMessenger = SmartMessenger(basicMessenger) basicMessenger.sendMessage("Hello!") // Sending message: Hello! println(smartMessenger.receiveMessage()) // You've got a new message! smartMessenger.sendMessage("Hello from SmartMessenger!") // Sending a smart message: Hello from SmartMessenger! // Sending message: [smart] Hello from SmartMessenger! } ``` ```KOTLIN interface Messenger { fun sendMessage(message: String) fun receiveMessage(): String } class BasicMessenger : Messenger { override fun sendMessage(message: String) { println("Sending message: $message") } override fun receiveMessage(): String { return "You've got a new message!" } } class SmartMessenger(val basicMessenger: BasicMessenger) : Messenger by basicMessenger { override fun sendMessage(message: String) { println("Sending a smart message: $message") basicMessenger.sendMessage("[smart] $message") } } fun main() { val basicMessenger = BasicMessenger() val smartMessenger = SmartMessenger(basicMessenger) basicMessenger.sendMessage("Hello!") // Sending message: Hello! println(smartMessenger.receiveMessage()) // You've got a new message! smartMessenger.sendMessage("Hello from SmartMessenger!") // Sending a smart message: Hello from SmartMessenger! // Sending message: [smart] Hello from SmartMessenger! } ``` ## See also * [Previous step](kotlin-tour-intermediate-lambdas-receiver.html) * [Next step](kotlin-tour-intermediate-objects.html) # Objects In this chapter, you'll expand your understanding of classes by exploring object declarations. This knowledge will help you efficiently manage behavior across your projects. ## Object declarations In Kotlin, you can use object declarations to declare a class with a single instance. In a sense, you declare the class and create the single instance at the same time. Object declarations are useful when you want to create a class to use as a single reference point for your program or to coordinate behavior across a system. Tip: A class that has only one instance that is easily accessible is called a singleton. Objects in Kotlin are lazy, meaning they are created only when accessed. Kotlin also ensures that all objects are created in a thread-safe manner so that you don't have to check this manually. To create an object declaration, use the `object` keyword: ```KOTLIN object DoAuth {} ``` Following the name of your `object`, add any properties or member functions within the object body defined by curly braces `{}`. Note: Objects can't have constructors, so they don't have headers like classes. For example, let's say that you wanted to create an object called `DoAuth` that is responsible for authentication: ```KOTLIN object DoAuth { fun takeParams(username: String, password: String) { println("input Auth parameters = $username:$password") } } fun main(){ // The object is created when the takeParams() function is called DoAuth.takeParams("coding_ninja", "N1njaC0ding!") // input Auth parameters = coding_ninja:N1njaC0ding! } ``` The object has a member function called `takeParams` that accepts `username` and `password` variables as parameters and prints a string to the console. The `DoAuth` object is only created when the function is called for the first time. Note: Objects can inherit from classes and interfaces. For example: ```KOTLIN interface Auth { fun takeParams(username: String, password: String) } object DoAuth : Auth { override fun takeParams(username: String, password: String) { println("input Auth parameters = $username:$password") } } ``` ### Data objects To make it easier to print the contents of an object declaration, Kotlin has data objects. Similar to data classes, which you learned about in the beginner tour, data objects automatically come with additional member functions: `toString()` and `equals()`. Tip: Unlike data classes, data objects do not come automatically with the `copy()` member function because they only have a single instance that can't be copied. To create a data object, use the same syntax as for object declarations but prefix it with the `data` keyword: ```KOTLIN data object AppConfig {} ``` For example: ```KOTLIN data object AppConfig { var appName: String = "My Application" var version: String = "1.0.0" } fun main() { println(AppConfig) // AppConfig println(AppConfig.appName) // My Application } ``` For more information about data objects, see [Data objects](object-declarations.html#data-objects). ### Companion objects In Kotlin, a class can have an object: a companion object. You can only have one companion object per class. A companion object is created only when its class is referenced for the first time. Any properties or functions declared inside a companion object are shared across all class instances. To create a companion object within a class, use the same syntax for an object declaration but prefix it with the `companion` keyword: ```KOTLIN companion object Bonger {} ``` Note: A companion object doesn't have to have a name. If you don't define one, the default is `Companion`. To access any properties or functions of the companion object, reference the class name. For example: ```KOTLIN class BigBen { companion object Bonger { fun getBongs(nTimes: Int) { repeat(nTimes) { print("BONG ") } } } } fun main() { // Companion object is created when the class is referenced for the // first time. BigBen.getBongs(12) // BONG BONG BONG BONG BONG BONG BONG BONG BONG BONG BONG BONG } ``` This example creates a class called `BigBen` that contains a companion object called `Bonger`. The companion object has a member function called `getBongs()` that accepts an integer and prints `"BONG"` to the console the same number of times as the integer. In the `main()` function, the `getBongs()` function is called by referring to the class name. The companion object is created at this point. The `getBongs()` function is called with parameter `12`. For more information, see [Companion objects](object-declarations.html#companion-objects). ## Practice ### Exercise 1 You run a coffee shop and have a system for tracking customer orders. Consider the code below and complete the declaration of the second data object so that the following code in the `main()` function runs successfully: ```KOTLIN interface Order { val orderId: String val customerName: String val orderTotal: Double } data object OrderOne: Order { override val orderId = "001" override val customerName = "Alice" override val orderTotal = 15.50 } data object // Write your code here fun main() { // Print the name of each data object println("Order name: $OrderOne") // Order name: OrderOne println("Order name: $OrderTwo") // Order name: OrderTwo // Check if the orders are identical println("Are the two orders identical? ${OrderOne == OrderTwo}") // Are the two orders identical? false if (OrderOne == OrderTwo) { println("The orders are identical.") } else { println("The orders are unique.") // The orders are unique. } println("Do the orders have the same customer name? ${OrderOne.customerName == OrderTwo.customerName}") // Do the orders have the same customer name? false } ``` ```KOTLIN interface Order { val orderId: String val customerName: String val orderTotal: Double } data object OrderOne: Order { override val orderId = "001" override val customerName = "Alice" override val orderTotal = 15.50 } data object OrderTwo: Order { override val orderId = "002" override val customerName = "Bob" override val orderTotal = 12.75 } fun main() { // Print the name of each data object println("Order name: $OrderOne") // Order name: OrderOne println("Order name: $OrderTwo") // Order name: OrderTwo // Check if the orders are identical println("Are the two orders identical? ${OrderOne == OrderTwo}") // Are the two orders identical? false if (OrderOne == OrderTwo) { println("The orders are identical.") } else { println("The orders are unique.") // The orders are unique. } println("Do the orders have the same customer name? ${OrderOne.customerName == OrderTwo.customerName}") // Do the orders have the same customer name? false } ``` ### Exercise 2 Create an object declaration that inherits from the `Vehicle` interface to create a unique vehicle type: `FlyingSkateboard`. Implement the `name` property and the `move()` function in your object so that the following code in the `main()` function runs successfully: ```KOTLIN interface Vehicle { val name: String fun move(): String } object // Write your code here fun main() { println("${FlyingSkateboard.name}: ${FlyingSkateboard.move()}") // Flying Skateboard: Glides through the air with a hover engine println("${FlyingSkateboard.name}: ${FlyingSkateboard.fly()}") // Flying Skateboard: Woooooooo } ``` ```KOTLIN interface Vehicle { val name: String fun move(): String } object FlyingSkateboard : Vehicle { override val name = "Flying Skateboard" override fun move() = "Glides through the air with a hover engine" fun fly(): String = "Woooooooo" } fun main() { println("${FlyingSkateboard.name}: ${FlyingSkateboard.move()}") // Flying Skateboard: Glides through the air with a hover engine println("${FlyingSkateboard.name}: ${FlyingSkateboard.fly()}") // Flying Skateboard: Woooooooo } ``` ### Exercise 3 You are building a user registration module for an app. You want to keep email validation associated with the `User` class but don't want to create an unnecessary `User` instance if the email address is invalid. For this exercise, consider an email address valid if it contains both `@` and `.`. Complete the data class so that the following code in the `main()` function runs successfully: Hint : Add an email validation function in a companion object for the `User` class so that you can call the function directly on `User`. ```KOTLIN data class User(val name: String, val email: String) { // Write your code here } fun main() { val candidates = listOf( Pair("Alice", "alice@example.com"), Pair("Bob", "bob2example-com") ) for ((name, email) in candidates) { if (User.isValidEmail(email)) { val user = User(name, email) println("Registered: ${user.name}, ${user.email}") // Registered: Alice, alice@example.com } else { println("Error: '${email}' is not valid. The email should contain '@' and '.'") // Error: 'bob2example-com' is not valid. The email should contain '@' and '.' } } } ``` ```KOTLIN data class User(val name: String, val email: String) { companion object { fun isValidEmail(email: String): Boolean = email.contains('@') && email.contains('.') } } fun main() { val candidates = listOf( Pair("Alice", "alice@example.com"), Pair("Bob", "bob2example-com") ) for ((name, email) in candidates) { if (User.isValidEmail(email)) { val user = User(name, email) println("Registered: ${user.name}, ${user.email}") // Registered: Alice, alice@example.com } else { println("Error: '${email}' is not valid. The email should contain '@' and '.'") // Error: 'bob2example-com' is not valid. The email should contain '@' and '.' } } } ``` Tip: As an extension of this exercise, try using functions in companion objects as factory methods to construct instances of a class. For an example and more information about this pattern, see [Companion objects](object-declarations.html#companion-objects). ## See also * [Previous step](kotlin-tour-intermediate-classes-interfaces.html) * [Next step](kotlin-tour-intermediate-open-special-classes.html) # Open and special classes In this chapter, you'll learn about open classes, how they work with interfaces, and other special types of classes available in Kotlin. ## Open classes If you can't use interfaces or abstract classes, you can explicitly make a class inheritable by declaring it as open. To do this, use the `open` keyword before your class declaration: ```KOTLIN open class Vehicle(val make: String, val model: String) ``` To create a class that inherits from another, add a colon after your class header followed by a call to the constructor of the parent class that you want to inherit from. In this example, the `Car` class inherits from the `Vehicle` class: ```KOTLIN open class Vehicle(val make: String, val model: String) class Car(make: String, model: String, val numberOfDoors: Int) : Vehicle(make, model) fun main() { // Creates an instance of the Car class val car = Car("Toyota", "Corolla", 4) // Prints the details of the car println("Car Info: Make - ${car.make}, Model - ${car.model}, Number of doors - ${car.numberOfDoors}") // Car Info: Make - Toyota, Model - Corolla, Number of doors - 4 } ``` Just like when creating a normal class instance, if your class inherits from a parent class, then it must initialize all the parameters declared in the parent class header. So in the example, the `car` instance of the `Car` class initializes the parent class parameters: `make` and `model`. ### Overriding inherited behavior If you want to inherit from a class but change some of the behavior, you can override the inherited behavior. By default, it's not possible to override a member function or property of a parent class. Just like with abstract classes, you need to add special keywords. #### Member functions To allow a function in the parent class to be overridden, use the `open` keyword before its declaration in the parent class: ```KOTLIN open fun displayInfo() {} ``` To override an inherited member function, use the `override` keyword before the function declaration in the child class: ```KOTLIN override fun displayInfo() {} ``` For example: ```KOTLIN open class Vehicle(val make: String, val model: String) { open fun displayInfo() { println("Vehicle Info: Make - $make, Model - $model") } } class Car(make: String, model: String, val numberOfDoors: Int) : Vehicle(make, model) { override fun displayInfo() { println("Car Info: Make - $make, Model - $model, Number of Doors - $numberOfDoors") } } fun main() { val car1 = Car("Toyota", "Corolla", 4) val car2 = Car("Honda", "Civic", 2) // Uses the overridden displayInfo() function car1.displayInfo() // Car Info: Make - Toyota, Model - Corolla, Number of Doors - 4 car2.displayInfo() // Car Info: Make - Honda, Model - Civic, Number of Doors - 2 } ``` This example: * Creates two instances of the `Car` class that inherit from the `Vehicle` class: `car1` and `car2`. * Overrides the `displayInfo()` function in the `Car` class to also print the number of doors. * Calls the overridden `displayInfo()` function on `car1` and `car2` instances. #### Properties In Kotlin, it's not common practice to make a property inheritable by using the `open` keyword and overriding it later. Most of the time, you use an abstract class or an interface where properties are inheritable by default. Properties inside open classes are accessible by their child class. In general, it's better to access them directly rather than override them with a new property. For example, let's say that you have a property called `transmissionType` that you want to override later. The syntax for overriding properties is exactly the same as for overriding member functions. You can do this: ```KOTLIN open class Vehicle(val make: String, val model: String) { open val transmissionType: String = "Manual" } class Car(make: String, model: String, val numberOfDoors: Int) : Vehicle(make, model) { override val transmissionType: String = "Automatic" } ``` However, this is not good practice. Instead, you can add the property to the constructor of your inheritable class and declare its value when you create the `Car` child class: ```KOTLIN open class Vehicle(val make: String, val model: String, val transmissionType: String = "Manual") class Car(make: String, model: String, val numberOfDoors: Int) : Vehicle(make, model, "Automatic") ``` Accessing properties directly, instead of overriding them, leads to simpler and more readable code. By declaring properties once in the parent class and passing their values through the constructor, you eliminate the need for unnecessary overrides in child classes. For more information about class inheritance and overriding class behavior, see [Inheritance](inheritance.html). ### Open classes and interfaces You can create a class that inherits a class and implements multiple interfaces. In this case, you must declare the parent class first, after the colon, before listing the interfaces: ```KOTLIN // Define interfaces interface EcoFriendly { val emissionLevel: String } interface ElectricVehicle { val batteryCapacity: Double } // Parent class open class Vehicle(val make: String, val model: String) // Child class open class Car(make: String, model: String, val numberOfDoors: Int) : Vehicle(make, model) // New class that inherits from Car and implements two interfaces class ElectricCar( make: String, model: String, numberOfDoors: Int, val capacity: Double, val emission: String ) : Car(make, model, numberOfDoors), EcoFriendly, ElectricVehicle { override val batteryCapacity: Double = capacity override val emissionLevel: String = emission } ``` ## Special classes In addition to abstract, open, and data classes, Kotlin has special types of classes designed for various purposes, such as restricting specific behavior or reducing the performance impact of creating small objects. ### Sealed classes There may be times when you want to restrict inheritance. You can do this with sealed classes. Sealed classes are a special type of [abstract class](kotlin-tour-intermediate-classes-interfaces.html#abstract-classes). Once you declare that a class is sealed, you can only create child classes from it within the same package. It's not possible to inherit from the sealed class outside of this scope. Tip: A package is a collection of code with related classes and functions, typically within a directory. To learn more about packages in Kotlin, see [Packages and imports](packages.html). To create a sealed class, use the `sealed` keyword: ```KOTLIN sealed class Mammal ``` Sealed classes are particularly useful when combined with a `when` expression. By using a `when` expression, you can define the behavior for all possible child classes. For example: ```KOTLIN sealed class Mammal(val name: String) class Cat(val catName: String) : Mammal(catName) class Human(val humanName: String, val job: String) : Mammal(humanName) fun greetMammal(mammal: Mammal): String { when (mammal) { is Human -> return "Hello ${mammal.name}; You're working as a ${mammal.job}" is Cat -> return "Hello ${mammal.name}" } } fun main() { println(greetMammal(Cat("Snowy"))) // Hello Snowy } ``` In the example: * There is a sealed class called `Mammal` that has the `name` parameter in the constructor. * The `Cat` class inherits from the `Mammal` sealed class and uses the `catName` parameter in its own constructor as the `name` parameter from the `Mammal` class. * The `Human` class inherits from the `Mammal` sealed class and uses the `humanName` parameter in its own constructor as the `name` parameter from the `Mammal` class. It also has the `job` parameter in its constructor. * The `greetMammal()` function accepts an argument of `Mammal` type and returns a string. * Within the `greetMammal()` function body, there's a `when` expression that uses the [is operator](typecasts.html#is-and-is-operators) to check the type of `mammal` and decide which action to perform. * The `main()` function calls the `greetMammal()` function with an instance of the `Cat` class and `name` parameter called `Snowy`. Tip: This tour discusses the `is` operator in more detail in the [Null safety](kotlin-tour-intermediate-null-safety.html) chapter. For more information about sealed classes and their recommended use cases, see [Sealed classes and interfaces](sealed-classes.html). ### Enum classes Enum classes are useful when you want to represent a finite set of distinct values in a class. An enum class contains enum constants, which are themselves instances of the enum class. To create an enum class, use the `enum` keyword: ```KOTLIN enum class State ``` Let's say that you want to create an enum class that contains the different states of a process. Each enum constant must be separated by a comma `,`: ```KOTLIN enum class State { IDLE, RUNNING, FINISHED } ``` The `State` enum class has enum constants: `IDLE`, `RUNNING`, and `FINISHED`. To access an enum constant, use the class name followed by a `.` and the name of the enum constant: ```KOTLIN val state = State.RUNNING ``` You can use this enum class with a `when` expression to define the action to take depending on the value of the enum constant: ```KOTLIN enum class State { IDLE, RUNNING, FINISHED } fun main() { val state = State.RUNNING val message = when (state) { State.IDLE -> "It's idle" State.RUNNING -> "It's running" State.FINISHED -> "It's finished" } println(message) // It's running } ``` Enum classes can have properties and member functions just like normal classes. For example, let's say you're working with HTML and you want to create an enum class containing some colors. You want each color to have a property, let's call it `rgb`, that contains their RGB value as a hexadecimal. When creating the enum constants, you must initialize it with this property: ```KOTLIN enum class Color(val rgb: Int) { RED(0xFF0000), GREEN(0x00FF00), BLUE(0x0000FF), YELLOW(0xFFFF00) } ``` Note: Kotlin stores hexadecimals as integers, so the `rgb` property has the `Int` type, not the `String` type. To add a member function to this class, separate it from the enum constants with a semicolon `;`: ```KOTLIN enum class Color(val rgb: Int) { RED(0xFF0000), GREEN(0x00FF00), BLUE(0x0000FF), YELLOW(0xFFFF00); fun containsRed() = (this.rgb and 0xFF0000 != 0) } fun main() { val red = Color.RED // Calls containsRed() function on enum constant println(red.containsRed()) // true // Calls containsRed() function on enum constants via class names println(Color.BLUE.containsRed()) // false println(Color.YELLOW.containsRed()) // true } ``` In this example, the `containsRed()` member function accesses the value of the enum constant's `rgb` property using the `this` keyword and checks if the hexadecimal value contains `FF` as its first bits to return a boolean value. For more information, see [Enum classes](enum-classes.html). ### Inline value classes Sometimes in your code, you may want to create small objects from classes and use them only briefly. This approach can have a performance impact. Inline value classes are a special type of class that avoids this performance impact. However, they can only contain values. To create an inline value class, use the `value` keyword and the `@JvmInline` annotation: ```KOTLIN @JvmInline value class Email ``` Tip: The `@JvmInline` annotation instructs Kotlin to optimize the code when it is compiled. To learn more, see [Annotations](annotations.html). An inline value class must have a single property initialized in the class header. Let's say that you want to create a class that collects an email address: ```KOTLIN // The address property is initialized in the class header. @JvmInline value class Email(val address: String) fun sendEmail(email: Email) { println("Sending email to ${email.address}") } fun main() { val myEmail = Email("example@example.com") sendEmail(myEmail) // Sending email to example@example.com } ``` In the example: * `Email` is an inline value class that has one property in the class header: `address`. * The `sendEmail()` function accepts objects with type `Email` and prints a string to the standard output. * The `main()` function: * Creates an instance of the `Email` class called `myEmail`. * Calls the `sendEmail()` function on the `myEmail` object. By using an inline value class, you make the class inlined and can use it directly in your code without creating an object. This can significantly reduce memory footprint and improve your code's runtime performance. For more information about inline value classes, see [Inline value classes](inline-classes.html). ## Practice ### Exercise 1 You manage a delivery service and need a way to track the status of packages. Create a sealed class called `DeliveryStatus`, containing data classes to represent the following statuses: `Pending`, `InTransit`, `Delivered`, `Canceled`. Complete the `DeliveryStatus` class declaration so that the code in the `main()` function runs successfully: ```KOTLIN sealed class // Write your code here fun printDeliveryStatus(status: DeliveryStatus) { when (status) { is DeliveryStatus.Pending -> { println("The package is pending pickup from ${status.sender}.") } is DeliveryStatus.InTransit -> { println("The package is in transit and expected to arrive by ${status.estimatedDeliveryDate}.") } is DeliveryStatus.Delivered -> { println("The package was delivered to ${status.recipient} on ${status.deliveryDate}.") } is DeliveryStatus.Canceled -> { println("The delivery was canceled due to: ${status.reason}.") } } } fun main() { val status1: DeliveryStatus = DeliveryStatus.Pending("Alice") val status2: DeliveryStatus = DeliveryStatus.InTransit("2024-11-20") val status3: DeliveryStatus = DeliveryStatus.Delivered("2024-11-18", "Bob") val status4: DeliveryStatus = DeliveryStatus.Canceled("Address not found") printDeliveryStatus(status1) // The package is pending pickup from Alice. printDeliveryStatus(status2) // The package is in transit and expected to arrive by 2024-11-20. printDeliveryStatus(status3) // The package was delivered to Bob on 2024-11-18. printDeliveryStatus(status4) // The delivery was canceled due to: Address not found. } ``` ```KOTLIN sealed class DeliveryStatus { data class Pending(val sender: String) : DeliveryStatus() data class InTransit(val estimatedDeliveryDate: String) : DeliveryStatus() data class Delivered(val deliveryDate: String, val recipient: String) : DeliveryStatus() data class Canceled(val reason: String) : DeliveryStatus() } fun printDeliveryStatus(status: DeliveryStatus) { when (status) { is DeliveryStatus.Pending -> { println("The package is pending pickup from ${status.sender}.") } is DeliveryStatus.InTransit -> { println("The package is in transit and expected to arrive by ${status.estimatedDeliveryDate}.") } is DeliveryStatus.Delivered -> { println("The package was delivered to ${status.recipient} on ${status.deliveryDate}.") } is DeliveryStatus.Canceled -> { println("The delivery was canceled due to: ${status.reason}.") } } } fun main() { val status1: DeliveryStatus = DeliveryStatus.Pending("Alice") val status2: DeliveryStatus = DeliveryStatus.InTransit("2024-11-20") val status3: DeliveryStatus = DeliveryStatus.Delivered("2024-11-18", "Bob") val status4: DeliveryStatus = DeliveryStatus.Canceled("Address not found") printDeliveryStatus(status1) // The package is pending pickup from Alice. printDeliveryStatus(status2) // The package is in transit and expected to arrive by 2024-11-20. printDeliveryStatus(status3) // The package was delivered to Bob on 2024-11-18. printDeliveryStatus(status4) // The delivery was canceled due to: Address not found. } ``` ### Exercise 2 In your program, you want to be able to handle different statuses and types of errors. You have a sealed class to capture the different statuses which are declared in data classes or objects. Complete the code below by creating an enum class called `Problem` that represents the different problem types: `NETWORK`, `TIMEOUT`, and `UNKNOWN`. ```KOTLIN sealed class Status { data object Loading : Status() data class Error(val problem: Problem) : Status() { // Write your code here } data class OK(val data: List) : Status() } fun handleStatus(status: Status) { when (status) { is Status.Loading -> println("Loading...") is Status.OK -> println("Data received: ${status.data}") is Status.Error -> when (status.problem) { Status.Error.Problem.NETWORK -> println("Network issue") Status.Error.Problem.TIMEOUT -> println("Request timed out") Status.Error.Problem.UNKNOWN -> println("Unknown error occurred") } } } fun main() { val status1: Status = Status.Error(Status.Error.Problem.NETWORK) val status2: Status = Status.OK(listOf("Data1", "Data2")) handleStatus(status1) // Network issue handleStatus(status2) // Data received: [Data1, Data2] } ``` ```KOTLIN sealed class Status { data object Loading : Status() data class Error(val problem: Problem) : Status() { enum class Problem { NETWORK, TIMEOUT, UNKNOWN } } data class OK(val data: List) : Status() } fun handleStatus(status: Status) { when (status) { is Status.Loading -> println("Loading...") is Status.OK -> println("Data received: ${status.data}") is Status.Error -> when (status.problem) { Status.Error.Problem.NETWORK -> println("Network issue") Status.Error.Problem.TIMEOUT -> println("Request timed out") Status.Error.Problem.UNKNOWN -> println("Unknown error occurred") } } } fun main() { val status1: Status = Status.Error(Status.Error.Problem.NETWORK) val status2: Status = Status.OK(listOf("Data1", "Data2")) handleStatus(status1) // Network issue handleStatus(status2) // Data received: [Data1, Data2] } ``` ## See also * [Previous step](kotlin-tour-intermediate-objects.html) * [Next step](kotlin-tour-intermediate-properties.html) # Properties In the beginner tour, you learned how properties are used to declare characteristics of class instances and how to access them. This chapter digs deeper into how properties work in Kotlin and explores other ways that you can use them in your code. ## Backing fields In Kotlin, properties have default `get()` and `set()` functions, known as property accessors, which handle retrieving and modifying their values. While these default functions are not explicitly visible in the code, the compiler automatically generates them to manage property access behind the scenes. These accessors use a backing field to store the actual property value. Backing fields exist if either of the following is true: * You use the default `get()` or `set()` functions for the property. * You try to access the property value in code by using the `field` keyword. Tip: `get()` and `set()` functions are also called getters and setters. For example, this code has the `category` property that has no custom `get()` or `set()` functions and therefore uses the default implementations: ```KOTLIN class Contact(val id: Int, var email: String) { var category: String = "" } ``` Under the hood, this is equivalent to this pseudocode: ```KOTLIN class Contact(val id: Int, var email: String) { var category: String = "" get() = field set(value) { field = value } } ``` In this example: * The `get()` function retrieves the property value from the field: `""`. * The `set()` function accepts `value` as a parameter and assigns it to the field, where `value` is `""`. Access to the backing field is useful when you want to add extra logic in your `get()` or `set()` functions without causing an infinite loop. For example, you have a `Person` class with a `name` property: ```KOTLIN class Person { var name: String = "" } ``` You want to ensure that the first letter of the `name` property is capitalized, so you create a custom `set()` function that uses the [.replaceFirstChar()](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.text/replace-first-char.html) and [.uppercase()](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.text/uppercase-char.html) extension functions. However, if you refer to the property directly in your `set()` function, you create an infinite loop and see a `StackOverflowError` at runtime: ```KOTLIN class Person { var name: String = "" set(value) { // This causes a runtime error name = value.replaceFirstChar { firstChar -> firstChar.uppercase() } } } fun main() { val person = Person() person.name = "kodee" println(person.name) // Exception in thread "main" java.lang.StackOverflowError } ``` To fix this, you can use the backing field in your `set()` function instead by referencing it with the `field` keyword: ```KOTLIN class Person { var name: String = "" set(value) { field = value.replaceFirstChar { firstChar -> firstChar.uppercase() } } } fun main() { val person = Person() person.name = "kodee" println(person.name) // Kodee } ``` Backing fields are also useful when you want to add logging, send notifications when a property value changes, or use additional logic that compares the old and new property values. For more information, see [Backing fields](properties.html#backing-fields). ## Extension properties Just like extension functions, there are also extension properties. Extension properties allow you to add new properties to existing classes without modifying their source code. However, extension properties in Kotlin do not have backing fields. This means that you need to write the `get()` and `set()` functions yourself. Additionally, the lack of a backing field means that they can't hold any state. To declare an extension property, write the name of the class that you want to extend followed by a `.` and the name of your property. Just like with normal class properties, you need to declare a type for your property. For example: ```KOTLIN val String.lastChar: Char ``` Extension properties are most useful when you want a property to contain a computed value without using inheritance. You can think of extension properties working like a function with only one parameter: the receiver. For example, let's say that you have a data class called `Person` with two properties: `firstName` and `lastName`. ```KOTLIN data class Person(val firstName: String, val lastName: String) ``` You want to be able to access the person's full name without modifying the `Person` data class or inheriting from it. You can do this by creating an extension property with a custom `get()` function: ```KOTLIN data class Person(val firstName: String, val lastName: String) // Extension property to get the full name val Person.fullName: String get() = "$firstName $lastName" fun main() { val person = Person(firstName = "John", lastName = "Doe") // Use the extension property println(person.fullName) // John Doe } ``` Note: Extension properties can't override existing properties of a class. Just like with extension functions, the Kotlin standard library uses extension properties widely. For example, see the [lastIndex property](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.text/last-index.html) for a `CharSequence`. ## Delegated properties You already learned about delegation in the [Classes and interfaces](kotlin-tour-intermediate-classes-interfaces.html#delegation) chapter. You can also use delegation with properties to delegate their property accessors to another object. This is useful when you have more complex requirements for storing properties that a simple backing field can't handle, such as storing values in a database table, browser session, or map. Using delegated properties also reduces boilerplate code because the logic for getting and setting your properties is contained only in the object that you delegate to. The syntax is similar to using delegation with classes but operates on a different level. Declare your property, followed by the `by` keyword and the object you want to delegate to. For example: ```KOTLIN val displayName: String by Delegate ``` Here, the delegated property `displayName` refers to the `Delegate` object for its property accessors. Every object you delegate to must have a `getValue()` operator function, which Kotlin uses to retrieve the value of the delegated property. If the property is mutable, it must also have a `setValue()` operator function for Kotlin to set its value. By default, the `getValue()` and `setValue()` functions have the following construction: ```KOTLIN operator fun getValue(thisRef: Any?, property: KProperty<*>): String {} operator fun setValue(thisRef: Any?, property: KProperty<*>, value: String) {} ``` In these functions: * The `operator` keyword marks these functions as operator functions, enabling them to overload the `get()` and `set()` functions. * The `thisRef` parameter refers to the object containing the delegated property. By default, the type is set to `Any?`, but you may need to declare a more specific type. * The `property` parameter refers to the property whose value is accessed or changed. You can use this parameter to access information like the property's name or type. By default, the type is set to `KProperty<*>` but you can also use `Any?`. You don't need to worry about changing this in your code. The `getValue()` function has a return type of `String` by default, but you can adjust this if you want. The `setValue()` function has an additional parameter `value`, which is used to hold the new value that's assigned to the property. So, how does this look in practice? Suppose you want to have a computed property, like a user's display name, that is calculated only once because the operation is expensive and your application is performance-sensitive. You can use a delegated property to cache the display name so that it is only computed once but can be accessed anytime without performance impact. First, you need to create the object to delegate to. In this case, the object will be an instance of the `CachedStringDelegate` class: ```KOTLIN class CachedStringDelegate { var cachedValue: String? = null } ``` The `cachedValue` property contains the cached value. Within the `CachedStringDelegate` class, add the behavior that you want from the `get()` function of the delegated property to the `getValue()` operator function body: ```KOTLIN class CachedStringDelegate { var cachedValue: String? = null operator fun getValue(thisRef: Any?, property: Any?): String { if (cachedValue == null) { cachedValue = "Default Value" println("Computed and cached: $cachedValue") } else { println("Accessed from cache: $cachedValue") } return cachedValue ?: "Unknown" } } ``` The `getValue()` function checks whether the `cachedValue` property is `null`. If it is, the function assigns the `"Default value"` and prints a string for logging purposes. If the `cachedValue` property has already been computed, the property isn't `null`. In this case, another string is printed for logging purposes. Finally, the function uses the Elvis operator to return the cached value or `"Unknown"` if the value is `null`. Now you can delegate the property that you want to cache (`val displayName`) to an instance of the `CachedStringDelegate` class: ```KOTLIN class CachedStringDelegate { var cachedValue: String? = null operator fun getValue(thisRef: User, property: Any?): String { if (cachedValue == null) { cachedValue = "${thisRef.firstName} ${thisRef.lastName}" println("Computed and cached: $cachedValue") } else { println("Accessed from cache: $cachedValue") } return cachedValue ?: "Unknown" } } class User(val firstName: String, val lastName: String) { val displayName: String by CachedStringDelegate() } fun main() { val user = User("John", "Doe") // First access computes and caches the value println(user.displayName) // Computed and cached: John Doe // John Doe // Subsequent accesses retrieve the value from cache println(user.displayName) // Accessed from cache: John Doe // John Doe } ``` This example: * Creates a `User` class that has two properties in the header, `firstName`, and `lastName`, and one property in the class body, `displayName`. * Delegates the `displayName` property to an instance of the `CachedStringDelegate` class. * Creates an instance of the `User` class called `user`. * Prints the result of accessing the `displayName` property on the `user` instance. Note that in the `getValue()` function, the type for the `thisRef` parameter is narrowed from `Any?` type to the object type: `User`. This is so that the compiler can access the `firstName` and `lastName` properties of the `User` class. ### Standard delegates The Kotlin standard library provides some useful delegates for you so you don't have to always create yours from scratch. If you use one of these delegates, you don't need to define `getValue()` and `setValue()` functions because the standard library automatically provides them. #### Lazy properties To initialize a property only when it's first accessed, use a lazy property. The standard library provides the `Lazy` interface for delegation. To create an instance of the `Lazy` interface, use the `lazy()` function by providing it with a lambda expression to execute when the `get()` function is called for the first time. Any further calls of the `get()` function return the same result that was provided on the first call. Lazy properties use the [trailing lambda](kotlin-tour-functions.html#trailing-lambdas) syntax to pass the lambda expression. For example: ```KOTLIN class Database { fun connect() { println("Connecting to the database...") } fun query(sql: String): List { return listOf("Data1", "Data2", "Data3") } } val databaseConnection: Database by lazy { val db = Database() db.connect() db } fun fetchData() { val data = databaseConnection.query("SELECT * FROM data") println("Data: $data") } fun main() { // First time accessing databaseConnection fetchData() // Connecting to the database... // Data: [Data1, Data2, Data3] // Subsequent access uses the existing connection fetchData() // Data: [Data1, Data2, Data3] } ``` In this example: * There is a `Database` class with `connect()` and `query()` member functions. * The `connect()` function prints a string to the console, and the `query()` function accepts an SQL query and returns a list. * There is a `databaseConnection` property that is a lazy property. * The lambda expression provided to the `lazy()` function: * Creates an instance of the `Database` class. * Calls the `connect()` member function on this instance (`db`). * Returns the instance. * There is a `fetchData()` function that: * Creates an SQL query by calling the `query()` function on the `databaseConnection` property. * Assigns the SQL query to the `data` variable. * Prints the `data` variable to the console. * The `main()` function calls the `fetchData()` function. The first time it is called, the lazy property is initialized. The second time, the same result is returned as the first call. Lazy properties are useful not only when initialization is resource-intensive but also when a property might not be used in your code. Additionally, lazy properties are thread-safe by default, which is particularly beneficial if you are working in a concurrent environment. For more information, see [Lazy properties](delegated-properties.html#lazy-properties). #### Observable properties To monitor whether the value of a property changes, use an observable property. An observable property is useful when you want to detect a change in the property value and use this knowledge to trigger a reaction. The standard library provides the `Delegates` object for delegation. To create an observable property, you must first import `kotlin.properties.Delegates.observable`. Then, use the `observable()` function and provide it with a lambda expression to execute whenever the property changes. Just like with lazy properties, observable properties use the [trailing lambda](kotlin-tour-functions.html#trailing-lambdas) syntax to pass the lambda expression. For example: ```KOTLIN import kotlin.properties.Delegates.observable class Thermostat { var temperature: Double by observable(20.0) { _, old, new -> if (new > 25) { println("Warning: Temperature is too high! ($old°C -> $new°C)") } else { println("Temperature updated: $old°C -> $new°C") } } } fun main() { val thermostat = Thermostat() thermostat.temperature = 22.5 // Temperature updated: 20.0°C -> 22.5°C thermostat.temperature = 27.0 // Warning: Temperature is too high! (22.5°C -> 27.0°C) } ``` In this example: * There is a `Thermostat` class that contains an observable property: `temperature`. * The `observable()` function accepts `20.0` as a parameter and uses it to initialize the property. * The lambda expression provided to the `observable()` function: * Has three parameters: * `_`, which refers to the property itself. * `old`, which is the old value of the property. * `new`, which is the new value of the property. * Checks if the `new` parameter is greater than `25` and, depending on the result, prints a string to console. * The `main()` function: * Creates an instance of the `Thermostat` class called `thermostat`. * Updates the value of the `temperature` property of the instance to `22.5`, which triggers a print statement with a temperature update. * Updates the value of the `temperature` property of the instance to `27.0`, which triggers a print statement with a warning. Observable properties are useful not only for logging and debugging purposes. You can also use them for use cases like updating a UI or to perform additional checks, like verifying the validity of data. For more information, see [Observable properties](delegated-properties.html#observable-properties). ## Practice ### Exercise 1 You manage an inventory system at a bookstore. The inventory is stored in a list where each item represents the quantity of a specific book. For example, `listOf(3, 0, 7, 12)` means the store has 3 copies of the first book, 0 of the second, 7 of the third, and 12 of the fourth. Write a function called `findOutOfStockBooks()` that returns a list of indices for all the books that are out of stock. Hint 1 : Use the : [indices](https://kotlinlang.org/api/core/kotlin-stdlib/kotlin.collections/indices.html) : extension property from the standard library. Hint 2 : You can use the : [buildList()](https://kotlinlang.org/api/core/kotlin-stdlib/kotlin.collections/build-list.html) : function to create and manage a list instead of manually creating and returning a mutable list. The : `buildList()` : function uses a lambda with a receiver, which you learned about in earlier chapters. ```KOTLIN fun findOutOfStockBooks(inventory: List): List { // Write your code here } fun main() { val inventory = listOf(3, 0, 7, 0, 5) println(findOutOfStockBooks(inventory)) // [1, 3] } ``` ```KOTLIN fun findOutOfStockBooks(inventory: List): List { val outOfStockIndices = mutableListOf() for (index in inventory.indices) { if (inventory[index] == 0) { outOfStockIndices.add(index) } } return outOfStockIndices } fun main() { val inventory = listOf(3, 0, 7, 0, 5) println(findOutOfStockBooks(inventory)) // [1, 3] } ``` ```KOTLIN fun findOutOfStockBooks(inventory: List): List = buildList { for (index in inventory.indices) { if (inventory[index] == 0) { add(index) } } } fun main() { val inventory = listOf(3, 0, 7, 0, 5) println(findOutOfStockBooks(inventory)) // [1, 3] } ``` ### Exercise 2 You have a travel app that needs to display distances in both kilometers and miles. Create an extension property for the `Double` type called `asMiles` to convert a distance in kilometers to miles: Note: The formula to convert kilometers to miles is `miles = kilometers * 0.621371`. Hint : Remember that extension properties need a custom : `get()` : function. ```KOTLIN val // Write your code here fun main() { val distanceKm = 5.0 println("$distanceKm km is ${distanceKm.asMiles} miles") // 5.0 km is 3.106855 miles val marathonDistance = 42.195 println("$marathonDistance km is ${marathonDistance.asMiles} miles") // 42.195 km is 26.218757 miles } ``` ```KOTLIN val Double.asMiles: Double get() = this * 0.621371 fun main() { val distanceKm = 5.0 println("$distanceKm km is ${distanceKm.asMiles} miles") // 5.0 km is 3.106855 miles val marathonDistance = 42.195 println("$marathonDistance km is ${marathonDistance.asMiles} miles") // 42.195 km is 26.218757 miles } ``` ### Exercise 3 You have a system health checker that can determine the state of a cloud system. However, the two functions it can run to perform a health check are performance intensive. Use lazy properties to initialize the checks so that the expensive functions are only run when needed: ```KOTLIN fun checkAppServer(): Boolean { println("Performing application server health check...") return true } fun checkDatabase(): Boolean { println("Performing database health check...") return false } fun main() { // Write your code here when { isAppServerHealthy -> println("Application server is online and healthy") isDatabaseHealthy -> println("Database is healthy") else -> println("System is offline") } // Performing application server health check... // Application server is online and healthy } ``` ```KOTLIN fun checkAppServer(): Boolean { println("Performing application server health check...") return true } fun checkDatabase(): Boolean { println("Performing database health check...") return false } fun main() { val isAppServerHealthy by lazy { checkAppServer() } val isDatabaseHealthy by lazy { checkDatabase() } when { isAppServerHealthy -> println("Application server is online and healthy") isDatabaseHealthy -> println("Database is healthy") else -> println("System is offline") } // Performing application server health check... // Application server is online and healthy } ``` ### Exercise 4 You're building a simple budget tracker app. The app needs to observe changes to the user's remaining budget and notify them whenever it goes below a certain threshold. You have a `Budget` class that is initialized with a `totalBudget` property that contains the initial budget amount. Within the class, create an observable property called `remainingBudget` that prints: * A warning when the value is lower than 20% of the initial budget. * An encouraging message when the budget is increased from the previous value. ```KOTLIN import kotlin.properties.Delegates.observable class Budget(val totalBudget: Int) { var remainingBudget: Int // Write your code here } fun main() { val myBudget = Budget(totalBudget = 1000) myBudget.remainingBudget = 800 myBudget.remainingBudget = 150 // Warning: Your remaining budget (150) is below 20% of your total budget. myBudget.remainingBudget = 50 // Warning: Your remaining budget (50) is below 20% of your total budget. myBudget.remainingBudget = 300 // Good news: Your remaining budget increased to 300. } ``` ```KOTLIN import kotlin.properties.Delegates.observable class Budget(val totalBudget: Int) { var remainingBudget: Int by observable(totalBudget) { _, oldValue, newValue -> if (newValue < totalBudget * 0.2) { println("Warning: Your remaining budget ($newValue) is below 20% of your total budget.") } else if (newValue > oldValue) { println("Good news: Your remaining budget increased to $newValue.") } } } fun main() { val myBudget = Budget(totalBudget = 1000) myBudget.remainingBudget = 800 myBudget.remainingBudget = 150 // Warning: Your remaining budget (150) is below 20% of your total budget. myBudget.remainingBudget = 50 // Warning: Your remaining budget (50) is below 20% of your total budget. myBudget.remainingBudget = 300 // Good news: Your remaining budget increased to 300. } ``` ## See also * [Previous step](kotlin-tour-intermediate-open-special-classes.html) * [Next step](kotlin-tour-intermediate-null-safety.html) # Null safety In the beginner tour, you learned how to handle `null` values in your code. This chapter covers common use cases for null safety features and how to make the most of them. ## Smart casts and safe casts Kotlin can sometimes infer the type without explicit declaration. When you tell Kotlin to treat a variable or object as if it belongs to a specific type, this process is called casting. When a type is automatically cast, like when it's inferred, it's called smart casting. ### is and !is operators Before we explore how casting works, let's see how you can check if an object has a certain type. For this, you can use the `is` and `!is` operators with `when` or `if` conditional expressions: * `is` checks if the object has the type and returns a boolean value. * `!is` checks if the object doesn't have the type and returns a boolean value. For example: ```KOTLIN fun printObjectType(obj: Any) { when (obj) { is Int -> println("It's an Integer with value $obj") !is Double -> println("It's NOT a Double") else -> println("Unknown type") } } fun main() { val myInt = 42 val myDouble = 3.14 val myList = listOf(1, 2, 3) // The type is Int printObjectType(myInt) // It's an Integer with value 42 // The type is List, so it's NOT a Double. printObjectType(myList) // It's NOT a Double // The type is Double, so the else branch is triggered. printObjectType(myDouble) // Unknown type } ``` Tip: You've already seen an example of how to use a `when` conditional expression with the `is` and `!is` operators in the [Open and other special classes](kotlin-tour-intermediate-open-special-classes.html#sealed-classes) chapter. ### as and as? operators To explicitly cast an object to any other type, use the `as` operator. This includes casting from a nullable type to its non-nullable counterpart. If the cast isn't possible, the program crashes at runtime. This is why it's called the unsafe cast operator. ```KOTLIN fun main() { //sampleStart val a: String? = null val b = a as String // Triggers an error at runtime print(b) //sampleEnd } ``` To explicitly cast an object to a non-nullable type, but return `null` instead of throwing an error on failure, use the `as?` operator. Since the `as?` operator doesn't trigger an error on failure, it is called the safe operator. ```KOTLIN fun main() { //sampleStart val a: String? = null val b = a as? String // Returns null value print(b) // null //sampleEnd } ``` You can combine the `as?` operator with the Elvis operator `?:` to reduce several lines of code down to one. For example, the following `calculateTotalStringLength()` function calculates the total length of all strings provided in a mixed list: ```KOTLIN fun calculateTotalStringLength(items: List): Int { var totalLength = 0 for (item in items) { totalLength += if (item is String) { item.length } else { 0 // Add 0 for non-String items } } return totalLength } ``` The example: * Uses the `totalLength` variable as a counter. * Uses a `for` loop to loop through every item in the list. * Uses an `if` and the `is` operator to check if the current item is a string: * If it is, the string's length is added to the counter. * If it is not, the counter isn't incremented. * Returns the final value of the `totalLength` variable. This code can be reduced to: ```KOTLIN fun calculateTotalStringLength(items: List): Int { return items.sumOf { (it as? String)?.length ?: 0 } } ``` The example uses the [.sumOf()](https://kotlinlang.org/api/core/kotlin-stdlib/kotlin.collections/sum-of.html) extension function and provides a lambda expression that: * For each item in the list, performs a safe cast to `String` using `as?`. * Uses a safe call `?.` to access the `length` property if the call doesn't return a `null` value. * Uses the Elvis operator `?:` to return `0` if the safe call returns a `null` value. ## Null values and collections In Kotlin, working with collections often involves handling `null` values and filtering out unnecessary elements. Kotlin has useful functions that you can use to write clean, efficient, and null-safe code when working with lists, sets, maps, and other types of collections. To filter `null` values from a list, use the [filterNotNull()](https://kotlinlang.org/api/core/kotlin-stdlib/kotlin.collections/filter-not-null.html) function: ```KOTLIN fun main() { //sampleStart val emails: List = listOf("alice@example.com", null, "bob@example.com", null, "carol@example.com") val validEmails = emails.filterNotNull() println(validEmails) // [alice@example.com, bob@example.com, carol@example.com] //sampleEnd } ``` If you want to perform filtering of `null` values directly when creating a list, use the [listOfNotNull()](https://kotlinlang.org/api/core/kotlin-stdlib/kotlin.collections/list-of-not-null.html) function: ```KOTLIN fun main() { //sampleStart val serverConfig = mapOf( "appConfig.json" to "App Configuration", "dbConfig.json" to "Database Configuration" ) val requestedFile = "appConfig.json" val configFiles = listOfNotNull(serverConfig[requestedFile]) println(configFiles) // [App Configuration] //sampleEnd } ``` In both of these examples, if all items are `null` values, an empty list is returned. Kotlin also provides functions that you can use to find values in collections. If a value isn't found, they return `null` values instead of triggering an error: * [maxOrNull()](https://kotlinlang.org/api/core/kotlin-stdlib/kotlin.collections/max-or-null.html) finds the highest value. If one doesn't exist, returns a `null` value. * [minOrNull()](https://kotlinlang.org/api/core/kotlin-stdlib/kotlin.collections/min-or-null.html) finds the lowest value. If one doesn't exist, returns a `null` value. For example: ```KOTLIN fun main() { //sampleStart // Temperatures recorded over a week val temperatures = listOf(15, 18, 21, 21, 19, 17, 16) // Find the highest temperature of the week val maxTemperature = temperatures.maxOrNull() println("Highest temperature recorded: ${maxTemperature ?: "No data"}") // Highest temperature recorded: 21 // Find the lowest temperature of the week val minTemperature = temperatures.minOrNull() println("Lowest temperature recorded: ${minTemperature ?: "No data"}") // Lowest temperature recorded: 15 //sampleEnd } ``` This example uses the Elvis operator `?:` to return a printed statement if the functions return a `null` value. Note: The `maxOrNull()`, and `minOrNull()` functions are designed to be used with collections that don't contain `null` values. Otherwise, you can't tell whether the function couldn't find the desired value or whether it found a `null` value. You can use the [singleOrNull()](https://kotlinlang.org/api/core/kotlin-stdlib/kotlin.collections/single-or-null.html) function with a lambda expression to find a single item that matches a condition. If one doesn't exist or there are multiple items that match, the function returns a `null` value: ```KOTLIN fun main() { //sampleStart // Temperatures recorded over a week val temperatures = listOf(15, 18, 21, 21, 19, 17, 16) // Check if there was exactly one day with 30 degrees val singleHotDay = temperatures.singleOrNull{ it == 30 } println("Single hot day with 30 degrees: ${singleHotDay ?: "None"}") // Single hot day with 30 degrees: None //sampleEnd } ``` Note: The `singleOrNull()` function is designed to be used with collections that don't contain `null` values. Some functions use a lambda expression to transform a collection and return `null` values if they can't fulfill their purpose. To transform a collection with a lambda expression and return the first value that isn't `null`, use the [firstNotNullOfOrNull()](https://kotlinlang.org/api/core/kotlin-stdlib/kotlin.collections/first-not-null-of-or-null.html) function. If no such value exists, the function returns a `null` value: ```KOTLIN fun main() { //sampleStart data class User(val name: String?, val age: Int?) val users = listOf( User(null, 25), User("Alice", null), User("Bob", 30) ) val firstNonNullName = users.firstNotNullOfOrNull { it.name } println(firstNonNullName) // Alice //sampleEnd } ``` To use a lambda expression to process each collection item sequentially and create an accumulated value (or return a `null` value if the collection is empty) use the [reduceOrNull()](https://kotlinlang.org/api/core/kotlin-stdlib/kotlin.collections/reduce-or-null.html) function: ```KOTLIN fun main() { //sampleStart // Prices of items in a shopping cart val itemPrices = listOf(20, 35, 15, 40, 10) // Calculate the total price using the reduceOrNull() function val totalPrice = itemPrices.reduceOrNull { runningTotal, price -> runningTotal + price } println("Total price of items in the cart: ${totalPrice ?: "No items"}") // Total price of items in the cart: 120 val emptyCart = listOf() val emptyTotalPrice = emptyCart.reduceOrNull { runningTotal, price -> runningTotal + price } println("Total price of items in the empty cart: ${emptyTotalPrice ?: "No items"}") // Total price of items in the empty cart: No items //sampleEnd } ``` This example also uses the Elvis operator `?:` to return a printed statement if the function returns a `null` value. Note: The `reduceOrNull()` function is designed to be used with collections that don't contain `null` values. Explore Kotlin's [standard library](https://kotlinlang.org/api/core/kotlin-stdlib/) to find more functions that you can use to make your code safer. ## Early returns and the Elvis operator In the beginner tour, you learned how to use [early returns](kotlin-tour-functions.html#early-returns-in-functions) to stop your function from being processed further than a certain point. You can use the Elvis operator `?:` with an early return to check preconditions in a function. This approach is a great way to keep your code concise because you don't need to use nested checks. The reduced complexity of your code also makes it easier to maintain. For example: ```KOTLIN data class User( val id: Int, val name: String, // List of friend user IDs val friends: List ) // Function to get the number of friends for a user fun getNumberOfFriends(users: Map, userId: Int): Int { // Retrieves the user or return -1 if not found val user = users[userId] ?: return -1 // Returns the number of friends return user.friends.size } fun main() { // Creates some sample users val user1 = User(1, "Alice", listOf(2, 3)) val user2 = User(2, "Bob", listOf(1)) val user3 = User(3, "Charlie", listOf(1)) // Creates a map of users val users = mapOf(1 to user1, 2 to user2, 3 to user3) println(getNumberOfFriends(users, 1)) // 2 println(getNumberOfFriends(users, 2)) // 1 println(getNumberOfFriends(users, 4)) // -1 } ``` In this example: * There is a `User` data class that has properties for the user's `id`, `name` and list of friends. * The `getNumberOfFriends()` function: * Accepts a map of `User` instances and a user ID as an integer. * Accesses the value of the map of `User` instances with the provided user ID. * Uses an Elvis operator to return the function early with the value of `-1` if the map value is a `null` value. * Assigns the value found from the map to the `user` variable. * Returns the number of friends in the user's friends list by using the `size` property. * The `main()` function: * Creates three `User` instances. * Creates a map of these `User` instances and assigns them to the `users` variable. * Calls the `getNumberOfFriends()` function on the `users` variable with values `1` and `2` that returns two friends for `"Alice"` and one friend for `"Bob"`. * Calls the `getNumberOfFriends()` function on the `users` variable with value `4`, which triggers an early return with a value of `-1`. You may notice that the code could be more concise without an early return. However, this approach needs multiple safe calls because the `users[userId]` might return a `null` value, making the code slightly harder to read: ```KOTLIN fun getNumberOfFriends(users: Map, userId: Int): Int { // Retrieve the user or return -1 if not found return users[userId]?.friends?.size ?: -1 } ``` Although this example checks only one condition with the Elvis operator, you can add multiple checks to cover any critical error paths. Early returns with the Elvis operator prevent your program from doing unnecessary work and make your code safer by stopping as soon as a `null` value or invalid case is detected. For more information about how you can use `return` in your code, see [Returns and jumps](returns.html). ## Practice ### Exercise 1 You are developing a notification system for an app where users can enable or disable different types of notifications. Complete the `getNotificationPreferences()` function so that: 1. The `validUser` variable uses the `as?` operator to check if `user` is an instance of the `User` class. If it isn't, return an empty list. 2. The `userName` variable uses the Elvis `?:` operator to ensure that the user's name defaults to `"Guest"` if it is `null`. 3. The final return statement uses the `.takeIf()` function to include email and SMS notification preferences only if they are enabled. 4. The `main()` function runs successfully and prints the expected output. Tip: The [takeIf() function](scope-functions.html#takeif-and-takeunless) returns the original value if the given condition is true, otherwise it returns `null`. For example: ```KOTLIN fun main() { // The user is logged in val userIsLoggedIn = true // The user has an active session val hasSession = true // Gives access to the dashboard if the user is logged in // and has an active session val canAccessDashboard = userIsLoggedIn.takeIf { hasSession } println(canAccessDashboard ?: "Access denied") // true } ``` ```KOTLIN data class User(val name: String?) fun getNotificationPreferences(user: Any, emailEnabled: Boolean, smsEnabled: Boolean): List { val validUser = // Write your code here val userName = // Write your code here return listOfNotNull( /* Write your code here */) } fun main() { val user1 = User("Alice") val user2 = User(null) val invalidUser = "NotAUser" println(getNotificationPreferences(user1, emailEnabled = true, smsEnabled = false)) // [Email Notifications enabled for Alice] println(getNotificationPreferences(user2, emailEnabled = false, smsEnabled = true)) // [SMS Notifications enabled for Guest] println(getNotificationPreferences(invalidUser, emailEnabled = true, smsEnabled = true)) // [] } ``` ```KOTLIN data class User(val name: String?) fun getNotificationPreferences(user: Any, emailEnabled: Boolean, smsEnabled: Boolean): List { val validUser = user as? User ?: return emptyList() val userName = validUser.name ?: "Guest" return listOfNotNull( "Email Notifications enabled for $userName".takeIf { emailEnabled }, "SMS Notifications enabled for $userName".takeIf { smsEnabled } ) } fun main() { val user1 = User("Alice") val user2 = User(null) val invalidUser = "NotAUser" println(getNotificationPreferences(user1, emailEnabled = true, smsEnabled = false)) // [Email Notifications enabled for Alice] println(getNotificationPreferences(user2, emailEnabled = false, smsEnabled = true)) // [SMS Notifications enabled for Guest] println(getNotificationPreferences(invalidUser, emailEnabled = true, smsEnabled = true)) // [] } ``` ### Exercise 2 You are working on a subscription-based streaming service where users can have multiple subscriptions, but only one can be active at a time. Complete the `getActiveSubscription()` function so that it uses the `singleOrNull()` function with a predicate to return a `null` value if there is more than one active subscription: ```KOTLIN data class Subscription(val name: String, val isActive: Boolean) fun getActiveSubscription(subscriptions: List): Subscription? // Write your code here fun main() { val userWithPremiumPlan = listOf( Subscription("Basic Plan", false), Subscription("Premium Plan", true) ) val userWithConflictingPlans = listOf( Subscription("Basic Plan", true), Subscription("Premium Plan", true) ) println(getActiveSubscription(userWithPremiumPlan)) // Subscription(name=Premium Plan, isActive=true) println(getActiveSubscription(userWithConflictingPlans)) // null } ``` ```KOTLIN data class Subscription(val name: String, val isActive: Boolean) fun getActiveSubscription(subscriptions: List): Subscription? { return subscriptions.singleOrNull { subscription -> subscription.isActive } } fun main() { val userWithPremiumPlan = listOf( Subscription("Basic Plan", false), Subscription("Premium Plan", true) ) val userWithConflictingPlans = listOf( Subscription("Basic Plan", true), Subscription("Premium Plan", true) ) println(getActiveSubscription(userWithPremiumPlan)) // Subscription(name=Premium Plan, isActive=true) println(getActiveSubscription(userWithConflictingPlans)) // null } ``` ```KOTLIN data class Subscription(val name: String, val isActive: Boolean) fun getActiveSubscription(subscriptions: List): Subscription? = subscriptions.singleOrNull { it.isActive } fun main() { val userWithPremiumPlan = listOf( Subscription("Basic Plan", false), Subscription("Premium Plan", true) ) val userWithConflictingPlans = listOf( Subscription("Basic Plan", true), Subscription("Premium Plan", true) ) println(getActiveSubscription(userWithPremiumPlan)) // Subscription(name=Premium Plan, isActive=true) println(getActiveSubscription(userWithConflictingPlans)) // null } ``` ### Exercise 3 You are working on a social media platform where users have usernames and account statuses. You want to see the list of currently active usernames. Complete the `getActiveUsernames()` function so that the [mapNotNull() function](https://kotlinlang.org/api/core/kotlin-stdlib/kotlin.collections/map-not-null.html) has a predicate that returns the username if it is active or a `null` value if it isn't: ```KOTLIN data class User(val username: String, val isActive: Boolean) fun getActiveUsernames(users: List): List { return users.mapNotNull { /* Write your code here */ } } fun main() { val allUsers = listOf( User("alice123", true), User("bob_the_builder", false), User("charlie99", true) ) println(getActiveUsernames(allUsers)) // [alice123, charlie99] } ``` Tip: Just like in Exercise 1, you can use the [takeIf() function](scope-functions.html#takeif-and-takeunless) when you check if the user is active. ```KOTLIN data class User(val username: String, val isActive: Boolean) fun getActiveUsernames(users: List): List { return users.mapNotNull { user -> if (user.isActive) user.username else null } } fun main() { val allUsers = listOf( User("alice123", true), User("bob_the_builder", false), User("charlie99", true) ) println(getActiveUsernames(allUsers)) // [alice123, charlie99] } ``` ```KOTLIN data class User(val username: String, val isActive: Boolean) fun getActiveUsernames(users: List): List = users.mapNotNull { user -> user.username.takeIf { user.isActive } } fun main() { val allUsers = listOf( User("alice123", true), User("bob_the_builder", false), User("charlie99", true) ) println(getActiveUsernames(allUsers)) // [alice123, charlie99] } ``` ### Exercise 4 You are working on an inventory management system for an e-commerce platform. Before processing a sale, you need to check if the requested quantity of a product is valid based on the available stock. Complete the `validateStock()` function so that it uses early returns and the Elvis operator (where applicable) to check if: * The `requested` variable is `null`. * The `available` variable is `null`. * The `requested` variable is a negative value. * The amount in the `requested` variable is higher than in the `available` variable. In all of the above cases, the function must return early with the value of `-1`. ```KOTLIN fun validateStock(requested: Int?, available: Int?): Int { // Write your code here } fun main() { println(validateStock(5,10)) // 5 println(validateStock(null,10)) // -1 println(validateStock(-2,10)) // -1 } ``` ```KOTLIN fun validateStock(requested: Int?, available: Int?): Int { val validRequested = requested ?: return -1 val validAvailable = available ?: return -1 if (validRequested < 0) return -1 if (validRequested > validAvailable) return -1 return validRequested } fun main() { println(validateStock(5,10)) // 5 println(validateStock(null,10)) // -1 println(validateStock(-2,10)) // -1 } ``` ## See also * [Previous step](kotlin-tour-intermediate-properties.html) * [Next step](kotlin-tour-intermediate-libraries-and-apis.html) # Libraries and APIs To get the most out of Kotlin, use existing libraries and APIs so you can spend more time coding and less time reinventing the wheel. Libraries distribute reusable code that simplifies common tasks. Within libraries, there are packages and objects that group related classes, functions, and utilities. Libraries expose APIs (Application Programming Interfaces) as a set of functions, classes, or properties that developers can use in their code. ![Kotlin libraries and APIs](images/kotlin-library-diagram.svg) Let's explore what's possible with Kotlin. ## The standard library Kotlin has a standard library that provides essential types, functions, collections, and utilities to make your code concise and expressive. A large portion of the standard library (everything in the [kotlin package](https://kotlinlang.org/api/core/kotlin-stdlib/kotlin/)) is readily available in any Kotlin file without the need to import it explicitly: ```KOTLIN fun main() { val text = "emosewa si niltoK" // Use the reversed() function from the standard library val reversedText = text.reversed() // Use the print() function from the standard library print(reversedText) // Kotlin is awesome } ``` However, some parts of the standard library require an import before you can use them in your code. For example, if you want to use the standard library's time measurement features, you need to import the [kotlin.time package](https://kotlinlang.org/api/core/kotlin-stdlib/kotlin.time/). At the top of your file, add the `import` keyword followed by the package that you need: ```KOTLIN import kotlin.time.* ``` The asterisk `*` is a wildcard import that tells Kotlin to import everything within the package. You can't use the asterisk `*` with companion objects. Instead, you need to explicitly declare the members of a companion object that you want to use. For example: ```KOTLIN import kotlin.time.Duration import kotlin.time.Duration.Companion.hours import kotlin.time.Duration.Companion.minutes fun main() { val thirtyMinutes: Duration = 30.minutes val halfHour: Duration = 0.5.hours println(thirtyMinutes == halfHour) // true } ``` This example: * Imports the `Duration` class and the `hours` and `minutes` extension properties from its companion object. * Uses the `minutes` property to convert `30` into a `Duration` of 30 minutes. * Uses the `hours` property to convert `0.5` into a `Duration` of 30 minutes. * Checks if both durations are equal and prints the result. ### Search before you build Before you decide to write your own code, check the standard library to see if what you're looking for already exists. Here's a list of areas where the standard library already provides a number of classes, functions, and properties for you: * [Collections](https://kotlinlang.org/api/core/kotlin-stdlib/kotlin.collections/) * [Sequences](https://kotlinlang.org/api/core/kotlin-stdlib/kotlin.sequences/) * [String manipulation](https://kotlinlang.org/api/core/kotlin-stdlib/kotlin.text/) * [Time management](https://kotlinlang.org/api/core/kotlin-stdlib/kotlin.time/) To learn more about what else is in the standard library, explore its [API reference](https://kotlinlang.org/api/core/kotlin-stdlib/). ## Kotlin libraries The standard library covers many common use cases, but there are some that it doesn't address. Fortunately, the Kotlin team and the rest of the community have developed a wide range of libraries to complement the standard library. For example, [kotlinx-datetime](https://kotlinlang.org/api/kotlinx-datetime/) helps you manage time across different platforms. You can find useful libraries on our [search platform](https://klibs.io/). To use them, you need to take extra steps, like adding a dependency or plugin. Each library has a GitHub repository with instructions on how to include it in your Kotlin projects. Once you add the library, you can import any package within it. Here's an example of how to import the `kotlinx-datetime` package to find the current time in New York: ```KOTLIN import kotlinx.datetime.* fun main() { val now = Clock.System.now() // Get current instant println("Current instant: $now") val zone = TimeZone.of("America/New_York") val localDateTime = now.toLocalDateTime(zone) println("Local date-time in NY: $localDateTime") } ``` This example: * Imports the `kotlinx.datetime` package. * Uses the `Clock.System.now()` function to create an instance of the `Instant` class that contains the current time and assigns the result to the `now` variable. * Prints the current time. * Uses the `TimeZone.of()` function to find the time zone for New York and assigns the result to the `zone` variable. * Calls the `.toLocalDateTime()` function on the instance containing the current time, with the New York time zone as an argument. * Assigns the result to the `localDateTime` variable. * Prints the time adjusted for the time zone in New York. Tip: To explore the functions and classes that this example uses in more detail, see the [API reference](https://kotlinlang.org/api/kotlinx-datetime/kotlinx-datetime/kotlinx.datetime/). ## Opt in to APIs Library authors may mark certain APIs as requiring opt-in before you can use them in your code. They usually do this when an API is still in development and may change in the future. If you don't opt in, you see warnings or errors like this: ```TEXT This declaration needs opt-in. Its usage should be marked with '@...' or '@OptIn(...)' ``` To opt in, write `@OptIn` followed by parentheses containing the class name that categorizes the API, appended by two colons `::` and `class`. For example, the `uintArrayOf()` function from the standard library falls under `@ExperimentalUnsignedTypes`, as shown [in the API reference](https://kotlinlang.org/api/core/kotlin-stdlib/kotlin.collections/to-u-int-array.html): ```KOTLIN @ExperimentalUnsignedTypes inline fun uintArrayOf(vararg elements: UInt): UIntArray ``` In your code, the opt-in looks like: ```KOTLIN @OptIn(ExperimentalUnsignedTypes::class) ``` Here's an example that opts in to use the `uintArrayOf()` function to create an array of unsigned integers and modifies one of its elements: ```KOTLIN @OptIn(ExperimentalUnsignedTypes::class) fun main() { // Create an unsigned integer array val unsignedArray: UIntArray = uintArrayOf(1u, 2u, 3u, 4u, 5u) // Modify an element unsignedArray[2] = 42u println("Updated array: ${unsignedArray.joinToString()}") // Updated array: 1, 2, 42, 4, 5 } ``` This is the easiest way to opt in, but there are other ways. To learn more, see [Opt-in requirements](opt-in-requirements.html). ## Practice ### Exercise 1 You are developing a financial application that helps users calculate the future value of their investments. The formula to calculate compound interest is: $A = P \times (1 + \displaystyle\frac{r}{n})^{nt}$ Where: * `A` is the amount of money accumulated after interest (principal + interest). * `P` is the principal amount (the initial investment). * `r` is the annual interest rate (decimal). * `n` is the number of times interest is compounded per year. * `t` is the time the money is invested for (in years). Update the code to: 1. Import the necessary functions from the [kotlin.math package](https://kotlinlang.org/api/core/kotlin-stdlib/kotlin.math/). 2. Add a body to the `calculateCompoundInterest()` function that calculates the final amount after applying compound interest. ```KOTLIN // Write your code here fun calculateCompoundInterest(P: Double, r: Double, n: Int, t: Int): Double { // Write your code here } fun main() { val principal = 1000.0 val rate = 0.05 val timesCompounded = 4 val years = 5 val amount = calculateCompoundInterest(principal, rate, timesCompounded, years) println("The accumulated amount is: $amount") // The accumulated amount is: 1282.0372317085844 } ``` ```KOTLIN import kotlin.math.* fun calculateCompoundInterest(P: Double, r: Double, n: Int, t: Int): Double { return P * (1 + r / n).pow(n * t) } fun main() { val principal = 1000.0 val rate = 0.05 val timesCompounded = 4 val years = 5 val amount = calculateCompoundInterest(principal, rate, timesCompounded, years) println("The accumulated amount is: $amount") // The accumulated amount is: 1282.0372317085844 } ``` ### Exercise 2 You want to measure the time it takes to perform multiple data processing tasks in your program. Update the code to add the correct import statements and functions from the [kotlin.time](https://kotlinlang.org/api/core/kotlin-stdlib/kotlin.time/) package: ```KOTLIN // Write your code here fun main() { val timeTaken = /* Write your code here */ { // Simulate some data processing val data = List(1000) { it * 2 } val filteredData = data.filter { it % 3 == 0 } // Simulate processing the filtered data val processedData = filteredData.map { it / 2 } println("Processed data") } println("Time taken: $timeTaken") // e.g. 16 ms } ``` ```KOTLIN import kotlin.time.measureTime fun main() { val timeTaken = measureTime { // Simulate some data processing val data = List(1000) { it * 2 } val filteredData = data.filter { it % 3 == 0 } // Simulate processing the filtered data val processedData = filteredData.map { it / 2 } println("Processed data") } println("Time taken: $timeTaken") // e.g. 16 ms } ``` ### Exercise 3 There's a new feature in the standard library available in the latest Kotlin release. You want to try it out, but it requires opt-in. The feature falls under [@ExperimentalStdlibApi](https://kotlinlang.org/api/core/kotlin-stdlib/kotlin/-experimental-stdlib-api/). What should the opt-in look like in your code? ```KOTLIN @OptIn(ExperimentalStdlibApi::class) ``` ## What's next? Congratulations! You've completed the intermediate tour! Would you like to [share your feedback](https://surveys.hotjar.com/bf4ce865-99ce-4fc1-b107-e9b16bc31592) about your experience? As a next step, check out our tutorials for popular Kotlin applications: * [Create a backend application with Spring Boot and Kotlin](jvm-create-project-with-spring-boot.html) * Create a cross-platform application for Android and iOS from scratch and: * [Share business logic while keeping the UI native](https://kotlinlang.org/docs/multiplatform/multiplatform-create-first-app.html) * [Share business logic and UI](https://kotlinlang.org/docs/multiplatform/compose-multiplatform-create-first-app.html) ## See also * [Previous step](kotlin-tour-intermediate-null-safety.html) # What's new in Kotlin 2.4.20 [Released: September 7, 2026](releases.html#release-history) Kotlin 2.4.20 is out! Here are the release highlights: * Standard library: [Support for coroutine stack trace recovery, new functions for checking the equality and uniqueness of collection elements, and new overloads for kotlin.test assertion functions](#standard-library) * Kotlin/Native: [New Swift export features, improved incremental compilation, and automatically generated Package.swift files for SwiftPM dependencies](#kotlin-native) * Kotlin/Wasm: [Changes to top-level require() calls in @JsFun declarations, improved initialization order of companion objects, support for Wasmtime in the Kotlin Gradle plugin, new compilation modes, and reduced binary size for functional interfaces](#kotlin-wasm) * Kotlin/JS: [A new DSL for browser testing, support for exporting suspending lambdas as async functions, improved exportability of data classes](#kotlin-js) * Gradle: [Support for Gradle 9.7.0 and improved reporting in the Problems API](#gradle) * Build tools API: [Support for new targets: Kotlin/JS, Kotlin/Wasm, and Kotlin metadata](#build-tools-api) * Kotlin compiler: [kotlinr runner command and a separate native image](#kotlin-compiler) You can also find an overview of the updates in this video: [Video: What's New in Kotlin 2.4.20](https://www.youtube.com/v/UhRfN7fx5rs) Tip: For information about the Kotlin release cycle, see [Kotlin release process](releases.html). ## Update to Kotlin 2.4.20 The latest version of Kotlin is included in the latest versions of [IntelliJ IDEA](https://www.jetbrains.com/idea/download/) and [Android Studio](https://developer.android.com/studio). To update to the new Kotlin version, make sure your IDE is updated to the latest version and [change the Kotlin version](releases.html#update-to-a-new-kotlin-version) to 2.4.20 in your build scripts. ## New features Kotlin 2.2.20 introduced experimental support for compiling `when` expressions with `invokedynamic` on JVM 21 and later. In Kotlin 2.4.20, the feature has now graduated to [Stable](components-stability.html#stability-levels-explained) and is enabled by default. For more information, see the [documentation](control-flow.html#bytecode-generation-on-the-jvm). ## New features The following pre-stable features are available in this release, including those with [Beta](components-stability.html#stability-levels-explained), [Alpha](components-stability.html#stability-levels-explained), and [Experimental](components-stability.html#stability-levels-explained) status: * [Standard library: Support for coroutine stack trace recovery](#support-for-coroutine-stack-trace-recovery) * [Standard library: New functions to check collection elements for equality and uniqueness](#new-functions-to-check-collection-elements-for-equality-and-uniqueness) * [Standard library: New overloads for kotlin.test assertion functions](#new-overloads-for-kotlin-test-assertion-functions) * [Kotlin/Native: New Swift export features](#new-swift-export-features) * [Kotlin/Native: Improved incremental compilation of klib artifacts](#improved-incremental-compilation-of-klib-artifacts) * [Kotlin/JS: A new DSL for browser testing](#a-new-dsl-for-browser-testing) * [Kotlin/JS: Support for exporting suspending lambdas as async functions](#support-for-exporting-suspending-lambdas-as-async-functions) * [Build tools API: Support for Kotlin/JS, Kotlin/Wasm, and Kotlin metadata](#support-for-kotlin-js-kotlin-wasm-and-kotlin-metadata) * [Kotlin compiler: Separate native image](#native-image) ## Standard library Kotlin 2.4.20 adds support for coroutine stack trace recovery and introduces new functions to check collection elements for equality and uniqueness, as well as new overloads for `kotlin.test` assertion functions. ### Support for coroutine stack trace recovery Kotlin 2.4.20 adds the [StackTraceRecoverable](https://kotlinlang.org/api/core/kotlin-stdlib/kotlin.coroutines.debug/-stack-trace-recoverable/) interface to the standard library. This improves integration with the `kotlinx.coroutines` library because it lets you define how to create new exception instances for stack trace recovery without adding a dependency on `kotlinx.coroutines`. Stack trace recovery helps with debugging when one coroutine throws an exception and another rethrows it. It lets you see where the exception originates and where another coroutine rethrows it. The `kotlinx.coroutines` library performs stack trace recovery by creating a new exception instance with additional coroutine stack trace information. This happens automatically for exceptions with constructors that take only an exception message, a cause, both, or no arguments. If an exception constructor has additional required arguments, such as a line number or an error code, implement the `StackTraceRecoverable` interface to define how the `kotlinx.coroutines` library creates a new instance of that exception. To implement the interface, override the [copyForStackTraceRecovery()](https://kotlinlang.org/api/core/kotlin-stdlib/kotlin.coroutines.debug/-stack-trace-recoverable/copy-for-stack-trace-recovery.html) function. In the override, return a new exception instance for stack trace recovery, or `null` if you don't want the `kotlinx.coroutines` library to copy the exception. Note: The `StackTraceRecoverable` interface is available on all targets, but the `kotlinx.coroutines` library uses it for stack trace recovery only on the JVM. These APIs are [Experimental](components-stability.html#stability-levels-explained) and require opt-in with the `@OptIn(ExperimentalStdlibCoroutineSupportApi::class)` annotation. Here's an example of a custom exception that preserves a `line` property when it creates a new instance for stack trace recovery: ```KOTLIN import kotlin.coroutines.ExperimentalStdlibCoroutineSupportApi import kotlin.coroutines.debug.StackTraceRecoverable @OptIn(ExperimentalStdlibCoroutineSupportApi::class) class FileEditException // The implementation requires a private constructor // to pass the cause to the IllegalStateException constructor private constructor( val line: Int, private val detail: String, cause: Throwable?, ) : IllegalStateException("When editing line $line: $detail", cause), // Implements StackTraceRecoverable for stack trace recovery StackTraceRecoverable { constructor(line: Int, detail: String) : this(line, detail, null) // Copies the line number and message details override fun copyForStackTraceRecovery(): FileEditException = FileEditException(line, detail, this) } fun main() { val original = FileEditException(15, "Unexpected token") // Normally, you don't need to call this function directly unless you're testing its behavior // The kotlinx.coroutines library invokes it automatically during stack trace recovery val copy = original.copyForStackTraceRecovery() println(copy.message) // When editing line 15: Unexpected token println(copy.cause == original) // true } ``` For more information, see the feature's [KEEP](https://github.com/Kotlin/KEEP/blob/main/proposals/stdlib/KEEP-0461-stacktrace-recoverable.md). We would appreciate your feedback in [YouTrack](https://youtrack.jetbrains.com/issue/KT-86595). ### New functions to check collection elements for equality and uniqueness Before Kotlin 2.4.20, if you wanted to check whether collection elements were all distinct or all equal, you had to use inefficient code patterns. Kotlin 2.4.20 introduces experimental functions to fill this gap: | Function |Checks | -------------------- | [allDistinct()](https://kotlinlang.org/api/core/kotlin-stdlib/kotlin.collections/all-distinct.html) |Every value in the collection is unique. | | [allDistinctBy()](https://kotlinlang.org/api/core/kotlin-stdlib/kotlin.collections/all-distinct-by.html) |Every object has a unique value for the selected property. | | [allEqual()](https://kotlinlang.org/api/core/kotlin-stdlib/kotlin.collections/all-equal.html) |Every value in the collection is the same. | | [allEqualBy()](https://kotlinlang.org/api/core/kotlin-stdlib/kotlin.collections/all-equal-by.html) |Every object has the same value for the selected property. | You can use these functions on collections, sequences, and arrays. They compare elements using structural equality just like other collection operations. These functions are [Experimental](components-stability.html#stability-levels-explained) and require opt-in with the `@OptIn(ExperimentalStdlibApi::class)` annotation or the `-opt-in=kotlin.ExperimentalStdlibApi` compiler option: ```KOTLIN @OptIn(ExperimentalStdlibApi::class) fun main() { data class Response( val participantId: String, val answer: String, val responseDate: String ) val responses = listOf( Response("P001", "Yes", "2026-07-21"), Response("P002", "Maybe", "2026-07-21"), Response("P003", "No", "2026-07-21") ) // Checks if all participants gave the same answer println(responses.allEqualBy { it.answer }) // false // Checks for duplicate participants println(responses.allDistinctBy { it.participantId }) // true // Checks if all responses were submitted on the same date println(responses.allEqualBy { it.responseDate }) // true val answers = responses.map { it.answer } // Checks if answers are identical println(answers.allEqual()) // false // Checks if answers are distinct println(answers.allDistinct()) // true } ``` We would appreciate your feedback in the [KEEP](https://github.com/Kotlin/KEEP/discussions/495). ### New overloads for `kotlin.test` assertion functions Kotlin 2.4.20 adds new overloads for `kotlin.test` assertion functions. They accept a lambda that generates error messages lazily, only when the assertion fails. Previously, `kotlin.test` assertion functions like `assertTrue()` or `assertEquals()` accepted only pre-formatted error messages built on every assertion, even when the assertion succeeded, and the message was never actually used. The new overloads align the `kotlin.test` API with JUnit 5 and accept a message supplier through a lambda, instead of a plain string. This improves performance, especially for the [Power-assert compiler plugin](power-assert.html), which generates detailed error messages for assertions. The new overloads are available for the following assertion functions: | Function |Description | ------------------------- | [assertTrue()](https://kotlinlang.org/api/core/kotlin-test/kotlin.test/assert-true.html) / [assertFalse()](https://kotlinlang.org/api/core/kotlin-test/kotlin.test/assert-false.html) |Checks whether the value is `true` or `false`. | | [assertEquals()](https://kotlinlang.org/api/core/kotlin-test/kotlin.test/assert-equals.html) / [assertNotEquals()](https://kotlinlang.org/api/core/kotlin-test/kotlin.test/assert-not-equals.html) |Checks whether the values are equal or not. | | [assertSame()](https://kotlinlang.org/api/core/kotlin-test/kotlin.test/assert-same.html) / [assertNotSame()](https://kotlinlang.org/api/core/kotlin-test/kotlin.test/assert-not-same.html) |Checks whether the values refer to the same instance. | | [assertIs()](https://kotlinlang.org/api/core/kotlin-test/kotlin.test/assert-is.html) / [assertIsNot()](https://kotlinlang.org/api/core/kotlin-test/kotlin.test/assert-is-not.html) |Checks whether the value is of the specified type. For `assertIs()`, the function smart-casts it to that type. | | [assertNull()](https://kotlinlang.org/api/core/kotlin-test/kotlin.test/assert-null.html) |Checks whether the value is `null`. | | [assertContains()](https://kotlinlang.org/api/core/kotlin-test/kotlin.test/assert-contains.html) |Checks whether the element (key, character, substring, or regex) is present in the collection, array, sequence, range, or map. | | [assertContentEquals()](https://kotlinlang.org/api/core/kotlin-test/kotlin.test/assert-content-equals.html) |Checks whether the collections, sequences, or arrays contain equal elements in the same order. | To use the new API, explicitly opt in with the `@OptIn(ExperimentalKotlinTestApi::class)` annotation: ```KOTLIN import kotlin.test.ExperimentalKotlinTestApi import kotlin.test.assertEquals import kotlin.test.assertTrue @OptIn(ExperimentalKotlinTestApi::class) fun testValues(actual: Int, expected: Int, items: List) { // The message is built only if the assertion fails assertTrue(actual > 0) { "Expected a positive value but got $actual" } // Avoids formatting the list unless the assertion fails assertEquals(expected, actual) { "Unexpected value for items: ${items.joinToString()}" } } ``` For more information, see the feature's [KEEP](https://github.com/Kotlin/KEEP/blob/main/proposals/stdlib/KEEP-0465-kotlin.test-lazy-assertion-messages.md). ## Kotlin/Native Kotlin 2.4.20 brings automatic generation of `Package.swift` files for SwiftPM dependencies in Kotlin Multiplatform projects, new Swift export features, including support for sealed classes and cross-language inheritance, and improved incremental compilation. ### Generated `Package.swift` for SwiftPM dependencies When exporting an XCFramework that depends on SwiftPM packages, you must publish the resulting SwiftPM package for it to resolve correctly. To help with this, the `assembleSharedXCFramework` Gradle task now generates a `Package.swift` file to be distributed along with the XCFramework. For details, see the [SwiftPM export page](https://kotlinlang.org/docs/multiplatform/multiplatform-spm-export.html). ### New Swift export features #### Sealed classes Kotlin 2.4.20 adds support for sealed classes and interfaces to Swift export. Previously, you had to write a `default` case for every `switch` statement over a sealed type. Now, sealed hierarchies defined in Kotlin are mapped to Swift enums, enabling exhaustive `switch` statements with full autocompletion in Xcode. Swift export generates a `sealedType()` method on each sealed type. This method returns a Swift enum whose cases match the direct subclasses of the sealed hierarchy. You can nest these calls to match deeper levels of the hierarchy. For example, declare a sealed interface with a class hierarchy in Kotlin: ```KOTLIN // Kotlin sealed interface Shape class Circle : Shape { override fun toString(): String = "Circle" } class Rectangle : Shape { override fun toString(): String = "Rectangle" } fun createCircle(): Shape = Circle() ``` On the Swift side, you can use an exhaustive `switch` without a `default` case: ```SWIFT // Swift let shape = createCircle() let name = switch shape.sealedType() { case let .circle(type): "It's a \(type.value)" case let .rectangle(type): "It's a \(type.value)" } // name == "It's a Circle" ``` Because the `switch` is exhaustive, the compiler warns you if a new subclass is added to the sealed hierarchy, so you can handle it immediately instead of relying on a `default` case. #### Cross-language inheritance in Swift export Kotlin 2.4.20 introduces cross-language inheritance support in Swift export. A common use case for this feature is the [reverse import](native-lib-import-stability.html#swift-library-import) pattern, where you define a contract in Kotlin and provide platform-specific implementations on the Swift side. This is especially useful when you need to use pure Swift libraries that can't be directly imported into Kotlin. To implement the pattern, declare a Kotlin superclass for the Swift implementation to inherit from and a Kotlin interface. Then implement this interface in Swift and pass the Swift object to Kotlin functions that accept that interface. For example, for the CryptoKit library: 1. On the Kotlin side, declare an interface, a function that accepts it, and an `open` base class: ```KOTLIN // Kotlin interface CryptoProvider { fun hashMD5(input: String): String } fun processHash(provider: CryptoProvider, input: String): String = provider.hashMD5(input) open class SwiftBase ``` 2. On the Swift side, inherit from the exported `SwiftBase` class, implement the interface using a pure Swift library, and pass the object back to Kotlin: ```SWIFT // Swift import CryptoKit final class IosCryptoProvider: SwiftBase, CryptoProvider { func hashMD5(input: String) -> String { guard let data = input.data(using: .utf8) else { return "failed" } return Insecure.MD5.hash(data: data).description } } let provider = IosCryptoProvider() // Calls the Kotlin function, which calls hashMD5() back in Swift print(processHash(provider: provider, input: "Hello, world!")) ``` When Kotlin receives a Swift object, it treats it like an implementation of a regular interface, calling the Swift code directly. For more details on Swift export, see our [documentation](native-swift-export.html). ### Improved incremental compilation of `klib` artifacts Kotlin 2.4.20 brings stabilization improvements to incremental compilation of `klib` artifacts, which is now [in Beta](components-stability.html#kotlin-native). This optimization was first introduced in [Kotlin 1.9.20](whatsnew1920.html#incremental-compilation-of-klib-artifacts) and proved to drastically reduce compilation time for debug builds. Since then, we've fixed a number of bugs and improved performance. To try out incremental compilation, add the following option to your `gradle.properties` file: ```PROPERTIES kotlin.incremental.native=true ``` We're actively collecting feedback and planning to enable incremental compilation by default for all projects in the next Kotlin releases. If you encounter any issues, please report them to our [issue tracker](https://kotl.in/issue). ## Kotlin/Wasm Kotlin 2.4.20 changes how Kotlin/Wasm handles top-level `require()` calls in `@JsFun` declarations, aligns companion object initialization order with JVM behavior, reduces binary size for functional interfaces, introduces new compilation modes, and adds support for Wasmtime as a runtime for the `wasmWasi` target in the Kotlin Gradle plugin. ### Changes to top-level `require()` calls in `@JsFun` declarations Kotlin/Wasm now reports an error when a [@JsFun](https://kotlinlang.org/api/core/kotlin-stdlib/kotlin/-js-fun/) declaration uses the top-level `require()` function. Previously, the compiler generated a `require` variable in the `import-object.mjs` file, allowing `@JsFun` declarations to call `require()`. This behavior unintentionally exposed a compiler implementation detail. To support migration away from it, Kotlin/Wasm removes this generated `require` declaration, and the compiler now reports errors for such calls. For example: ```KOTLIN // Reports an error @JsFun("(mod) => require(mod)") external fun loadModule(mod: String): JsAny ``` To prepare for this change, replace top-level `require()` calls in `@JsFun` declarations with the [@JsModule](https://kotlinlang.org/api/core/kotlin-stdlib/kotlin.js/-js-module/) annotation: ```KOTLIN @JsModule("module") external val module: Module external interface Module { // Defines the expected module members } ``` For dynamic module loading, use the `import()` expression instead. Add the `/* webpackIgnore: true */` magic comment to prevent webpack from parsing the dynamic import: ```KOTLIN @JsFun(""" ((module) => () => module)( await import(/* webpackIgnore: true */ "module") ) """) private external fun loadModuleDynamically(): JsAny? ``` You can also use the `import()` expression conditionally. For example, you can load a module only when running in Node.js: ```KOTLIN @JsFun(""" ((module) => () => module)( ((typeof process !== "undefined") && (process.release.name === "node")) ? await import(/* webpackIgnore: true */ "module") : null ) """) private external fun loadNodeModule(): JsAny? ``` If your project relies on dependencies that require a top-level `require()` function, add it as a property of `globalThis` as a workaround: ```KOTLIN @JsFun(""" ((module) => { globalThis.require = module.default.createRequire(import.meta.url) return () => {} })(await import("node:module")) """) external fun defineRequire() ``` If you run into any issues, share your feedback in our [issue tracker](https://youtrack.jetbrains.com/issue/KT-86192). ### Improved companion object initialization order Kotlin/Wasm now initializes superclass companion objects before subclass companion objects, matching the JVM behavior. Previously, the initialization could be reversed, leading to inconsistent behavior across platforms. The update improves cross-platform consistency and reduces platform-specific differences in class initialization behavior. It also enables correct handling of companion object initialization in deeper inheritance hierarchies, including cases where intermediate classes don't declare companion objects. ### Support for Wasmtime in the Kotlin Gradle plugin Kotlin 2.4.20 introduces support for [Wasmtime](https://docs.wasmtime.dev/) as a runtime for the `wasmWasi` target in the Kotlin Gradle plugin. Previously, the `wasmWasi` target supported only the Node.js runtime, which required a JavaScript bootstrap to run WASI applications. With Wasmtime support, you can now run Kotlin/Wasm applications on a standalone WebAssembly runtime. To use Wasmtime as the runtime for the `wasmWasi` target, add `wasmtime()` to your Gradle build file: ```KOTLIN kotlin { wasmWasi { wasmtime() } } ``` We would appreciate your feedback in [YouTrack](https://youtrack.jetbrains.com/issue/KT-86633). ### New compilation modes Kotlin 2.4.20 adds support for selecting a Kotlin/Wasm compilation mode, including new multi-module modes. Previously, the compiler used the monolith compilation mode, which compiles the project and its dependencies together and generates a single binary. This lets the compiler perform dead code elimination and produce the smallest output. You can now select one of the following compilation modes: | Compilation mode |Compilation |Output |Optimization behavior | ---------------------------------------------------------------- | `monolith` (default) |Compiles the project and its dependencies together. |A single binary |Removes unreachable declarations and applies optimizations for the entire program, including dependencies. | | `multimodule-open-world` |Compiles each module independently and recompiles only modules that change. |A separate, independent binary for each module |Doesn't apply cross-module optimizations, which results in larger binaries. | | `multimodule-closed-world` |Processes all modules in one invocation and recompiles only modules that change. |Separate binaries that depend on each other |Removes unreachable declarations but optimizes each Wasm binary independently. | To select a compilation mode, add the `kotlin.wasm.compilationMode` property to your `gradle.properties` file: ```PROPERTIES kotlin.wasm.compilationMode=multimodule-open-world ``` You can also configure Kotlin/Wasm to use closed-world multi-module compilation for development builds and monolith compilation for production builds. This reduces recompilation time during development and produces the smallest output for production builds. To use this configuration, add the following property to your `gradle.properties` file: ```PROPERTIES kotlin.wasm.compilationMode=multimodule-closed-world-only-in-dev ``` We would appreciate your feedback in [YouTrack](https://youtrack.jetbrains.com/issue/KT-86919). ### Reduced binary size for lambdas and functional interfaces Kotlin 2.4.20 changes how Kotlin/Wasm compiles lambdas and functional interfaces. Instead of generating separate anonymous classes, the compiler now generates functions and uses shared base classes. Tests with the [KotlinConf application](https://github.com/JetBrains/kotlinconf-app) show that this change reduces Wasm binary size by approximately 5–10%. Because the change introduces more dynamic calls, it may affect runtime performance. If you experience any issues, report them in our [issue tracker](https://youtrack.jetbrains.com/issue/KT-83159). ## Kotlin/JS Kotlin 2.4.20 improves exportability of data classes, introduces a new experimental DSL for browser testing, and adds support for exporting suspending lambdas as JavaScript async functions. ### Consistent exportability of synthetic functions on exported data classes Kotlin 2.4.20 fixes an issue which prevented the `@JsExport.Ignore` annotation from being properly applied to data class properties. Previously, when you marked a data class with the `@JsExport` annotation, the compiler still reported warnings about the data class exportability because of the automatically generated `copy()` and `componentN()` functions. This happened even if the constructor and the properties were explicitly marked as ignored with `@JsExport.Ignore`. For example, consider a `Session` data class exported to JavaScript that also has a reference to an internal `DatabaseConnection` type that isn't meant to be exported: ```KOTLIN // Kotlin // An internal type that isn't exported to JavaScript class DatabaseConnection @JsExport data class Session @JsExport.Ignore constructor( val userId: String, @JsExport.Ignore val connection: DatabaseConnection, ) ``` Now that the issue is fixed, the compiler accounts for `@JsExport.Ignore` annotations, so `Session`'s synthetic `copy()` and `componentN()` functions no longer trigger warnings about the non-exported type `DatabaseConnection`. This aligns with the visibility rules introduced by the [@ConsistentCopyVisibility and @ExposedCopyVisibility annotations](whatsnew2020.html#data-class-copy-function-to-have-the-same-visibility-as-constructor). ### A new DSL for browser testing Kotlin 2.4.20 introduces a new experimental DSL for running Kotlin/JS tests in a browser environment. Currently, the Kotlin Gradle plugin uses [Karma](https://github.com/karma-runner/karma) as a browser launcher to run JavaScript tests across different browsers. The Karma project has been deprecated for two years now, which has led us to explore alternative ways to support browser testing. The new DSL is intended to replace Karma as a manager of different tools under the hood and includes: * [Playwright](https://playwright.dev/) as a browser driver and a distribution manager that supports the Chromium, Firefox, and WebKit (Safari) browser engines. * [Mocha](https://mochajs.org/) as a test runner. * [webpack](https://webpack.js.org/) as a bundler (will be replaced with [Vite](https://vite.dev/) in [future releases](https://youtrack.jetbrains.com/issue/KT-48308/)). To try out the new DSL for browser testing, add the opt-in `test {}` block inside `browser {}` for your Kotlin/JS target: ```KOTLIN import org.jetbrains.kotlin.gradle.ExperimentalJsTestDsl import kotlin.time.Duration.Companion.seconds kotlin { js { browser { // Add and configure the new test {} block @OptIn(ExperimentalJsTestDsl::class) test { // Configure default timeout for all runners timeout = 2.seconds // Configure headless mode using Gradle providers headless = providers .environmentVariable("IS_IN_CI") .map { it.toBoolean() } .orElse(false) // Enable and configure Chromium test runner chromium { // Override the common timeout option timeout = 5.seconds // Add extra launch arguments launchArgs.add("--no-sandbox") } // Enable Firefox test runner firefox() // Enable WebKit test runner webkit() // Enable and configure an additional WebKit test runner webkit("noheadless") { // Set up custom options headless = false } } } } } ``` The new DSL for browser testing is in active development. We would appreciate your feedback in [YouTrack](https://youtrack.jetbrains.com/issue/KT-66897). For more information, see [Run tests in Kotlin/JS](js-running-tests.html). ### Support for exporting suspending lambdas as async functions With Kotlin 2.4.20, you can now export suspending [lambda expressions](lambdas.html#lambda-expressions-and-anonymous-functions) as JavaScript `async` functions. Previously, there was no way to export declarations containing suspending lambdas from Kotlin/JS libraries. Now the Kotlin compiler automatically handles the bridging between Kotlin's `suspend` functions and JavaScript's native [async/await](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/async_function) model, which is useful for mixed Kotlin/TypeScript codebases. To enable this feature, add the following compiler option to your `build.gradle.kts` file: ```KOTLIN kotlin { js { compilations.all { compileTaskProvider.configure { compilerOptions { freeCompilerArgs.add("-Xsuspend-lambda-exporting") } } } } } ``` Then, mark the relevant declarations with `@JsExport`: ```KOTLIN // Kotlin @JsExport class TaskRunner { suspend fun runTask(task: suspend () -> String): String { return task() } } ``` From the TypeScript side, the suspending lambda appears as a regular `async` function: ```TYPESCRIPT // TypeScript import { TaskRunner } from "..." const runner = new TaskRunner(); const result = await runner.runTask(async () => "done"); console.log(result); // "done" ``` For more information on the `@JsExport` annotation, see [our documentation](js-to-kotlin-interop.html#jsexport-annotation). ## Gradle Kotlin 2.4.20 is fully compatible with Gradle 7.6.3 through 9.7.0. You can also use Gradle versions up to the latest Gradle release. However, be aware that doing so may result in deprecation warnings, and some new Gradle features might not work. Kotlin 2.4.20 also comes with an improved integration with the Problems API. ### Improved reporting in Problems API Kotlin 2.2.0 was the first release in which the [Kotlin Gradle Plugin (KGP) integrated with Gradle's Problems API](whatsnew22.html#integration-of-problems-api-within-kgp-diagnostics). Kotlin 2.4.0 added support for [writing compiler messages to the Problems API for Kotlin/JVM](whatsnew24.html#compiler-messages-written-to-problems-api-for-kotlin-jvm). Kotlin 2.4.20 adds compiler diagnostic IDs to the information that the compiler passes to the [Problems API](https://docs.gradle.org/current/kotlin-dsl/gradle/org.gradle.api.problems/index.html). It also groups diagnostics by these IDs, making it easier to identify the source of compilation problems. Starting with Gradle 8.6, the KGP enables this integration by default. As the API is still evolving, use the most recent Gradle version to benefit from the latest improvements. ## Build tools API Kotlin 2.4.20 adds experimental support for Kotlin/JS, Kotlin/Wasm, and Kotlin metadata to the build tools API. ### Support for Kotlin/JS, Kotlin/Wasm, and Kotlin metadata In [Kotlin 2.2.0](whatsnew22.html#new-experimental-build-tools-api), the build tools API (BTA) became available for Kotlin/JVM. Kotlin 2.4.20 takes the next step toward BTA stabilization by adding support for new targets: Kotlin/JS, Kotlin/Wasm, and Kotlin metadata. This makes the Kotlin Gradle plugin interact with the compiler more consistently. In some cases, you can also benefit from faster, more stable compilation. The BTA is a universal API that acts as an abstraction layer between build systems and the Kotlin compiler ecosystem. It helps support Kotlin features and compatibility with the Kotlin compiler in available build tools. In Kotlin 2.4.20, BTA is available as an opt-in for the new targets. To try it out, add the corresponding properties to your `gradle.properties` file: ```PROPERTIES kotlin.wasm.runViaBuildToolsApi=true kotlin.js.runViaBuildToolsApi=true kotlin.metadata.runViaBuildToolsApi=true ``` Starting with Kotlin 2.5.0, we plan to enable BTA in Kotlin/JS, Kotlin/Wasm, and Kotlin metadata by default. If you're curious about the BTA proposal or want to share your feedback, see this [KEEP](https://github.com/Kotlin/KEEP/blob/build-tools-api/proposals/extensions/build-tools-api.md). ## Kotlin compiler Kotlin 2.4.20 includes an update about the changed Kotlin runner command, `kotlinr`, and introduces an experimental Kotlin compiler native image. ### Changed the Kotlin runner command from `kotlin` to `kotlinr` The `kotlinr` command replaces `kotlin` as the Kotlin runner command to avoid a naming conflict with the `kotlin` command in the [Kotlin Toolchain](https://kotlin-toolchain.org/latest/). The Kotlin runner also warns you when you use the `kotlin` command and recommends `kotlinr` instead. ### Native image Kotlin 2.4.20 features the first [Experimental](components-stability.html#stability-levels-explained) release of the Kotlin compiler native image. The native image provides a drop-in replacement for the standard `kotlinc` command-line tool, while offering faster startup time and higher performance. To try out the native image, download the build from [GitHub Releases](https://github.com/JetBrains/kotlin/releases/tag/v2.4.20). The native image also bundles the following compiler plugins you can use with the `-Xplugin` or `-Xcompiler-plugin` CLI options: * [Serialization](serialization.html) * [Compose compiler](compose-compiler-options.html) * [All-open](all-open-plugin.html) * [no-arg](no-arg-plugin.html) * [SAM with receiver](sam-with-receiver-plugin.html) * [Assignment](https://plugins.gradle.org/plugin/org.jetbrains.kotlin.plugin.assignment) * [Lombok](lombok.html) * [Power-assert](power-assert.html) For more information on the Kotlin compiler native image, see its [README](https://github.com/JetBrains/kotlin/blob/master/prepare/compiler-native-image/README.md). ## Breaking changes and deprecations This section highlights important breaking changes and deprecations. For a complete overview, see our [Compatibility guide](compatibility-guide-24.html). * Since Apple is dropping support for its 32-bit watchOS targets, the `watchosArm32` [Kotlin/Native](native-target-support.html) target is now deprecated. It's planned for removal in Kotlin 2.5.0 to ensure compatibility with Xcode 27. * Starting with Kotlin 2.4.20, the Kotlin/Native compiler prohibits AtomicFU atomic operations inside a `public` inline function or inside an `internal` inline function called from another file. * Kotlin 2.4.20 updates the npm dependency for webpack to 5.108.1. This can affect your project in two ways: * webpack has moved its built-in minimizer dependency from `terser-webpack-plugin` to the broader [minimizer-webpack-plugin](https://www.npmjs.com/package/minimizer-webpack-plugin). Terser remains the default JavaScript minimizer, but if your project configures or depends on `terser-webpack-plugin` directly, you may need to update its configuration. * webpack no longer ignores `import.meta` when determining a JavaScript file's module type. If `import.meta` is present, webpack treats the file as an ES module, which can break files that also use CommonJS constructs. For Kotlin/JS, you can [configure the target to use ES modules with the useEsModules() Gradle DSL](js-modules.html#choose-the-target-module-system). Kotlin/Wasm should work in most cases without additional configuration. If you encounter an `import.meta` error with Kotlin/Wasm, check whether your project's sources or a direct or transitive dependency uses `import.meta`. Update your own code as needed. If a dependency causes the issue, update it to a compatible version if one is available, or report the issue to the library maintainers. * Starting with Kotlin 2.4.20, Kotlin/Wasm deprecates the generated JavaScript `wasmExports` API. The compiler prohibits access to all exports except `wasmExports.memory`, which remains temporarily available with a warning. Use the `kotlin.wasm.unsafe.wasmMemory` property to access the module's `WebAssembly.Memory` object. ## Documentation updates Since the last release, we've created new pages and tutorials for the Kotlin ecosystem documentation and revamped existing ones: * [Configure an iOS delivery pipeline](https://kotlinlang.org/docs/multiplatform/ios-ci-cd-teamcity.html) – Set up continuous delivery for a Kotlin Multiplatform iOS app with TeamCity. * Compose Multiplatform updates: * [Popups](https://kotlinlang.org/docs/multiplatform/compose-popups.html) – Learn how to create and configure popups in Compose Multiplatform. * [Window and dialog API v2](https://kotlinlang.org/docs/multiplatform/compose-desktop-top-level-windows-management.html#window-and-dialog-api-v2) – Explore the new API for managing desktop windows and dialogs in Compose Multiplatform. * [Tray and notifications](https://kotlinlang.org/docs/multiplatform/compose-desktop-tray.html) – Learn how to add an application icon to the system tray and send system notifications in Compose Multiplatform for desktop. * [Menu bar](https://kotlinlang.org/docs/multiplatform/compose-desktop-menu-bar.html) – Learn how to create a menu bar for a specific window in Compose Multiplatform for desktop. * [Drag and drop](https://kotlinlang.org/docs/multiplatform/compose-drag-drop.html#platform-specific-data-handling) – Handle platform-specific data when implementing drag and drop in Compose Multiplatform. * [UIKit alternative for Liquid Glass](https://kotlinlang.org/docs/multiplatform/ios-liquid-glass.html#alternative-skip-swiftui-and-drive-uikit-from-kotlin) – Explore an alternative approach to Liquid Glass that uses UIKit navigation instead of SwiftUI. * [MCP server for AI agents](https://kotlinlang.org/docs/multiplatform/compose-hot-reload.html#mcp-server-for-ai-agents) – Learn how to use the MCP server in Compose Hot Reload to connect AI agents to your development workflow. * [Caching with Spring](https://spring.io/guides/gs/caching) – Learn how to add caching to a Spring application with new Kotlin examples. * [Exposed IntelliJ IDEA plugin](https://www.jetbrains.com/help/idea/exposed.html) – Learn how to work with Exposed in IntelliJ IDEA using code completion, database-aware inspections, and live templates. * [Kotlin serialization](serialization.html) – Learn how to serialize Kotlin data, customize JSON structure and type representation, and work with more advanced serialization scenarios. * [Flow](coroutines-flow.html) and [Flow operators](coroutines-flow-operators.html) – Learn how to create and collect cold and hot flows, handle exceptions, and use a wide range of flow operators. * [Debug coroutines](coroutines-debugging.html) – Learn how to debug coroutines on the JVM using debug mode, stack trace recovery, and the debug agent. * Lincheck – Learn how [model checking](lincheck-model-checking.html) works in Lincheck, how to use [operation execution options](lincheck-operation-execution-options.html), and how to [verify](lincheck-results-validation.html) the test results. * [kapt compiler plugin](kapt.html) – Learn how to configure the kapt compiler plugin in Gradle, Maven, and the command-line compiler. * [Code quality tools in Kotlin projects](jvm-code-analysis.html) – Explore tools for analyzing JVM bytecode and Kotlin code. * [Power-assert plugin with Maven](jvm-test-maven.html#get-detailed-failure-messages) – Learn how to use the Power-assert plugin to get more detailed test failure messages. * [Multiple-round processing with KSP](ksp-multi-round.html) – Explore how KSP works across multiple processing rounds, including generated files, deferred symbols, and validation. * Non-denotable types – Learn about [platform types](java-interop.html#null-safety-and-platform-types), [captured types](generics.html#captured-types), and [intersection types](typecasts.html#intersection-types) in Kotlin. * [Type aliases](type-aliases.html) – Learn about type alias scope and visibility. * [This expressions](this-expressions.html) – Learn how implicit `this` is resolved and when to use `this` explicitly to refer to a receiver. * [Strings](strings.html) – Learn about string templates, common string operations, building strings, and type conversion. * [Packages and imports](packages.html) – Learn how to organize Kotlin code using packages and imports. # What's new in Kotlin 2.4.20-RC3 [Released: September 2, 2026](eap.html#build-details) Note: This document doesn't cover all of the features of the Early Access Preview (EAP) release, but it highlights some major improvements. See the full list of changes in the [GitHub changelog](https://github.com/JetBrains/kotlin/releases/tag/v2.4.20-RC3). The Kotlin 2.4.20-RC3 release is out! Here are some details of this EAP release: * Standard library: [Support for coroutine stack trace recovery and new features for checking equality and uniqueness of collection elements](#standard-library) * Kotlin/Native: [New Swift export features and automatically generated Package.swift files for SwiftPM dependencies](#kotlin-native) * Kotlin/Wasm: [Changes to top-level require() calls in @JsFun declarations, improved companion object initialization order, and support for Wasmtime in the Kotlin Gradle plugin](#kotlin-wasm) * Kotlin/JS: [New DSL for browser testing and support for exporting suspend lambdas as async functions](#kotlin-js) * Build tools API: [Support for new targets: Kotlin/JS, Kotlin/Wasm, and Kotlin metadata](#build-tools-api) * Kotlin compiler: [Experimental release of the native image](#kotlin-compiler-native-image) Tip: For information about the Kotlin release cycle, see [Kotlin release process](releases.html). ## Update to Kotlin 2.4.20-RC3 The latest version of Kotlin is included in the latest versions of [IntelliJ IDEA](https://www.jetbrains.com/idea/download/) and [Android Studio](https://developer.android.com/studio). To update to the new Kotlin version, make sure your IDE is updated to the latest version and [change the Kotlin version](releases.html#update-to-a-new-kotlin-version) to 2.4.20-RC3 in your build scripts. ## New features The following pre-stable features are available in this release. This includes features with [Beta](components-stability.html#stability-levels-explained), [Alpha](components-stability.html#stability-levels-explained), and [Experimental](components-stability.html#stability-levels-explained) status: * [Standard library: Support for coroutine stack trace recovery](#support-for-coroutine-stack-trace-recovery) * [Standard library: New functions to check collection elements for equality and uniqueness](#new-functions-to-check-collection-elements-for-equality-and-uniqueness) * [Kotlin/JS: New DSL for browser testing](#a-new-dsl-for-browser-testing) * [Build tools API: Support for Kotlin/JS, Kotlin/Wasm, and Kotlin metadata](#build-tools-api) * [Kotlin compiler: Separate Kotlin compiler image](#kotlin-compiler-native-image) ## Standard library Kotlin 2.4.20-RC3 adds support for coroutine stack trace recovery and introduces new functions to check collection elements for equality and uniqueness. ### Support for coroutine stack trace recovery Kotlin 2.4.20-RC3 adds the `StackTraceRecoverable` interface to the standard library. This improves integration with the `kotlinx.coroutines` library because it lets you define how to create new exception instances for stack trace recovery without adding a dependency on `kotlinx.coroutines`. Stack trace recovery helps with debugging when one coroutine throws an exception and another rethrows it. It lets you see where the exception originates and where another coroutine rethrows it. The `kotlinx.coroutines` library performs stack trace recovery by creating a new exception instance with additional coroutine stack trace information. This happens automatically for exceptions with constructors that take only an exception message, a cause, both, or no arguments. If an exception constructor has additional required arguments, such as a line number or an error code, implement the `StackTraceRecoverable` interface to define how the `kotlinx.coroutines` library creates a new instance of that exception. To implement the interface, override the `copyForStackTraceRecovery()` function. In the override, return a new exception instance for stack trace recovery, or `null` if you don't want the `kotlinx.coroutines` library to copy the exception. Note: The `StackTraceRecoverable` interface is available on all targets, but the `kotlinx.coroutines` library uses it for stack trace recovery only on the JVM. These APIs are [Experimental](components-stability.html#stability-levels-explained) and require opt-in with the `@OptIn(ExperimentalStdlibCoroutineSupportApi::class)` annotation. Here's an example of a custom exception that preserves a `line` property when it creates a new instance for stack trace recovery: ```KOTLIN import kotlin.coroutines.ExperimentalStdlibCoroutineSupportApi import kotlin.coroutines.debug.StackTraceRecoverable @OptIn(ExperimentalStdlibCoroutineSupportApi::class) class FileEditException // The implementation requires a private constructor // to pass the cause to the IllegalStateException constructor private constructor( val line: Int, private val detail: String, cause: Throwable?, ) : IllegalStateException("When editing line $line: $detail", cause), // Implements StackTraceRecoverable for stack trace recovery StackTraceRecoverable { constructor(line: Int, detail: String) : this(line, detail, null) // Copies the line number and message details override fun copyForStackTraceRecovery(): FileEditException = FileEditException(line, detail, this) } fun main() { val original = FileEditException(15, "Unexpected token") // Normally, you don't need to call this function directly unless you're testing its behavior // The kotlinx.coroutines library invokes it automatically during stack trace recovery val copy = original.copyForStackTraceRecovery() println(copy.message) // When editing line 15: Unexpected token println(copy.cause == original) // true } ``` For more information, see the feature's [KEEP](https://github.com/Kotlin/KEEP/blob/main/proposals/stdlib/KEEP-0461-stacktrace-recoverable.md). We would appreciate your feedback in [YouTrack](https://youtrack.jetbrains.com/issue/KT-86595). ### New functions to check collection elements for equality and uniqueness Before Kotlin 2.4.20-RC3, if you wanted to check whether collection elements were all distinct or all equal, you had to use inefficient code patterns. Kotlin 2.4.20-RC3 introduces experimental functions to fill this gap: | Function |Checks | -------------------- | `.allDistinct()` |Every value in the collection is unique. | | `.allDistinctBy()` |Every object has a unique value for the selected property. | | `.allEqual()` |Every value in the collection is the same. | | `.allEqualBy()` |Every object has the same value for the selected property. | You can use these functions on collections, sequences, and arrays. They compare elements using structural equality just like other collection operations. These functions are [Experimental](components-stability.html#stability-levels-explained) and require opt-in with the `@OptIn(ExperimentalStdlibApi::class)` annotation or the `-opt-in=kotlin.ExperimentalStdlibApi` compiler option: ```KOTLIN @OptIn(ExperimentalStdlibApi::class) fun main() { data class Response( val participantId: String, val answer: String, val responseDate: String ) val responses = listOf( Response("P001", "Yes", "2026-07-21"), Response("P002", "Maybe", "2026-07-21"), Response("P003", "No", "2026-07-21") ) // Checks if all participants gave the same answer println(responses.allEqualBy { it.answer }) // false // Checks for duplicate participants println(responses.allDistinctBy { it.participantId }) // true // Checks if all responses were submitted on the same date println(responses.allEqualBy { it.responseDate }) // true val answers = responses.map { it.answer } // Checks if answers are identical println(answers.allEqual()) // false // Checks if answers are distinct println(answers.allDistinct()) // true } ``` We would appreciate hearing your feedback on your experience with these functions in [YouTrack](https://youtrack.jetbrains.com/issue/KT-30270). ## Kotlin/Native Kotlin 2.4.20-RC3 brings new Swift export features, including support for sealed classes and cross-language inheritance, and automatic generation of `Package.swift` files for SwiftPM dependencies. ### New Swift export features #### Sealed classes Kotlin 2.4.20-RC3 adds support for sealed classes and interfaces to Swift export. Previously, you had to write a `default` case for every `switch` statement over a sealed type. Now, sealed hierarchies defined in Kotlin are mapped to Swift enums, enabling exhaustive `switch` statements with full autocompletion in Xcode. Swift export generates a `.sealedType()` method on each sealed type. This method returns a Swift enum whose cases match the direct subclasses of the sealed hierarchy. You can nest these calls to match deeper levels of the hierarchy. For example, declare a sealed interface with a class hierarchy in Kotlin: ```KOTLIN // Kotlin sealed interface Shape class Circle : Shape { override fun toString(): String = "Circle" } class Rectangle : Shape { override fun toString(): String = "Rectangle" } fun createCircle(): Shape = Circle() ``` On the Swift side, you can use an exhaustive `switch` without a `default` case: ```SWIFT // Swift let shape = createCircle() let name = switch shape.sealedType() { case let .circle(type): "It's a \(type.value)" case let .rectangle(type): "It's a \(type.value)" } // name == "It's a Circle" ``` Because the `switch` is exhaustive, the compiler warns you if a new subclass is added to the sealed hierarchy, so you can handle it immediately instead of relying on a `default` case. #### Cross-language inheritance in Swift export Kotlin 2.4.20-RC3 introduces cross-language inheritance support to Swift export. A common use case for this feature is the [reverse import](native-lib-import-stability.html#swift-library-import) pattern, where you define a contract in Kotlin and provide platform-specific implementations on the Swift side. This is especially useful when you need to use pure Swift libraries that can't be directly imported into Kotlin. To implement the pattern, declare a Kotlin superclass for the Swift implementation to inherit from and a Kotlin interface. Then implement the interface in Swift and pass the Swift object to Kotlin functions that accept that interface. For example, for the CryptoKit library: 1. On the Kotlin side, declare an `open` base class and a Kotlin interface with a function that accepts it: ```KOTLIN // Kotlin interface CryptoProvider { fun hashMD5(input: String): String } fun processHash(provider: CryptoProvider, input: String): String = provider.hashMD5(input) open class SwiftBase ``` 2. On the Swift side, inherit from the exported `SwiftBase` class, implement the interface using a pure Swift library, and pass the object back to Kotlin: ```SWIFT // Swift import CryptoKit final class IosCryptoProvider: SwiftBase, CryptoProvider { func hashMD5(input: String) -> String { guard let data = input.data(using: .utf8) else { return "failed" } return Insecure.MD5.hash(data: data).description } } let provider = IosCryptoProvider() // The call is dispatched to the Swift implementation print(processHash(provider: provider, input: "Hello, world!")) ``` When Kotlin receives a Swift object, it treats it like an implementation of a regular interface, executing Swift code. For more details on Swift export, see our [documentation](native-swift-export.html). ### Generated `Package.swift` for SwiftPM dependencies When exporting an XCFramework that depends on SwiftPM packages, you must publish the resulting SwiftPM package for it to resolve correctly. To help with this, the `assembleSharedXCFramework` Gradle task now generates a `Package.swift` file to be distributed along with the XCFramework. For details, see the [SwiftPM export page](https://kotlinlang.org/docs/multiplatform/multiplatform-spm-export.html). ## Kotlin/Wasm Kotlin 2.4.20-RC3 changes how Kotlin/Wasm handles top-level `require()` calls in `@JsFun` declarations, aligns companion object initialization order with JVM behavior, and adds support for Wasmtime as a runtime for the `wasmWasi` target in the Kotlin Gradle plugin. ### Changes to top-level `require()` calls in `@JsFun` declarations Kotlin/Wasm now reports an error when a `@JsFun` declaration uses the top-level `require()` function. Previously, the compiler generated a `require` variable in the `import-object.mjs` file, allowing `@JsFun` declarations to call `require()`. This behavior unintentionally exposed a compiler implementation detail. To support migration away from it, Kotlin/Wasm removes this generated `require` declaration, and the compiler now reports errors for such calls. For example: ```KOTLIN // Reports an error @JsFun("(mod) => require(mod)") external fun loadModule(mod: String): JsAny ``` To prepare for this change, replace top-level `require()` calls in `@JsFun` declarations with the `@JsModule` annotation: ```KOTLIN @JsModule("module") external val module: Module external interface Module { // Defines the expected module members } ``` For dynamic module loading, use the `import()` expression instead. Add the `/* webpackIgnore: true */` magic comment to prevent webpack from parsing the dynamic import: ```KOTLIN @JsFun(""" ((module) => () => module)( await import(/* webpackIgnore: true */ "module") ) """) private external fun loadModuleDynamically(): JsAny? ``` You can also use the `import()` expression conditionally. For example, you can load a module only when running in Node.js: ```KOTLIN @JsFun(""" ((module) => () => module)( ((typeof process !== "undefined") && (process.release.name === "node")) ? await import(/* webpackIgnore: true */ "module") : null ) """) private external fun loadNodeModule(): JsAny? ``` If your project relies on dependencies that require a top-level `require()` function, add it as a property of `globalThis` as a workaround: ```KOTLIN @JsFun(""" ((module) => { globalThis.require = module.default.createRequire(import.meta.url) return () => {} })(await import("node:module")) """) external fun defineRequire() ``` If you run into any issues, share your feedback in our [issue tracker](https://youtrack.jetbrains.com/projects/KT/issues/KT-86192). ### Improved companion object initialization order Kotlin/Wasm now initializes superclass companion objects before subclass companion objects, matching the JVM behavior. Previously, the initialization could be reversed, leading to inconsistent behavior across platforms. The update improves cross-platform consistency and reduces platform-specific differences in class initialization behavior. It also enables correct handling of companion object initialization in deeper inheritance hierarchies, including cases where intermediate classes don't declare companion objects. ### Support for Wasmtime in the Kotlin Gradle plugin Kotlin 2.4.20-RC3 introduces support for [Wasmtime](https://docs.wasmtime.dev/) as a runtime for the `wasmWasi` target in the Kotlin Gradle plugin. Previously, the `wasmWasi` target supported only the Node.js runtime, which required a JavaScript bootstrap to run WASI applications. With Wasmtime support, you can now run Kotlin/Wasm applications on a standalone WebAssembly runtime. To use Wasmtime as the runtime for the `wasmWasi` target, add `wasmtime()` to your Gradle build file: ```KOTLIN kotlin { wasmWasi { wasmtime() } } ``` We would appreciate your feedback in [YouTrack](https://youtrack.jetbrains.com/issue/KT-86633). ## Kotlin/JS Kotlin 2.4.20-RC3 introduces a new experimental DSL for browser testing and adds support for exporting suspending lambdas as JavaScript async functions. ### A new DSL for browser testing Kotlin 2.4.20-RC3 introduces a new experimental DSL for running Kotlin/JS tests in a browser environment. Currently, the Kotlin Gradle plugin uses [Karma](https://github.com/karma-runner/karma) as a browser launcher to run JavaScript tests across different browsers. The Karma project has been deprecated for two years now, which has led us to explore alternative ways to support browser testing. The new DSL is intended to replace Karma as a manager of different tools under the hood and includes: * [Mocha](https://mochajs.org/) as a test runner. * [Webpack](https://webpack.js.org/) as a bundler (will be replaced with [Vite](https://vite.dev/) in [future releases](https://youtrack.jetbrains.com/issue/KT-48308/)). * [Playwright](https://playwright.dev/) as a browser driver and a distribution manager that supports the Chromium, Firefox, and WebKit (Safari) browser engines. To try out the new testing DSL, add the opt-in `test{}` block inside `browser{}` for your Kotlin/JS target: ```KOTLIN import org.jetbrains.kotlin.gradle.ExperimentalJsTestDsl import kotlin.time.Duration.Companion.seconds kotlin { js { browser { @OptIn(ExperimentalJsTestDsl::class) // Add and configure the new test{} block test { // Configure default timeout for all runners timeout = 2.seconds // Configure headless mode using Gradle providers headless = providers .environmentVariable("IS_IN_CI") .map { it.toBoolean() } .orElse(false) // Enable and configure Chromium test runner chromium { // Override the common timeout option timeout = 5.seconds // Add extra launch arguments launchArgs.add("--no-sandbox") } // Enable Firefox test runner firefox() // Enable WebKit test runner webkit() // Enable and configure an additional WebKit test runner webkit("noheadless") { // Set up custom options headless = false } } } } } ``` The new DSL is in active development. We would appreciate your feedback in [YouTrack](https://youtrack.jetbrains.com/issue/KT-66897). ### Support for exporting suspending lambdas as async functions With Kotlin 2.4.20-RC3, you can now export suspending [lambda expressions](lambdas.html#lambda-expressions-and-anonymous-functions) as JavaScript `async` functions. Previously, there was no way to export declarations containing suspending lambdas from Kotlin/JS libraries. Now the Kotlin compiler automatically handles the bridging between Kotlin's `suspend` functions and JavaScript's native [async/await](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/async_function) model, which is useful for mixed Kotlin/TypeScript codebases. To enable this feature, add the following compiler option to your `build.gradle.kts` file: ```KOTLIN kotlin { js { compilations.all { compileTaskProvider.configure { compilerOptions { freeCompilerArgs.add("-Xsuspend-lambda-exporting") } } } } } ``` Then, mark the relevant declarations with `@JsExport`: ```KOTLIN // Kotlin @JsExport class TaskRunner { suspend fun runTask(task: suspend () -> String): String { return task() } } ``` From the TypeScript side, the suspending lambda appears as a regular `async` function: ```TYPESCRIPT // TypeScript import { TaskRunner } from "..." const runner = new TaskRunner(); const result = await runner.runTask(async () => "done"); console.log(result); // "done" ``` For more information on the `@JsExport` annotation, see [our documentation](js-to-kotlin-interop.html#jsexport-annotation). ## Build tools API ### Support for Kotlin/JS, Kotlin/Wasm, and Kotlin metadata In [Kotlin 2.2.0](whatsnew22.html#new-experimental-build-tools-api), the build tools API (BTA) became available for Kotlin/JVM. Kotlin 2.4.20-RC3 takes the next step toward BTA stabilization by adding support for new targets: Kotlin/JS, Kotlin/Wasm, and Kotlin metadata. This makes the Kotlin Gradle plugin interact with the compiler more consistently. In some cases, you can also benefit from faster, more stable compilation. The BTA is a universal API that acts as an abstraction layer between build systems and the Kotlin compiler ecosystem. It helps support Kotlin features and compatibility with the Kotlin compiler in available build tools. In Kotlin 2.4.20-RC3, BTA is available as an opt-in for the new targets. To try it out, add the corresponding properties to your `gradle.properties` file: ```PROPERTIES kotlin.wasm.runViaBuildToolsApi=true kotlin.js.runViaBuildToolsApi=true kotlin.metadata.runViaBuildToolsApi=true ``` Starting with Kotlin 2.5.0, we plan to enable BTA in Kotlin/JS, Kotlin/Wasm, and Kotlin metadata by default. If you're curious about the BTA proposal or want to share your feedback, see this [KEEP](https://github.com/Kotlin/KEEP/blob/build-tools-api/proposals/extensions/build-tools-api.md). ## Kotlin compiler: Native image Kotlin 2.4.20-RC3 features the first [Experimental](components-stability.html#stability-levels-explained) release of the Kotlin compiler native image. The native image provides a drop-in replacement for the standard `kotlinc` command-line tool, while offering faster startup time and higher performance. To try out the native image, download the build from [GitHub Releases](https://github.com/JetBrains/kotlin/releases/tag/v2.4.20-RC3). The native image also bundles the following compiler plugins you can use with the `-Xplugin` or `-Xcompiler-plugin` CLI options: * [Serialization](serialization.html) * [Compose compiler](compose-compiler-options.html) * [All-open](all-open-plugin.html) * [no-arg](no-arg-plugin.html) * [SAM with receiver](sam-with-receiver-plugin.html) * [Assignment](https://plugins.gradle.org/plugin/org.jetbrains.kotlin.plugin.assignment) * [Lombok](lombok.html) * [Power-assert](power-assert.html) For more information on the Kotlin compiler native image, see its [README](https://github.com/JetBrains/kotlin/blob/master/prepare/compiler-native-image/README.md). # What's new in Kotlin 2.4.0 For details about bug fix release 2.4.10, see the [changelog](https://github.com/JetBrains/kotlin/releases/tag/v2.4.10) [Released: July 14, 2026](releases.html#release-history) The Kotlin 2.4.0 release is out! Here are the main highlights: * Language: [Stable context parameters, explicit backing fields, and multiple features for annotation use-site targets](#stable-features) * Standard library: [Stabilized support for the UUID API](#stable-uuid-api-in-the-common-kotlin-standard-library) and [support for checking sorted order](#support-for-checking-sorted-order) * Kotlin/JVM: [Support for Java 26](#support-for-java-26) and [annotations in metadata enabled by default](#annotations-in-metadata-enabled-by-default) * Kotlin/Native: [Support for Swift packages as dependencies, updates on Swift export, and the CMS GC enabled by default](#kotlin-native) * Kotlin/Wasm: [Incremental compilation enabled by default and support for WebAssembly Component Model](#kotlin-wasm) * Kotlin/JS: [Support for value class export and ES2015 features in JS code inlining](#kotlin-js) * Gradle: [Compatibility with Gradle 9.5.0](#gradle) * Maven: [Automatic alignment between Java and JVM target versions](#maven) * Kotlin compiler: [More consistent inline function behavior during .klib compilation](#consistent-intra-module-function-inlining-during-klib-compilation) You can also find an overview of the updates in this video: [Video: What's New in Kotlin 2.4](https://www.youtube.com/v/RI4J0C2_FR8) Tip: For information about the Kotlin release cycle, see the [Kotlin release process](releases.html). ## Update to Kotlin 2.4.0 The latest version of Kotlin is included in the latest versions of [IntelliJ IDEA](https://www.jetbrains.com/idea/download/) and [Android Studio](https://developer.android.com/studio). To update to the new Kotlin version, make sure your IDE is updated to the latest version and [change the Kotlin version](releases.html#update-to-a-new-kotlin-version) to 2.4.0 in your build scripts. ## New features In previous Kotlin releases, several new features were introduced as Experimental. The following features have now graduated to [Stable](components-stability.html#stability-levels-explained) in Kotlin 2.4.0, so you no longer need to opt in to use them: * [Context parameters](context-parameters.html), except for [context arguments](#explicit-context-arguments-for-context-parameters) and [callable references](https://github.com/Kotlin/KEEP/blob/context-parameters/proposals/context-parameters.md#callable-references) * [@all meta-target for properties](annotations.html#all-meta-target) * [New defaulting rules for use-site annotation targets](annotations.html#defaults-when-no-use-site-targets-are-specified) * [Explicit backing fields](properties.html#explicit-backing-fields) * [Stable UUID API in the common Kotlin standard library](#stable-uuid-api-in-the-common-kotlin-standard-library) * [New API for converting unsigned integers to BigInteger on the JVM](#new-api-for-converting-unsigned-integers-to-biginteger-on-the-jvm) * [Support for checking sorted order](#support-for-checking-sorted-order) * [Support for value class export to JavaScript/TypeScript](#support-for-value-class-export-to-javascript-typescript) * [Support for ES2015 features when inlining JS code](#support-for-es2015-features-when-inlining-js-code) * [Maven: Automatic alignment between Java and JVM target versions](#automatic-alignment-between-java-and-jvm-target-versions) * [Support for Maven Toolchains](#support-for-maven-toolchains) ## New features * [Explicit context arguments for context parameters](#explicit-context-arguments-for-context-parameters) * [Support for collection literals](#support-for-collection-literals) * [Improved compile-time constants](#improved-compile-time-constants) * [Improved unused result checks for higher-order functions](#improved-unused-result-checks-for-higher-order-functions) * [New @IntroducedAt annotation to generate version-based overloads for optional parameters](#new-introducedat-annotation-to-generate-version-based-overloads-for-optional-parameters) * [New map fallback functions to distinguish null values and missing keys](#new-map-fallback-functions-to-distinguish-null-values-and-missing-keys) * [Swift package import](#swift-package-import) * [Swift export goes Alpha with improved concurrency support](#swift-export-goes-alpha-with-improved-concurrency-support) * [Support for the WebAssembly Component Model](#support-for-the-webassembly-component-model) ## Language Kotlin 2.4.0 promotes context parameters, explicit backing fields, and annotation use-site targets features to [Stable](components-stability.html#stability-levels-explained). This release also introduces [explicit context arguments for context parameters](#explicit-context-arguments-for-context-parameters). ### Stable features Kotlin 2.2.0 and 2.3.0 introduced a few language features as [Experimental](components-stability.html#stability-levels-explained). We're happy to announce that the following language features are now [Stable](components-stability.html#stability-levels-explained) in this release: * [Context parameters](whatsnew22.html#preview-of-context-parameters), except for [context arguments](#explicit-context-arguments-for-context-parameters) and [callable references](https://github.com/Kotlin/KEEP/blob/context-parameters/proposals/context-parameters.md#callable-references) * [@all meta-target for properties](annotations.html#all-meta-target) * [New defaulting rules for use-site annotation targets](annotations.html#defaults-when-no-use-site-targets-are-specified) * [Explicit backing fields](properties.html#explicit-backing-fields) [See the full list of Kotlin language design features and proposals](kotlin-language-features-and-proposals.html). ### No more deprecation warnings on the last segments of imports In previous Kotlin versions, when a deprecated class was imported, the deprecation error was reported at the call site as well as at the import directive itself. As there's no way to suppress deprecation errors on imports, you may have worked around this by suppressing deprecation reports for the entire file or by using star imports. Since reporting the deprecation on the import of a called symbol isn't useful in most cases, Kotlin 2.4.0 doesn't issue a warning when the deprecated symbol is referenced in the last segment of the import directive. For more information, see [KT-30155](https://youtrack.jetbrains.com/issue/KT-30155). ### Explicit context arguments for context parameters Kotlin 2.4.0 introduces explicit context arguments for [context parameters](context-parameters.html). Kotlin 2.3.20 [changed the overload resolution for context parameters](whatsnew2320.html#changes-to-overload-resolution-for-context-parameters). As a result, calls to overloads that differ only by context parameters can become ambiguous. You can now resolve this ambiguity by passing an explicit context argument at the call site. Here's an example: ```KOTLIN class EmailSender class SmsSender context(emailSender: EmailSender) fun sendNotification() { println("Sent email notification") } context(smsSender: SmsSender) fun sendNotification() { println("Sent SMS notification") } context(defaultEmailSender: EmailSender, defaultSmsSender: SmsSender) fun notifyUser() { // Selects the overload with the EmailSender context parameter sendNotification(emailSender = defaultEmailSender) // Selects the overload with the SmsSender context parameter sendNotification(smsSender = defaultSmsSender) } ``` You can also use explicit context arguments instead of the `context()` function to reduce nesting and make some calls easier to read. If you need to use the same context arguments in multiple calls, use the `context()` function instead. This feature is [Experimental](components-stability.html#stability-levels-explained). To opt in, add the following compiler option to your build file: Gradle: ```KOTLIN kotlin { compilerOptions { freeCompilerArgs.add("-Xexplicit-context-arguments") } } ``` Maven: ```XML org.jetbrains.kotlin kotlin-maven-plugin -Xexplicit-context-arguments ``` For more information, see the feature's [KEEP](https://github.com/Kotlin/KEEP/blob/main/proposals/KEEP-0448-explicit-context-arguments.md). ### Support for collection literals Kotlin 2.4.0 introduces experimental support for collection literals. You can now create collections in a simpler and more concise way using brackets `[]`. For example: ```KOTLIN fun main() { // Mutable list with explicit type declaration // val shapes: MutableList = mutableListOf("triangle", "square", "circle") // Mutable list with brackets syntax val shapes: MutableList = ["triangle", "square", "circle"] println(shapes) // [triangle, square, circle] } ``` Note: Currently, collection literals can't be used to construct collections defined in Java. For more information, see [KT-80494](https://youtrack.jetbrains.com/issue/KT-80494). If the compiler doesn't have enough information to infer the collection type, it defaults to the `List` type: ```KOTLIN fun main() { val fruit = ["apple", "banana", "cherry"] println(fruit) // [apple, banana, cherry] } ``` You can also declare custom `operator fun of` functions to use bracket syntax with your own types. For example, if you have the following `DoubleMatrix` class: ```KOTLIN class DoubleMatrix(vararg val rows: Row) { companion object { operator fun of(vararg rows: Row) = DoubleMatrix(*rows) } class Row(vararg val elements: Double) { companion object { operator fun of(vararg elements: Double) = Row(*elements) } } } ``` You can create an `identityMatrix` class instance like this: ```KOTLIN fun main() { val identityMatrix: DoubleMatrix = [ [1.0, 0.0, 0.0], [0.0, 1.0, 0.0], [0.0, 0.0, 1.0], ] } ``` In this example, the compiler translates the nested collection literals into calls to the corresponding `operator fun of` functions. The compiler resolves these calls recursively and uses the expected types to choose the correct overloads. This feature is [Experimental](components-stability.html#stability-levels-explained). To opt in, add the following compiler option to your build file: Gradle: ```KOTLIN kotlin { compilerOptions { freeCompilerArgs.add("-Xcollection-literals") } } ``` Maven: ```XML org.jetbrains.kotlin kotlin-maven-plugin -Xcollection-literals ``` For more information, see the feature's [KEEP](https://github.com/Kotlin/KEEP/blob/main/proposals/KEEP-0416-collection-literals.md). ### Improved compile-time constants Kotlin 2.4.0 brings experimental improvements to [compile-time constants](properties.html#compile-time-constants), making support for numeric and string types more consistent and easier to use. These improvements include support for: * Unsigned type operations. * Standard library functions for strings, like `.lowercase()`, `.uppercase()`, and `.trim()` functions. * Evaluation of the `.name` property of [enum constants](enum-classes.html#working-with-enum-constants) and the [KCallable interface](https://kotlinlang.org/api/core/kotlin-stdlib/kotlin.reflect/-k-callable/). To make it clear which functions are evaluated at compile time, Kotlin 2.4.0 introduces the `IntrinsicConstEvaluation` annotation. Some functions are evaluated at compile-time but don't have the annotation yet. Later releases will add the annotation to the remaining functions. For a list of supported functions, see the KEEP [appendix](https://github.com/Kotlin/KEEP/blob/main/proposals/KEEP-0444-improve-compile-time-constants.md#appendix). This feature is [Experimental](components-stability.html#stability-levels-explained). To opt in, add the following compiler option to your build file: Gradle: ```KOTLIN kotlin { compilerOptions { freeCompilerArgs.add("-Xintrinsic-const-evaluation") } } ``` Maven: ```XML org.jetbrains.kotlin kotlin-maven-plugin -Xintrinsic-const-evaluation ``` For more information, see the feature's [KEEP](https://github.com/Kotlin/KEEP/blob/main/proposals/KEEP-0444-improve-compile-time-constants.md). ### Improved unused result checks for higher-order functions Kotlin 2.4.0 introduces a new Experimental `returnsResultOf()` contract to improve the [unused return value checker](unused-return-value-checker.html). This contract enables the checker to distinguish between unused results that can be ignored and meaningful unused results from higher-order functions that return the result of a lambda, such as the `let` scope function. Warning: Kotlin contracts are [Experimental](components-stability.html#stability-levels-explained). To opt in, add the `@OptIn(ExperimentalContracts::class)` annotation when declaring a function with a contract. To use this feature, add `returnsResultOf()` to the function's contract: ```KOTLIN import kotlin.contracts.ExperimentalContracts import kotlin.contracts.contract @OptIn(ExperimentalContracts::class) inline fun T.customLet(block: (T) -> R): R { contract { returnsResultOf(block) } return block(this) } ``` Here's an example that uses a custom `.customLet()` function with a nullable value: ```KOTLIN fun handleNullablePackageName(packageName: String?, builder: StringBuilder) { // The checker doesn't report a warning // because the return value of the append() function can be ignored packageName?.customLet { builder.append(it) } // The checker reports a warning because the returned string is unused packageName?.customLet { "kotlin.$it" } } ``` The unused return value checker is [Experimental](components-stability.html#stability-levels-explained) and must be enabled to report unused return values. For more information about enabling and configuring the checker, see [Unused return value checker](unused-return-value-checker.html#configure-the-unused-return-value-checker). #### How to enable The `returnsResultOf()` contract is [Experimental](components-stability.html#stability-levels-explained). Be aware that using it produces pre-release binaries that earlier Kotlin compiler versions can't read. To opt in, add the following compiler option to your build file: Gradle: ```KOTLIN // build.gradle(.kts) kotlin { compilerOptions { freeCompilerArgs.add("-Xallow-returns-result-of") } } ``` Maven: ```XML org.jetbrains.kotlin kotlin-maven-plugin -Xallow-returns-result-of ``` ### New `@IntroducedAt` annotation to generate version-based overloads for optional parameters Kotlin 2.4.0 introduces the `@IntroducedAt` annotation for preserving binary compatibility when adding new optional parameters to published APIs. Previously, adding optional parameters to a function often required using `@JvmOverloads`, which can generate more overloads than needed. Alternatively, preserving binary compatibility required you to keep older signatures as hidden deprecated overloads. With the `@IntroducedAt` annotation, you can annotate newly added optional parameters with the version in which they were introduced. The compiler uses this information to automatically generate the corresponding hidden overloads. This annotation is [Experimental](components-stability.html#stability-levels-explained). To opt in, use the `@OptIn(ExperimentalVersionOverloading::class)` annotation. Here's an example: ```KOTLIN @OptIn(ExperimentalVersionOverloading::class) fun Button( label: String = "", color: Color = DefaultColor, @IntroducedAt("1.1") borderColor: Color = DefaultBorderColor, @IntroducedAt("1.2") borderStyle: Style = DefaultBorderStyle, @IntroducedAt("1.2") borderWidth: Int = 1, onClick: () -> Unit ) { // Function body } ``` In this example, the compiler generates hidden overloads for the older versions of the `Button()` function. Since both `@IntroducedAt` and `@JvmOverloads` generate overloads, using them together can cause conflicting overloads. If you use both annotations, the compiler reports a warning. If you suppress the warning, the compiler prioritizes overloads generated from the `@IntroducedAt` annotation. ## Standard library Kotlin 2.4.0 stabilizes support for UUIDs in the common Kotlin standard library. It also adds new extension functions for converting unsigned integers to `BigInteger` on the JVM and support for checking sorted order. ### Stable UUID API in the common Kotlin standard library Kotlin 2.0.20 introduced a [class for generating UUIDs](whatsnew2020.html#support-for-uuids-in-the-common-kotlin-standard-library) (universally unique identifiers) and added support for converting between Kotlin and Java UUIDs. Later releases gradually improved this experimental feature by adding support for: * [Comparing UUIDs with < and > operators](whatsnew2120.html#changes-in-uuid-parsing-formatting-and-comparability) * [Parsing UUIDs from hex-and-dash and plain text formats](uuids.html#parse-uuids) * [Returning null when parsing invalid UUIDs](whatsnew23.html#support-for-returning-null-when-parsing-invalid-uuids). In Kotlin 2.4.0, [the kotlin.uuid.Uuid API](https://kotlinlang.org/api/core/kotlin-stdlib/kotlin.uuid/-uuid/) becomes [Stable](components-stability.html#stability-levels-explained). The only exceptions are [the functions for generating V4 and V7 UUIDs](whatsnew23.html#support-for-generating-v7-uuids-for-specific-timestamps), which remain [Experimental](components-stability.html#stability-levels-explained) and still require opt-in. For more information about how to work with UUIDs, see [UUIDs](uuids.html). ### Support for checking sorted order Kotlin 2.4.0 adds new extension functions for checking sorted order in iterables, arrays, and sequences. This includes the following extension functions: * `.isSorted()` * `.isSortedDescending()` * `.isSortedWith(comparator)` * `.isSortedBy(selector)` * `.isSortedByDescending(selector)` You can use these extension functions to check whether elements are already sorted, without sorting them again or creating your own helper functions. They return `true` if the elements are in the specified order, or if there are fewer than two elements, and `false` otherwise. These functions stop as soon as they encounter an out-of-order pair, which makes them efficient for large inputs. Here's an example of checking sorted order with `.isSorted()` and `.isSortedBy()` functions: ```KOTLIN data class User(val name: String, val age: Int) fun main() { val numbers = listOf(1, 2, 3, 4) println(numbers.isSorted()) // true val users = listOf( User("Alice", 24), User("Bob", 31), User("Charlie", 29), ) println(users.isSortedBy(User::age)) // false } ``` ### New API for converting unsigned integers to `BigInteger` on the JVM Kotlin 2.4.0 introduces the `UInt.toBigInteger()` and `ULong.toBigInteger()` extension functions on the JVM. Previously, converting `UInt` and `ULong` values to `BigInteger` required string-based workarounds or custom conversion logic. Starting with Kotlin 2.4.0, you can now use `.toBigInteger()` to convert unsigned integer values directly to `BigInteger`. Here's an example: ```KOTLIN fun main() { //sampleStart val unsignedLong = Long.MAX_VALUE.toULong() + 1uL val unsignedInt = UInt.MAX_VALUE println(unsignedLong.toBigInteger()) // 9223372036854775808 println(unsignedInt.toBigInteger()) // 4294967295 //sampleEnd } ``` ### New map fallback functions to distinguish `null` values and missing keys Kotlin 2.4.0 adds new variants of the existing [.getOrElse()](https://kotlinlang.org/api/core/kotlin-stdlib/kotlin.collections/get-or-else.html) and [.getOrPut()](https://kotlinlang.org/api/core/kotlin-stdlib/kotlin.collections/get-or-put.html) [map extension functions](map-operations.html) for maps with nullable values. These functions retrieve a value for a key or use a default value as a fallback. For maps with nullable values, the new variants let you choose whether a stored `null` value behaves like a missing key or an existing value, and they make that choice clear in their function names. The new extension functions include the following: * `.getOrElseIfNull(key, defaultValue)` and `.getOrPutIfNull(key, defaultValue)`, which return the default value if the key is missing or has a `null` value, similar to the existing `.getOrElse()` and `.getOrPut()` functions. * `.getOrElseIfMissing(key, defaultValue)` and `.getOrPutIfMissing(key, defaultValue)`, which return the default value only when the map doesn't contain the specified key. These APIs are [Experimental](components-stability.html#stability-levels-explained) and require opt-in with the `@OptIn(ExperimentalStdlibApi::class)` annotation. Here's an example that demonstrates the difference between `.getOrPutIfNull()` and `.getOrPutIfMissing()` when the key exists with a `null` value: ```KOTLIN @OptIn(ExperimentalStdlibApi::class) fun main() { val mapForNull = mutableMapOf("user" to null) val mapForMissing = mutableMapOf("user" to null) // Replaces the value if "user" has a null value mapForNull.getOrPutIfNull("user") { "default_user" } println(mapForNull) // {user=default_user} // Keeps the null value because "user" exists in the map mapForMissing.getOrPutIfMissing("user") { "default_user" } println(mapForMissing) // {user=null} } ``` You can also use the `.getOrElseIfMissing()` and `.getOrPutIfMissing()` functions for caches that store nullable values. If `defaultValue` returns `null`, the map stores it and doesn't call `defaultValue` again for the same key. Here's an example: ```KOTLIN data class Response(val body: String) class Service { var queryCount = 0 fun query(key: String): Response? { queryCount += 1 return null } } //sampleStart @OptIn(ExperimentalStdlibApi::class) fun main() { val service = Service() val cache = mutableMapOf() fun getCachedResponseOrQuery(key: String): Response? = cache.getOrPutIfMissing(key) { service.query(key) } // Stores null because the cache doesn't contain "user" getCachedResponseOrQuery("user") println(cache) // {user=null} // Uses the cached null and doesn't query the service again getCachedResponseOrQuery("user") println(service.queryCount) // 1 } //sampleEnd ``` We would appreciate your feedback in [YouTrack](https://youtrack.jetbrains.com/issue/KT-67337). ## Kotlin/JVM Kotlin 2.4.0 supports a new Java version and enables annotations in metadata by default. ### Support for Java 26 Starting with Kotlin 2.4.0, the compiler can generate classes containing Java 26 bytecode. ### Annotations in metadata enabled by default The Kotlin Metadata JVM library in Kotlin 2.2.0 [introduced support for reading annotations stored in Kotlin metadata](whatsnew22.html#support-for-reading-and-writing-annotations-in-kotlin-metadata). With this support, the Kotlin compiler writes annotations into metadata alongside the JVM bytecode, making them accessible to the Kotlin Metadata JVM library. As a result, annotation processors and other tools can understand and manipulate these annotations at the metadata level without using reflection or modifying source code. In Kotlin 2.4.0, this support is enabled by default. ## Kotlin/Native Starting with Kotlin 2.4.0, [Swift export is promoted to Alpha](#swift-export-goes-alpha-with-improved-concurrency-support). This release also brings support for [Swift package import](#swift-package-import), Xcode 26.4, improvements for memory consumption, and garbage collection. ### Default concurrent marking in garbage collector In Kotlin 2.0.20, the Kotlin team [introduced experimental support](whatsnew2020.html#concurrent-marking-in-garbage-collector) for the concurrent mark and sweep garbage collector (CMS GC). After processing user feedback and fixing regressions, we are now ready to enable CMS by default, starting with Kotlin 2.4.0. The previous default parallel mark concurrent sweep (PMCS) setup in the garbage collector had to pause application threads while the GC marked objects in the heap. In contrast, CMS allows the marking phase to run concurrently with application threads. This significantly improves GC pause duration and app responsiveness, which is important for the performance of latency-critical applications. CMS has already demonstrated its effectiveness in benchmarks for UI applications built with [Compose Multiplatform](https://blog.jetbrains.com/kotlin/2024/10/compose-multiplatform-1-7-0-released/#performance-improvements-on-ios). If you face problems, you can switch back to PMCS. To do that, set the following [binary option](native-binary-options.html) in your `gradle.properties` file: ``` kotlin.native.binary.gc=pmcs ``` For more information on the Kotlin/Native garbage collector, see our [documentation](native-memory-manager.html#garbage-collector). ### Reduced memory consumption during devirtualization analysis Previously, devirtualization analysis was one of the most memory-consuming phases in the Kotlin/Native compiler. Namely, the link release task consumed too much memory, especially in large projects. Kotlin 2.4.0 introduces improvements that help reduce peak memory consumption during link release tasks. According to benchmarks from one of our EAP users, the improved devirtualization analysis reduced memory consumption by link release tasks by half, saving at least 13 GB. ### Support for Xcode 26.4 Starting with Kotlin 2.4.0, the Kotlin/Native compiler supports Xcode 26.4 – one of the latest stable versions of Xcode. You can now update your Xcode and get access to the latest APIs to continue working on your Kotlin projects for Apple operating systems. ### LLVM update to version 21 In Kotlin 2.4.0, we updated LLVM from version 19 to 21. The new version includes performance improvements and helps keep the Kotlin/Native compiler up to date. This update shouldn't affect your code, but if you encounter any issues, please report them to our [issue tracker](http://kotl.in/issue). ### Changes to Apple target support Kotlin 2.4.0 raises the default minimum supported versions of Apple targets: * For iOS and tvOS, from 14.0 to 15.0. * For macOS, from 11.0 to 12.0. * For watchOS, from 7.0 to 8.0. If you need to support a lower version in your project than the default one, use the `freeCompilerArgs` option in your build file: ```KOTLIN kotlin { targets.withType().configureEach { binaries.configureEach { freeCompilerArgs += "-Xoverride-konan-properties=minVersion.ios=14.0" freeCompilerArgs += "-Xoverride-konan-properties=minVersion.macos=11.0" freeCompilerArgs += "-Xoverride-konan-properties=minVersion.tvos=14.0" freeCompilerArgs += "-Xoverride-konan-properties=minVersion.watchos=7.0" } } } ``` ### Swift export goes Alpha with improved concurrency support Starting with Kotlin 2.4.0, Kotlin's interoperability with Swift through Swift export is officially in Alpha! This release brings major improvements to concurrency support, adding native and direct structured concurrency to Swift export and the ability to export `kotlinx.coroutines` flows to Swift. #### Support for structured concurrency You can now seamlessly call suspending Kotlin code from Swift. Kotlin [suspend functions](composing-suspending-functions.html) and suspend functional types are exported as Swift's idiomatic `async` counterparts: ```KOTLIN // Kotlin suspend fun hello(): String { delay(1000) return "Hello Swift! This is Kotlin." } ``` ```SWIFT // Swift let msg = try await hello() ``` #### Export of flow types to Swift This update also adds support for exporting `kotlinx.coroutines` flows to Swift. Flows in `kotlinx.coroutines` represent an asynchronous stream of data that can be emitted and consumed concurrently. They are commonly used for reactive programming patterns, such as listening for database updates, network requests, or UI events. Previously, the only way to expose the `Flow` interface from [kotlinx.coroutines.flow](https://kotlinlang.org/api/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.flow/-flow/) to Swift was through third-party solutions. Now you can export flows out of the box into Swift's idiomatic counterpart: [AsyncSequence](https://developer.apple.com/documentation/Swift/AsyncSequence). The feature is enabled by default. You can export any public API with the `Flow` type to Swift while preserving type information. For example: ```KOTLIN // Kotlin // Type String is preserved when exporting Flow fun flowOfStrings(): Flow = flowOf("hello", "any", "world") ``` ```SWIFT // Swift var actual: [String] = [] // Type String is correctly inferred from Kotlin for try await element in flowOfStrings().asAsyncSequence() { actual.append(element) } ``` For more information about Swift export, see our [documentation](native-swift-export.html). ### Swift package import Kotlin Multiplatform projects now can declare [Swift packages](https://docs.swift.org/swiftpm/documentation/packagemanagerdocs/) as dependencies for an iOS app in their Gradle configuration: ```KOTLIN // build.gradle.kts kotlin { swiftPMDependencies { swiftPackage( url = url("https://github.com/firebase/firebase-ios-sdk.git"), version = from("12.11.0"), products = listOf( product("FirebaseAI"), product("FirebaseAnalytics"), ... } ``` For working samples and more detailed information, see [SwiftPM import](https://kotlinlang.org/docs/multiplatform/multiplatform-spm-import.html). If your project relies on CocoaPods dependencies, you can migrate the current setup to use Swift packages. The KMP tooling accounts for this use case and helps you reconfigure the project automatically. For details, see our [CocoaPods migration guide](https://kotlinlang.org/docs/multiplatform/multiplatform-cocoapods-spm-migration.html). ## Kotlin/Wasm Kotlin 2.4.0 enables incremental compilation for Kotlin/Wasm by default and introduces support for the WebAssembly Component Model. ### Incremental compilation enabled by default Kotlin/Wasm introduced incremental compilation in Kotlin 2.1.0. Starting with Kotlin 2.4.0, it is [Stable](components-stability.html#stability-levels-explained) and enabled by default. With this feature, the compiler rebuilds only the files affected by recent changes, which significantly reduces build time. To disable incremental compilation, add the following line to your project's `local.properties` or `gradle.properties` file: ``` # gradle.properties kotlin.incremental.wasm=false ``` If you run into any issues, report them in [YouTrack](https://kotl.in/issue) ### Improved display of internal variables in Chrome DevTools Kotlin 2.4.0 improves the debugging experience for Kotlin/Wasm in Chrome DevTools by making temporary, synthetic, and internal variables easier to distinguish from user-defined variables. The Kotlin compiler and compiler plugins, such as Compose, can generate these variables. They now use the `~` prefix by default, so they are grouped together and moved to the end of the variable list, which Chrome DevTools sorts by name. ### Support for the WebAssembly Component Model Kotlin/Wasm goes a step further in Kotlin 2.4.0 by introducing experimental support for the [WebAssembly Component Model](https://component-model.bytecodealliance.org/). The proposal defines a way to build components from Wasm modules through standardized interfaces and types. This approach helps Wasm evolve from a low-level binary instruction format into a system for composing reusable, language-agnostic components. It enables Kotlin/Wasm to go beyond the browser. For example, Kotlin and WebAssembly are well suited for Function-as-a-Service, also known as FaaS or serverless, applications. To try this feature, check out [a simple server built with wasi:http](https://github.com/Kotlin/sample-wasi-http-kotlin/). ![Kotlin/Wasm with WebAssembly Component Model](images/kotlin-wasm-wasi-http.gif) Share your feedback in [YouTrack](https://youtrack.jetbrains.com/issue/KT-64569/Kotlin-Wasm-Support-Component-Model). ## Kotlin/JS Kotlin 2.4.0 further improves export to JavaScript/TypeScript, including support for exporting value classes, interfaces, and type variance, as well as ES2015 features when inlining JS code. ### Support for value class export to JavaScript/TypeScript Previously, only regular Kotlin classes could be exported to JavaScript/TypeScript. Kotlin 2.4.0 lifts that limitation. You can now export Kotlin's [inline value classes](inline-classes.html) as regular TypeScript classes. To export a value class, mark it with the `@JsExport` annotation on the Kotlin side: ```KOTLIN // Kotlin @JsExport @JvmInline value class Email(val address: String) { init { require(address.contains("@")) { "Invalid email" } } } @JsExport class AuthService { suspend fun login(email: Email): String = ... } ``` From the TypeScript side, it looks like a regular class: ```TYPESCRIPT // TypeScript import { AuthService, Email } from "..." const auth = new AuthService(); console.log(await auth.login(new Email("jane@example.com"))); // "Welcome, jane@example.com!" console.log(await auth.login(new Email("not-an-email"))); // "Invalid email" ``` For more information, see [@JsExport annotation](js-to-kotlin-interop.html#jsexport-annotation). ### Support for ES2015 features when inlining JS code Starting with Kotlin 2.4.0, JavaScript code inlining has full support for [ES2015 features](js-project-setup.html#support-for-es2015-features). It's useful for interoperability with third-party libraries, as well as for direct control over automatic application code generation. Now you can use modern JS features inside [js()](https://kotlinlang.org/api/core/kotlin-stdlib/kotlin.js/js.html) calls, including: * `const` and `let` variable declarations * ES classes * Generators * Lambdas ([arrow functions](whatsnew21.html#support-for-generating-es2015-arrow-functions)) * Spread and rest operators * Template strings Remember that the parameter of the `js()` function should be a string constant because it's parsed at compile time and translated to JavaScript code "as-is". For example, to inline the spread operator, use: ```KOTLIN fun spreadExample(): dynamic = js(""" const add = (a, b, c) => a + b + c; const nums = [1, 2, 3]; const sum = add(...nums); const a = [1, 2, 3]; const b = [...a, 4, 5, 6]; return { sum, b: b }; """) ``` For more information on inlining JavaScript code, see [our documentation](js-interop.html#inline-javascript). ### Preserve type variance when exporting to TypeScript Previously, Kotlin [variance](generics.html#variance) information in generic positions was lost when exporting types to TypeScript. With Kotlin 2.4.0, variance annotation is now saved during export and mapped to TypeScript's [variance annotations](https://www.typescriptlang.org/docs/handbook/2/generics.html#variance-annotations). In your Kotlin code, define the variance of your generic type parameters: ```KOTLIN // Kotlin // 'out' signals covariance (the interface only produces T) interface Producer { fun produce(): T } // 'in' signals contravariance (the interface only consumes T) interface Consumer { fun consume(item: T) } ``` With Kotlin 2.4.0, the `in` and `out` keywords are preserved in the generated TypeScript output: ```TYPESCRIPT // Generated .d.ts export interface Producer { produce(): T; } export interface Consumer { consume(item: T): void; } ``` ### Improved interface export to JavaScript/TypeScript Kotlin 2.4.0 makes it more convenient to export Kotlin interfaces to JavaScript/TypeScript. The new `@JsNoRuntime` annotation removes the previously required metadata for implementing Kotlin interfaces, allowing the direct mapping to regular TypeScript interfaces, similar to how external interfaces already behave by default. To export a Kotlin interface, for example in your Kotlin Multiplatform project, annotate it with `@JsNoRuntime` in the common code: ```KOTLIN // commonMain import kotlin.js.JsNoRuntime @JsNoRuntime expect interface DataProcessor { fun process(data: String): Int } ``` Then provide the actual implementation in your JS-specific source code: ```KOTLIN // jsMain @JsNoRuntime actual interface DataProcessor { actual fun process(data: String) } ``` Because the required metadata for implementing Kotlin interfaces is removed, the interface is mapped to a regular TypeScript interface: ```TYPESCRIPT // Generated .d.ts export interface DataProcessor { process(data: string): void; } ``` The `@JsNoRuntime` annotation is only allowed on standard interfaces, so that TypeScript can treat Kotlin interfaces as regular TypeScript interfaces. Therefore, the following operations are prohibited: * `is` and `as` type checks. * Class references with the [::class syntax](js-reflection.html). * Passing an interface as a reified type argument. Tip: Avoid annotating external interfaces with `@JsNoRuntime`, as this results in a compiler warning. ### Lifting restrictions on exporting interfaces Kotlin 2.4.0 makes another step toward the stabilization of `@JsExport`, improving how Kotlin interfaces are exported. Now you can export Kotlin interfaces with nested classes and named companion objects: ```KOTLIN @JsExport interface Identity { class Metadata(val tag: String) companion object Registry { val defaultTag = "GUEST" } } ``` For more information, see [@JsExport annotation](js-to-kotlin-interop.html#jsexport-annotation). ## Gradle Kotlin 2.4.0 is fully compatible with Gradle 7.6.3 through 9.5.0. You can also use Gradle versions up to the latest Gradle release. However, be aware that doing so may result in deprecation warnings, and some new Gradle features might not work. Kotlin 2.4.0 also brings improvements like consistent default module names across platforms and compiler messages written to the Problems API for the Kotlin/JVM. ### Minimum supported AGP version bumped to 8.5.2 Starting with Kotlin 2.4.0, the minimum supported Android Gradle plugin version is 8.5.2. ### Consistent module names across platforms Prior to Kotlin 2.4.0, default module names differed across platforms. This inconsistency could cause naming conflicts and resolution issues. Kotlin 2.4.0 standardizes the default names to `{group}:{project_name}` across all platforms. If you need to revert the JVM module name to its previous version, add the following to your `build.gradle.kts` file for a Kotlin/JVM project: ```KOTLIN kotlin { compilerOptions.moduleName(project.name) } ``` For a multiplatform project: ```KOTLIN kotlin { jvm { compilerOptions.moduleName(project.name) } } ``` ### Compiler messages written to Problems API for Kotlin/JVM In Kotlin 2.2.0, the Kotlin Gradle plugin (KGP) started reporting diagnostics to [Gradle's Problems API](https://docs.gradle.org/current/userguide/reporting_problems.html) to provide a consistent experience both in Gradle's CLI and in IntelliJ IDEA. In Kotlin 2.4.0, the plugin also writes compiler messages to the Problems API for Kotlin/JVM, bringing the API closer to becoming a single source for all logs and messages. ## Maven Kotlin 2.4.0 makes project configuration even easier with support for Maven Toolchains and automatic alignment between Java and JVM target versions. ### Automatic alignment between Java and JVM target versions To simplify project configuration and prevent compatibility issues, the Kotlin Maven plugin now automatically aligns the JVM target version with the Java compiler version configured in the project. This ensures that the Kotlin and Maven compilers target the same bytecode version, avoiding issues where Kotlin-generated bytecode is incompatible with the rest of the project or the intended deployment environment. With the `` option enabled, you don't need to set the `kotlin.compiler.jvmTarget` or `kotlin.compiler.jdkRelease` options. If neither of them is defined, the Kotlin Maven plugin automatically resolves the JVM target version in the following order: 1. As the `maven.compiler.release` version defined either as a project property or within the `maven-compiler-plugin` configuration. In this case, both `jvmTarget` and `jdkRelease` compiler options are set for the Kotlin compiler, limiting the API to a specific JDK version. 2. As the `maven.compiler.target` version in case the Maven release version is not set. The compiler target can be defined either as a project property or within the `maven-compiler-plugin` configuration. In this case, only Kotlin's `jvmTarget` is set, and the API is not limited to a specific JDK version. This greatly simplifies your Kotlin project configuration, so your `pom.xml` file can look like this: ```XML 17 2.4.20 org.jetbrains.kotlin kotlin-maven-plugin ${kotlin.version} true ``` During the build, the plugin outputs a similar message: ``` [INFO] Using jvmTarget=17 (derived from maven.compiler.release=17) ``` Note: The `` option only checks project-level properties and the global `maven-compiler-plugin` configuration. It doesn't check the configurations defined in the plugin's `` section. For more information about automatic project configuration, see [our documentation](maven-configure-project.html#jvm-target-version). ### Support for Maven Toolchains Kotlin 2.4.0 introduces support for [Maven Toolchains](https://maven.apache.org/guides/mini/guide-using-toolchains.html) to the Kotlin Maven plugin. The feature helps manage the JDK version in your build. With Maven Toolchains, you can specify the JDK version used for Kotlin compilation, independent of the JVM version running Maven (set in `JAVA_HOME`). When the `maven-toolchains-plugin` is configured in the build, the Kotlin Maven plugin automatically picks up the selected JDK toolchain, in the same way the Maven compiler plugin and other Maven plugins do. This allows you to configure a single toolchain to control the JDK used across all plugins in the build, including Kotlin compilation: ```XML org.apache.maven.plugins maven-toolchains-plugin 3.2.0 toolchain 21 ``` Keep in mind the priority of different ways to set up the JDK version: 1. `jdkHome` in the `kotlin-maven-plugin` configuration. An explicitly set `jdkHome` option always takes precedence over the toolchain version. 2. JDK version in `maven-toolchains-plugin`. The JDK version set through Maven Toolchains overrides the JDK version set in the `JAVA_HOME` path. 3. The `JAVA_HOME` path. You can also use a plugin-specific `` option to directly set the JDK version in the toolchain of `kotlin-maven-plugin`. Compared to using `maven-toolchains-plugin`, this parameter only affects Kotlin compilation and has no impact on other plugins in the build. Note: Currently, setting `maven-toolchains-plugin` to use a specific JDK version does not affect the `kapt` and `test-kapt` goals of `kotlin-maven-plugin`. To work around this, set the necessary version in the `JAVA_HOME` path. For more details, see [KT-79897](https://youtrack.jetbrains.com/issue/KT-79897). For more information on configuring Kotlin Maven projects, see our [documentation](maven-configure-project.html). ## Build tools API Kotlin 2.4.0 brings a number of improvements to the build tools API (BTA). The BTA: * Introduces new type-safe abstractions for most JVM and common compiler options. The BTA now handles their format instead of the client, reducing the risk of errors and providing an additional layer of assistance. This change is backwards-compatible at runtime, but it may break source compatibility. * Can now track non-source changes in incremental compilation, such as configuring a different Kotlin version or changing compiler options. Build systems can control this behavior through the `BaseIncrementalCompilationConfiguration.TRACK_CONFIGURATION_INPUTS` option. * Supports [binary compatibility validation](gradle-binary-compatibility-validation.html) through the `AbiValidationToolchain`, making it easier for other build systems to add this functionality. * Introduces a new feature so that build systems can customize how compiler messages are displayed through the [CompilerMessageRenderer](https://github.com/JetBrains/kotlin/blob/2.4.0/compiler/build-tools/kotlin-build-tools-api/src/main/kotlin/org/jetbrains/kotlin/buildtools/api/CompilerMessageRenderer.kt) interface and the [JvmCompilationOperation builder](https://github.com/JetBrains/kotlin/blob/2.4.0/compiler/build-tools/kotlin-build-tools-api/src/main/kotlin/org/jetbrains/kotlin/buildtools/api/jvm/operations/JvmCompilationOperation.kt#L59). * Introduces new options for configuring [Kotlin daemon](kotlin-daemon.html) logging: * `LOGS_PATH` — the directory for daemon log files. * `LOGS_FILE_SIZE_LIMIT` — the maximum log file size in bytes. * `LOGS_FILE_COUNT_LIMIT` — the maximum number of retained log files. By default, limits are set to a value specific to the Kotlin compiler version. To have no limit, build tools must set the option to `null`. Build systems can set the option when configuring the [execution policy](https://github.com/JetBrains/kotlin/blob/2.4.0/compiler/build-tools/kotlin-build-tools-api/src/main/kotlin/org/jetbrains/kotlin/buildtools/api/ExecutionPolicy.kt): ```KOTLIN val executionPolicy = kotlinToolchains.daemonExecutionPolicy { set(ExecutionPolicy.WithDaemon.LOGS_PATH, Paths("/var/log/kotlin-daemon")) set(ExecutionPolicy.WithDaemon.LOGS_FILE_SIZE_LIMIT, 10_485_760L) set(ExecutionPolicy.WithDaemon.LOGS_FILE_COUNT_LIMIT, 10) } ``` ## Kotlin compiler Kotlin 2.4.0 includes more consistent behavior for inline functions declared in the same module during `.klib` compilation. ### Consistent intra-module function inlining during klib compilation Previously, [function inlining](inline-functions.html) behaved inconsistently on different Kotlin platforms. The JetBrains team is working to unify it across all supported platforms to ensure the same compatibility guarantees. On the Kotlin/JVM, function inlining happens at compile time. So, when Kotlin sources are compiled with the Kotlin/JVM compiler, the resulting class files have no inline function calls in the bytecode because the bodies of inline functions are inlined into their call sites, so their behavior is fixed during compilation. On the contrary, on Kotlin/Native, Kotlin/JS, and Kotlin/Wasm, function inlining did not happen during source-to-klib compilation, only during binary generation. As a result, the behavior of inline functions wasn't fixed during `.klib` compilation, and `.klib` libraries didn't provide the same compatibility guarantees for inline functions as Kotlin/JVM does. Kotlin 2.4.0 takes the first step in unifying the behavior of inline functions by enabling intra-module inlining when generating `.klib` artifacts: ```KOTLIN // Existing logging.klib library inline fun logDebug(message: String) { println("[DEBUG] $message") } ``` ```KOTLIN // Currently compiled App module inline fun greetUser(name: String) { println("Hello, $name!") } fun main() { logDebug("App started") // Not inlined: declared in another module greetUser("Alice") // Inlined: declared in the same module } ``` When compiled to a `.klib`, the code looks something like: ```KOTLIN // Pseudocode fun main() { logDebug("App started") // Not inlined, declared in another module val tmp0 = "Alice" println("Hello, $tmp0!") // Inlined from greetUser() } ``` This means only inline functions declared in the same module are inlined during `.klib` compilation. Other functions, in this case, are inlined during the generation of platform-specific binaries. #### How to enable Starting with 2.4.0, the intra-module inlining is enabled by default for Kotlin/Native, Kotlin/JS, and Kotlin/Wasm. If you face unexpected problems with this feature, you can disable it using the following compiler option in the command line: ```BASH -Xklib-ir-inliner=disabled ``` The next step is to enable cross-module inlining to ensure all inline functions in the project are consistently inlined. This change is planned for future Kotlin releases, but you can already try it out using the following compiler option in the command line: ```BASH -Xklib-ir-inliner=full ``` Please share your feedback and report any problems in [YouTrack](https://kotl.in/issue). ### Consistent partial library linkage across Kotlin compilers In Kotlin 1.9.0, partial library linkage was enabled by default for both the Kotlin/Native and Kotlin/JS compilers, with Kotlin/Wasm following in Kotlin 2.0.0. This feature effectively makes compilers treat linkage issues in Kotlin libraries consistently with Kotlin/JVM. Since then, we haven't received negative feedback and haven't noticed users disabling the partial linkage in their projects. That's why starting with Kotlin 2.4.0, the partial linkage is always enabled, and the `-Xpartial-linkage` compiler option is now deprecated. The default log level for all Kotlin compilers is `SILENT`. Linkage issues are not reported during compilation. To change this behavior in your projects, set the `-Xpartial-linkage-loglevel` compiler option in your build file: ```KOTLIN // build.gradle.kts kotlin { macosX64("native") { binaries.executable() compilations.configureEach { compilerOptions.configure { // To report linkage issues with the “info” log level: freeCompilerArgs.add("-Xpartial-linkage-loglevel=INFO") // To report issues as errors: freeCompilerArgs.add("-Xpartial-linkage-loglevel=ERROR") } } } } ``` * `INFO` reports linkage issues with the "info" log level. * `WARNING` reports warnings at compile time and records them in compilation logs. * `ERROR` allows compilation to fail in case of linkage issues and reports errors in compilation logs. Use this option to examine the linkage issues more closely. If you encounter issues with this feature, please report them in [our issue tracker](https://kotl.in/issue). ## Kotlin compiler plugins In Kotlin 2.4.0, Kotlin's compiler plugins received notable updates, too. The kapt plugin can now exclude unnecessary annotation processors from the compile classpath, and the Power-assert plugin offers simplified configuration through the new runtime library. ### kapt: Exclude annotation processors from compile classpath Kotlin 2.4.0 adds support for the `includeCompileClasspath` configuration option for annotation processor discovery, similar to the Kotlin Gradle plugin. The new option allows you to exclude unnecessary annotation processors from the compile classpath. To configure this in your build file, set the `includeCompileClasspath` option to `false` in the `` section of the kapt plugin: ```XML kapt kapt false ... ... ``` Alternatively, you can do the same with the `kapt.include.compile.classpath` in the `` section: ```XML false ``` With the option set to `false`, annotation processors not included in the `` section of the kapt configuration are excluded from the kapt processing. If `includeCompileClasspath` is not set and kapt detects an annotation processor on the compile classpath that is not explicitly defined in the `` section, you'll see the following deprecation warning: ```TEXT [WARNING] Annotation processors discovery from compile classpath is deprecated. Set 'kapt.include.compile.classpath=false' to disable discovery. ``` For more information on kapt configuration, see our [documentation](kapt.html). ### Power-assert: New runtime library Kotlin 2.4.0 makes Power-assert capable functions more discoverable and easier to configure with the new runtime library. Previously, adopting Power-assert required complex build configurations and function parameter conventions. Starting with this release, Power-assert capable functions can use the new runtime library to integrate directly with the compiler plugin transformations. This brings major improvements for both plugin users and library authors: * The new `CallExplanation` data structure provides detailed information about the call site. This enables more dynamic diagram rendering for assertion failures and better integration with external tools. * The new `@PowerAssert` annotation makes assertion functions instantly discoverable by the compiler plugin. That way, you can now add out-of-the-box support for Power-assert into your libraries. Tip: Use our [example collection](https://github.com/bnorm/power-assert-examples#power-assert-examples) as a playground for experimenting with the new features. For more information, see our [documentation](power-assert.html#use-the-power-assert-plugin). ## Compose compiler With Kotlin 2.4.0, the Compose compiler offers more consistent incremental compilation and advances the deprecation cycle of several feature flags. ### Consistent incremental compilation for internal declarations Starting from Kotlin 2.4.0, the Compose compiler offers more consistent incremental compilation. Stability of internal types across different files is now inferred during runtime. This allows Compose to update inferred stability values even when class usages are not recompiled. As a side effect, the size of your artifacts may increase whenever a `@Composable` function uses an `internal` class from a different file as a parameter. This is caused by the compiler encoding the execution paths for both stable and unstable cases, since stability has to be decided during runtime. This overhead of runtime stability is removed by minifiers that perform full-app optimizations (such as R8) as they are able to infer the unnecessary execution path and eliminate it. This update does not change the final stability value, so the behavior of `@Composable` functions remains unchanged. ### Feature flag deprecations Kotlin 2.4.0 advances the deprecation cycle of experimental feature flags that graduated to stable and are now enabled by default: * `StrongSkipping`, `IntrinsicRemember`, and associated DSL properties are advanced to `DeprecationLevel.ERROR`. They will be removed in Kotlin 2.5.0. * `OptimizeNonSkippingGroups` and `PausableComposition` are now deprecated. They are scheduled to be removed in Kotlin 2.6.0. ## Breaking changes and deprecations This section highlights important breaking changes and deprecations. For a complete overview, see our [Compatibility guide](compatibility-guide-24.html). * Starting with Kotlin 2.4.0, the compiler no longer supports `-language-version=1.9`. As a result, the K1 compiler is no longer supported. * Kotlin 2.4.0 streamlines the DSL for binary compatibility validation in the Kotlin Gradle plugin and deprecates some parts. For the latest DSL, see [Binary compatibility validation in the Kotlin Gradle plugin](gradle-binary-compatibility-validation.html). * [Support for Kotlin script execution through the KotlinScriptMojo Maven plugin has been removed](compatibility-guide-22.html#deprecations-to-kotlin-scripting). ## Documentation updates We made the following documentation changes in the Kotlin ecosystem: * [Liquid Glass in a Compose Multiplatform app](https://kotlinlang.org/docs/multiplatform/ios-liquid-glass.html) – Migrate an iOS app from fully Compose-driven navigation to native SwiftUI navigation with iOS 26 Liquid Glass styling. * [Adding Swift packages as dependencies to KMP modules](https://kotlinlang.org/docs/multiplatform/multiplatform-spm-import.html) – Learn how to set up a SwiftPM dependency in your KMP project. * [Switch Kotlin Multiplatform project from CocoaPods to SwiftPM dependencies](https://kotlinlang.org/docs/multiplatform/multiplatform-cocoapods-spm-migration.html) manually or [with Junie](https://kotlinlang.org/docs/multiplatform/multiplatform-cocoapods-spm-migration-ai.html) – Learn how you can use Junie and Kotlin AI skills to make migration easier. * [Configure TeamCity for a KMP app](https://kotlinlang.org/docs/multiplatform/configure-teamcity-for-kmp.html) – Use TeamCity to build, test, and deploy your KMP applications. * [Recommended serialization approaches for Navigation 3](https://kotlinlang.org/docs/multiplatform/compose-navigation-3.html#recommended-serialization-approaches) – Find the best way to use serialization with Navigation 3 in your CMP application. * [Multiplatform ViewModel](https://kotlinlang.org/docs/multiplatform/compose-viewmodel.html) – Learn how to set up and work with ViewModels in a multiplatform project. * [Backend development with Kotlin](server-overview.html) – Explore the different frameworks you can use for backend development. * [Create a task manager app with Spring Boot and Claude](spring-boot-claude.html) – Learn how Claude can help you create an app with Spring Boot from scratch. * [Configure a Maven project](maven-configure-project.html) – Set up Kotlin compilation in your existing Java Maven project or in a new Kotlin Maven project. * [Test Kotlin projects with Maven](jvm-test-maven.html) – Learn how to create tests with JUnit and use Maven plugins to run unit and integration tests. * [Use annotation processors in Kotlin projects](jvm-annotation-processors.html) – Choose between kapt and KSP to process annotations in your backend project. * [Kotlin AI skills](kotlin-ai-skills.html) – Use agent skills to help you perform Kotlin-specific tasks. * [Kotlin Language Server](kotlin-lsp.html) – Read about JetBrains' official implementation of the Language Server Protocol (LSP) for Kotlin. * [Numbers](numbers.html) – Explore Kotlin's number types and how to work with them. * [Getting started with KSP](ksp-quickstart.html) – Learn how to add a KSP-based processor to your project or create your own. * [Migrate from kapt to KSP](ksp-kapt-migration.html) – Migrate your annotation processors to get the best out of Kotlin's features. * [Lincheck overview](lincheck-guide.html) – Understand how Lincheck works behind the scenes to test concurrent code on the JVM. * [Getting started with Lincheck](lincheck-getting-started.html) – Create a project and run tests with Lincheck. * [Testing arbitrary code with Lincheck](lincheck-testing-arbitrary-code.html) – Learn how to test concurrent code with Lincheck. * [How to test data structures with Lincheck](lincheck-how-to-test-data-structures.html) – Dive into Lincheck's data structure testing process. * [Testing strategies with Lincheck](lincheck-testing-strategies.html) – Learn about Lincheck's testing strategies: model checking and stress testing. * [Configuring a testing strategy with Lincheck](lincheck-testing-strategies-options.html) – Explore the different options for Lincheck's testing strategies. * [Deploy a Ktor application with Dokku](https://ktor.io/docs/dokku.html) – Learn about the deployment workflow with Dokku. # Compatibility guide for Kotlin 2.4.x [Keeping the Language Modern](kotlin-evolution-principles.html) and [Comfortable Updates](kotlin-evolution-principles.html) are among the fundamental principles in Kotlin Language Design. The former says that constructs which obstruct language evolution should be removed, and the latter says that this removal should be well-communicated beforehand to make code migration as smooth as possible. While most of the language changes were already announced through other channels, like update changelogs or compiler warnings, this document summarizes them all, providing a complete reference for migration from Kotlin 2.3 to Kotlin 2.4. This document also includes information about tool-related changes. ## Basic terms In this document, we introduce several kinds of compatibility: * source: source-incompatible change stops code that used to compile fine (without errors or warnings) from compiling anymore * binary: two binary artifacts are said to be binary-compatible if interchanging them doesn't lead to loading or linkage errors * behavioral: a change is said to be behavioral-incompatible if the same program demonstrates different behavior before and after applying the change Remember that those definitions are given only for pure Kotlin. Compatibility of Kotlin code from the other languages perspective (for example, from Java) is out of the scope of this document. ## Language ### Drop support for `-language-version=1.9` and the K1 compiler Tip: Issue: [KT-80590](https://youtrack.jetbrains.com/issue/KT-80590) Component: Compiler Incompatible change type: source Short summary: Starting with Kotlin 2.4, the compiler no longer supports [-language-version=1.9](compiler-reference.html#language-version-version). As a result, the K1 compiler is no longer supported. Deprecation cycle: * 2.2.0: report a warning when using `-language-version` with version 1.9 * 2.4.0: raise the warning to an error ### Prohibit flexible explicit nullable type arguments for Java types Tip: Issue: [KTLC-284](https://youtrack.jetbrains.com/issue/KTLC-284) Component: Core language Incompatible change type: source Short summary: Previously, when calling Java APIs from Kotlin, the compiler could treat explicitly specified nullable type arguments as flexible type arguments. Kotlin 2.4.0 no longer applies this behavior for nullable type arguments, so the compiler now reports errors for code that could break type safety or fail at runtime. Deprecation cycle: * 2.2.0: report a warning for explicitly specified nullable type arguments that are treated as flexible types * 2.4.0: raise the warning to an error ### Prohibit always-false `is` checks for definitely incompatible types Tip: Issue: [KTLC-365](https://youtrack.jetbrains.com/issue/KTLC-365) Component: Core language Incompatible change type: source Short summary: The compiler now prevents meaningless `is` checks that are always false because the checked types are definitely incompatible. This keeps the behavior consistent with other operations involving incompatible types. Deprecation cycle: * 2.0.0: report a warning for `is` checks with definitely incompatible types * 2.4.0: raise the warning to an error ### Prohibit exposing types and declarations with lower visibility in inline functions Tip: Issue: [KTLC-283](https://youtrack.jetbrains.com/issue/KTLC-283) Component: Core language Incompatible change type: source Short summary: The compiler now prevents inline functions from exposing types and declarations that have lower visibility than the inline function itself. Deprecation cycle: * 2.3.0: report a warning for exposing types and declarations with lower visibility in inline functions * 2.4.0: raise the warning to an error ### Change default use-site target selection for annotations Tip: Issue: [KTLC-391](https://youtrack.jetbrains.com/issue/KTLC-391) Component: Core language Incompatible change type: binary Short summary: Kotlin 2.4.0 updates the defaulting rules for propagating annotations to parameters, properties, and fields. This can affect annotation processing, reflection, and binary metadata after recompilation. When you don't specify a use-site target, the compiler now uses `param` and `property` if they apply, and uses `field` only if `property` doesn't apply. You can specify a use-site target explicitly, such as `@param:Annotation` instead of `@Annotation`. To use the previous defaulting rule for your whole project, add `-Xannotation-default-target=first-only` to your build file. Deprecation cycle: * 2.2.0: report a warning when the new defaulting rule changes the chosen use-site targets * 2.4.0: enable the new defaulting rule ### Forbid implicit references to inaccessible types Tip: Issue: [KTLC-384](https://youtrack.jetbrains.com/issue/KTLC-384) Component: Core language Incompatible change type: source Short summary: Using declarations that implicitly reference inaccessible types from indirect dependencies now results in an error. To migrate, add an explicit dependency on the module that declares the inaccessible type, or update the intermediate API so it doesn't expose that type. Deprecation cycle: * 2.3.0: report a warning for implicit references to inaccessible types * 2.4.0: raise the warning to an error ### Enforce Jakarta nullability annotations Tip: Issue: [KTLC-285](https://youtrack.jetbrains.com/issue/KTLC-285) Component: Core language Incompatible change type: source Short summary: The compiler now enforces declared nullability in Kotlin for Java declarations that use [jakarta.annotation.Nullable](https://jakarta.ee/specifications/annotations/2.1/apidocs/jakarta.annotation/jakarta/annotation/nullable) or [jakarta.annotation.Nonnull](https://jakarta.ee/specifications/annotations/2.1/apidocs/jakarta.annotation/jakarta/annotation/nonnull). If you assign a Java declaration marked as nullable by these annotations to a non-null Kotlin type, the compiler reports an error. Deprecation cycle: * 2.2.0: report a warning for nullability mismatches in Java declarations annotated with Jakarta nullability annotations * 2.4.0: raise the warning to an error ### Report misplaced type arguments in callable reference qualifiers Tip: Issue: [KTLC-388](https://youtrack.jetbrains.com/issue/KTLC-388) Component: Core language Incompatible change type: source Short summary: The compiler now checks the left-hand side of callable references and reports a warning if an inner class contains type arguments in the wrong part of the qualifier. To migrate, update the reference so that each type argument belongs to the class that declares it. For example, write the full type `Outer.Inner::toString` instead of `Inner::toString`. Deprecation cycle: * 2.4.0: report a warning when type arguments in the left-hand side of a callable reference belong to another part of the qualifier ### Report errors for class literals from reified type parameters with nullable upper bounds Tip: Issue: [KTLC-370](https://youtrack.jetbrains.com/issue/KTLC-370) Component: Core language Incompatible change type: source Short summary: The compiler now reports an error when you use `::class` on an expression whose type comes from a reified type parameter with a nullable upper bound. If you use `::class` on such an expression, make the value non-null first with an explicit null check or the `!!` operator. Deprecation cycle: * 2.3.0: report a warning when `::class` is used on an expression whose type comes from a reified type parameter with a nullable upper bound * 2.4.0: raise the warning to an error ### Prohibit initialization before declarations in anonymous objects Tip: Issue: [KTLC-290](https://youtrack.jetbrains.com/issue/KTLC-290) Component: Core language Incompatible change type: source Short summary: Kotlin now reports an error when you initialize a property in an `init` block of an anonymous object before declaring that property. Deprecation cycle: * 2.2.20: report a warning when an `init` block in an anonymous object initializes a property before the property declaration * 2.4.0: raise the warning to an error ### Enforce exhaustiveness for `when` expressions with non-abstract Java sealed classes Tip: Issue: [KTLC-366](https://youtrack.jetbrains.com/issue/KTLC-366) Component: Core language Incompatible change type: source Short summary: Kotlin now checks exhaustiveness more strictly and requires an `else` branch or a branch that matches the sealed class itself when you use a `when` expression with a non-abstract Java sealed class. Previously, Kotlin could treat such `when` expressions as exhaustive even though the Java sealed class itself could be instantiated directly. Deprecation cycle: * 2.3.0: report a warning for non-exhaustive `when` expressions with non-abstract Java sealed classes * 2.4.0: raise the warning to an error ### Prohibit `operator` modifier on `getValue()` and `setValue()` functions with too many parameters Tip: Issue: [KTLC-289](https://youtrack.jetbrains.com/issue/KTLC-289) Component: Core language Incompatible change type: source Short summary: When you mark the [getValue()](https://kotlinlang.org/api/core/kotlin-stdlib/kotlin.properties/-read-only-property/get-value.html) or [setValue()](https://kotlinlang.org/api/core/kotlin-stdlib/kotlin.properties/-read-write-property/set-value.html) functions with the `operator` modifier, the compiler now checks that they have the required number of value parameters. The `getValue()` function must have exactly two value parameters, and the `setValue()` function must have exactly three. To migrate, remove the `operator` modifier or change the function signature. Deprecation cycle: * 2.2.20: report a warning for `operator` `getValue()` and `setValue()` functions with too many value parameters * 2.4.0: raise the warning to an error ### Prohibit inconsistent type arguments in generic calls Tip: Issue: [KTLC-373](https://youtrack.jetbrains.com/issue/KTLC-373) Component: Core language Incompatible change type: source Short summary: When you specify type arguments in a generic call, the compiler now reports an error if one type argument violates an upper-bound constraint that depends on another type argument. If type parameters depend on each other, use type arguments that match those constraints, for example `Container()` instead of `Container()`. Deprecation cycle: * 2.3.0: report a warning when explicit type arguments in a generic call violate upper-bound constraints between type parameters * 2.4.0: raise the warning to an error ### Deprecate references to the `javaClass` property Tip: Issue: [KTLC-375](https://youtrack.jetbrains.com/issue/KTLC-375) Component: Kotlin/JVM Incompatible change type: source Short summary: Kotlin 2.4.0 deprecates property references to the [javaClass](https://kotlinlang.org/api/core/kotlin-stdlib/kotlin.jvm/java-class.html) property to reduce confusion with `::class.java`. Use `.javaClass` to get the runtime Java class of an object, or `::class.java` to get a Java class reference. Deprecation cycle: * 2.4.0: report a warning for property references to the `javaClass` property ### Report errors for implicit enum constructor calls that require opt-in Tip: Issue: [KTLC-359](https://youtrack.jetbrains.com/issue/KTLC-359) Component: Core language Incompatible change type: source Short summary: Kotlin now reports an error when an enum entry implicitly calls an enum primary constructor that requires opt-in. To migrate, add `@OptIn` to the enum class or to each enum entry that calls the constructor. Deprecation cycle: * 2.2.20: report a warning when an enum entry implicitly calls an enum primary constructor that requires opt-in * 2.4.0: raise the warning to an error ### Forbid `inline` modifier on enum entries Tip: Issue: [KTLC-361](https://youtrack.jetbrains.com/issue/KTLC-361) Component: Core language Incompatible change type: source Short summary: Kotlin now reports an error when you use the `inline` modifier on an enum entry. Deprecation cycle: * 2.3.0: report a warning when the `inline` modifier is used on an enum entry * 2.4.0: raise the warning to an error ### Prohibit array literals outside annotation calls and parameter defaults Tip: Issue: [KTLC-369](https://youtrack.jetbrains.com/issue/KTLC-369) Component: Core language Incompatible change type: source Short summary: Using array literals outside annotation calls and default values for annotation parameters now results in an error. To migrate, use `arrayOf(...)`, for example `Roles(arrayOf("admin", "user"))` instead of `Roles(["admin", "user"])`. Deprecation cycle: * 2.3.0: report a warning for array literals outside annotation calls and default values for annotation parameters * 2.4.0: raise the warning to an error ### Prohibit `_root_ide_package_` in CLI compiler mode Tip: Issue: [KTLC-378](https://youtrack.jetbrains.com/issue/KTLC-378) Component: Compiler Incompatible change type: source Short summary: Using the IDE-only `_root_ide_package_` qualifier in CLI compiler mode now results in an error. Deprecation cycle: * 2.3.20: report a warning for `_root_ide_package_` references in CLI compiler mode * 2.4.0: raise the warning to an error ### Correct equality for function references with vararg conversions Tip: Issue: [KTLC-385](https://youtrack.jetbrains.com/issue/KTLC-385) Component: Kotlin/JVM Incompatible change type: behavioral Short summary: Kotlin/JVM now treats function references with different conversions as unequal. Previously, Kotlin/JVM ignored vararg conversion in equality checks when the same function reference also used another conversion, so `getDefault(::foo) == getDefaultAndVararg(::foo)` could return `true` even though only one side used vararg conversion. Deprecation cycle: * 2.4.0: introduce the new behavior ### Enforce opt-in for companion object access Tip: Issue: [KTLC-386](https://youtrack.jetbrains.com/issue/KTLC-386) Component: Core language Incompatible change type: source Short summary: Kotlin now reports an opt-in error when a class name reference resolves to a companion object that requires opt-in. For example, `val p = C` requires opt-in if `C` resolves to a companion object marked with an opt-in annotation. Deprecation cycle: * 2.3.20: report a warning when companion object access requires opt-in * 2.4.0: raise the warning to an error for `ERROR`-level opt-in requirements ### Report type mismatches from supertypes with nested generic arguments Tip: Issue: [KTLC-372](https://youtrack.jetbrains.com/issue/KTLC-372) Component: Core language Incompatible change type: source Short summary: Kotlin now reports an error when the compiler detects a type mismatch involving a supertype with nested generic arguments. Previously, the compiler could miss this mismatch, which later failed with a `ClassCastException`. To migrate, use a type argument that matches the receiver's generic type, or remove the explicit type argument so the compiler can infer it. Deprecation cycle: * 2.4.0: report an error for type mismatches involving supertypes with nested generic arguments ### Prohibit inferred types with inaccessible declarations Tip: Issue: [KTLC-363](https://youtrack.jetbrains.com/issue/KTLC-363) Component: Core language Incompatible change type: source Short summary: Using an inferred type that contains a declaration inaccessible in the current scope now results in an error. Deprecation cycle: * 2.3.0: report a warning when an inferred type contains a declaration that isn't accessible in the current scope * 2.4.0: raise the warning to an error ## Standard library ### Deprecate `kotlin.io.readLine()` function Tip: Issue: [KTLC-394](https://youtrack.jetbrains.com/issue/KTLC-394) Component: kotlin-stdlib Incompatible change type: source Short summary: The [kotlin.io.readLine()](https://kotlinlang.org/api/core/kotlin-stdlib/kotlin.io/read-line.html) function is deprecated. Use the [readln()](https://kotlinlang.org/api/core/kotlin-stdlib/kotlin.io/readln.html) function instead of `readLine()!!`, and the [readlnOrNull()](https://kotlinlang.org/api/core/kotlin-stdlib/kotlin.io/readln-or-null.html) function instead of `readLine()`. Deprecation cycle: * 2.4.0: report a warning when using `kotlin.io.readLine()` ### Deprecate `AbstractCoroutineContextKey` and related APIs Tip: Issue: [KT-84970](https://youtrack.jetbrains.com/issue/KT-84970) Component: kotlin-stdlib Incompatible change type: source Short summary: The [AbstractCoroutineContextKey](https://kotlinlang.org/api/core/kotlin-stdlib/kotlin.coroutines/-abstract-coroutine-context-key/) class and its related APIs were experimental since Kotlin 1.3 and proved to be error-prone. For this reason, this class and the related [getPolymorphicElement()](https://kotlinlang.org/api/core/kotlin-stdlib/kotlin.coroutines/get-polymorphic-element.html) and [minusPolymorphicKey()](https://kotlinlang.org/api/core/kotlin-stdlib/kotlin.coroutines/minus-polymorphic-key.html) functions are deprecated. Deprecation cycle: * 2.4.0: report a warning when using the deprecated APIs ### Change `Random.nextDouble()` contract for infinite bounds Tip: Issue: [KT-84368](https://youtrack.jetbrains.com/issue/KT-84368) Component: kotlin-stdlib Incompatible change type: behavioral Short summary: The documented contract for [Random.nextDouble(until)](https://kotlinlang.org/api/core/kotlin-stdlib/kotlin.random/-random/next-double.html) now requires the `until` bound to be finite. Use a finite bound instead. Deprecation cycle: * 2.4.0: enable the new behavior ## Tools ### Deprecate legacy Kotlin/JS compiler type selection APIs Tip: Issue: [KT-64275](https://youtrack.jetbrains.com/issue/KT-64275), [KT-84753](https://youtrack.jetbrains.com/issue/KT-84753) Component: Gradle Incompatible change type: source Short summary: Kotlin 2.4.0 removes deprecated Gradle APIs related to selecting the legacy Kotlin/JS compiler type. Additionally, the `KotlinJsCompilerType` enum and the `KotlinProjectExtension.js()` overloads with a compiler type parameter are deprecated. To migrate, remove the compiler type argument from the `js()` target declaration and use the `js {}` block instead. Deprecation cycle: * 1.8.0: deprecate legacy Kotlin/JS compiler type constants * 2.4.0: remove the deprecated legacy compiler type APIs and report a warning when using `KotlinJsCompilerType` or `KotlinProjectExtension.js()` overloads with a compiler type parameter ### Deprecate `sourceSets` in the Kotlin Android extension Tip: Issue: [KT-74451](https://youtrack.jetbrains.com/issue/KT-74451) Component: Gradle Incompatible change type: source Short summary: The `sourceSets` property in `KotlinAndroidProjectExtension` is deprecated. To migrate, configure source sets through the Android Gradle plugin's `android { sourceSets { ... } }` block instead. Deprecation cycle: * 2.4.0: report a warning when accessing `sourceSets` from `KotlinAndroidProjectExtension` ### Remove consumable configurations for Kotlin/Native Apple frameworks Tip: Issue: [KT-74503](https://youtrack.jetbrains.com/issue/KT-74503), [KT-82230](https://youtrack.jetbrains.com/issue/KT-82230) Component: Gradle Incompatible change type: source Short summary: Kotlin 2.4.0 removes generated consumable Gradle configurations that expose Kotlin/Native Apple frameworks as outgoing artifacts. Deprecation cycle: * 2.4.0: remove consumable configurations for Kotlin/Native Apple frameworks ### Remove deprecated task, compilation, and DSL APIs from the Kotlin Gradle plugin Tip: Issue: [KT-85509](https://youtrack.jetbrains.com/issue/KT-85509) Component: Gradle Incompatible change type: source Short summary: Kotlin 2.4.0 removes the following deprecated Kotlin Gradle plugin APIs: Compile task configuration APIs: * `KotlinJvmCompile.parentKotlinOptions` * `KotlinJvmCompile.moduleName` * `KotlinJvmFactory.createKotlinJvmOptions()` * `BaseKotlinCompile.moduleName` from `KotlinCompile` and `Kotlin2JsCompile` tasks Kotlin Multiplatform hierarchy and target APIs: * `DeprecatedKotlinTargetHierarchyDsl` * `KotlinMultiplatformExtension.targetHierarchy` * `KotlinTargetComponent.sourcesArtifacts` * `KotlinTarget.sourceSets` * `KotlinHierarchyBuilder.withoutCompilations()` * `KotlinHierarchyBuilder.filterCompilations()` * `KotlinHierarchyBuilder.withWasm()` * `KotlinCompilation.defaultSourceSetName` Kotlin compilation task APIs: * `KotlinCompilation.compileKotlinTaskProvider` * `KotlinCompilation.compileKotlinTask` Kotlin dependency handler APIs: * `KotlinDependencyHandler.enforcedPlatform()` * `KotlinDependencyHandler.platform()` Other deprecated task and extension APIs: * `KaptExtension.processors` * `KotlinTest.excludes` * `KotlinTest.fileResolver` * `KotlinTest.execHandleFactory` * `IncrementalSyncTask.destinationDir` To migrate, remove usages of these APIs and use the replacements suggested by the deprecation diagnostics. Deprecation cycle: * 2.4.0: remove the deprecated APIs ### Deprecate explicit shrunk classpath snapshot configuration Tip: Issue: [KT-75837](https://youtrack.jetbrains.com/issue/KT-75837) Component: Build tools API Incompatible change type: source Short summary: The `shrunkClasspathSnapshot` configuration parameter in `ClasspathSnapshotBasedIncrementalCompilationApproachParameters` is deprecated. The shrunk classpath snapshot is an internal incremental compilation cache, so the compiler now creates and manages it automatically under the incremental compiler metadata `workingDirectory`. To migrate, use the automatically managed snapshot file, instead of passing a value to `shrunkClasspathSnapshot`. Deprecation cycle: * 2.4.0: report a warning when using `shrunkClasspathSnapshot` ### Remove redundant ABI validation Gradle DSL elements Tip: Issue: [KT-80685](https://youtrack.jetbrains.com/issue/KT-80685) Component: Gradle Incompatible change type: source Short summary: Kotlin 2.4.0 simplifies the [ABI validation](gradle-binary-compatibility-validation.html) Gradle DSL and removes redundant configuration entries. To migrate, configure report settings directly in `abiValidation {}` instead of `abiValidation { legacyDump { ... } }`, remove `abiValidation { klib { enabled = ... } }`, and use `keepLocallyUnsupportedTargets` instead of `klib.keepUnsupportedTargets`. Deprecation cycle: * 2.4.0: remove redundant ABI validation DSL elements ### Deprecate obsolete Compose compiler Gradle plugin options Tip: Issue: [KT-85343](https://youtrack.jetbrains.com/issue/KT-85343) Component: Gradle Incompatible change type: source Short summary: In Kotlin 2.4.0, the following deprecated Compose compiler Gradle plugin options now report an error when used: * `generateFunctionKeyMetaClasses` * `enableIntrinsicRemember` * `enableNonSkippingGroupOptimization` * `enableStrongSkippingMode` * `stabilityConfigurationFile` * `ComposeFeatureFlag.StrongSkipping` * `ComposeFeatureFlag.IntrinsicRemember` Use `featureFlags` instead of the deprecated feature options, and `stabilityConfigurationFiles` instead of `stabilityConfigurationFile`. Deprecation cycle: * 2.0.20: report warnings for `enableIntrinsicRemember`, `enableNonSkippingGroupOptimization`, and `enableStrongSkippingMode` * 2.1.0: report a warning for `stabilityConfigurationFile` * 2.4.0: raise the warnings to errors ### Report errors for obsolete Kotlin/Native Gradle task APIs Tip: Issue: [KT-85510](https://youtrack.jetbrains.com/issue/KT-85510) Component: Gradle Incompatible change type: source Short summary: The following deprecated Kotlin/Native Gradle task APIs now report an error when used: `AbstractKotlinNativeCompile` properties: * `additionalCompilerOptions` * `languageSettings` * `progressiveMode` `KotlinNativeCompile` properties: * `moduleName` * `konanDataDir` * `konanHome` * `languageVersion` * `apiVersion` * `enabledLanguageFeatures` * `optInAnnotationsInUse` * `additionalCompilerOptions` `CInteropProcess` properties: * `outputFile` * `konanDataDir` * `konanHome` * `defFile` `KotlinNativeLink` properties: * `languageSettings` * `additionalCompilerOptions` * `konanDataDir` * `konanHome` Additionally, the `KotlinNativeLink.compilation` property is removed. Deprecation cycle: * 2.4.0: report an error for the deprecated Kotlin/Native Gradle task APIs, remove the `KotlinNativeLink.compilation` property ### Report warnings for case mismatches in compiler argument values Tip: Issue: [KT-86059](https://youtrack.jetbrains.com/issue/KT-86059) Component: Build tools API Incompatible change type: source Short summary: Compiler arguments that accept a fixed set of values previously handled letter case inconsistently: some accepted any letter case, while others required an exact match. The [Build tools API](build-tools-api.html) now accepts any letter case for these values but reports a warning, for example `Case mismatch for -module-kind: expected 'commonjs', got 'CommonJS'`. To migrate, use the letter case listed for the argument in the [compiler reference](compiler-reference.html). Deprecation cycle: * 2.4.20: report a warning when the letter case of a compiler argument value doesn't match the expected value # Basic syntax overview 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 Core track](https://hyperskill.org/tracks?category=4&utm_source=jbkotlin_hs&utm_medium=referral&utm_campaign=kotlinlang-docs&utm_content=button_1&utm_term=22.03.23) by JetBrains Academy. ## Package definition and imports Package specification should be at the top of the source file: ```KOTLIN 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](packages.html). ## Program entry point An entry point of a Kotlin application is the `main` function: ```KOTLIN fun main() { println("Hello world!") } ``` Another form of `main` accepts a variable number of `String` arguments: ```KOTLIN fun main(args: Array) { println(args.contentToString()) } ``` ## Print to the standard output `print` prints its argument to the standard output: ```KOTLIN fun main() { //sampleStart print("Hello ") print("world!") //sampleEnd } ``` `println` prints its arguments and adds a line break, so that the next thing you print appears on the next line: ```KOTLIN fun main() { //sampleStart println("Hello world!") println(42) //sampleEnd } ``` ## Read from the standard input The `readln()` function reads from the standard input. This function reads the entire line the user enters as a string. You can use the `println()`, `readln()`, and `print()` functions together to print messages requesting and showing user input: ```KOTLIN // Prints a message to request input println("Enter any word: ") // Reads and stores the user input. For example: Happiness val yourWord = readln() // Prints a message with the input print("You entered the word: ") print(yourWord) // You entered the word: Happiness ``` For more information, see [Read standard input](read-standard-input.html). ## Functions A function with two `Int` parameters and `Int` return type: ```KOTLIN //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)) } ``` A function body can be an expression. Its return type is inferred: ```KOTLIN //sampleStart fun sum(a: Int, b: Int) = a + b //sampleEnd fun main() { println("sum of 19 and 23 is ${sum(19, 23)}") } ``` A function that returns no meaningful value: ```KOTLIN //sampleStart fun printSum(a: Int, b: Int): Unit { println("sum of $a and $b is ${a + b}") } //sampleEnd fun main() { printSum(-1, 8) } ``` `Unit` return type can be omitted: ```KOTLIN //sampleStart fun printSum(a: Int, b: Int) { println("sum of $a and $b is ${a + b}") } //sampleEnd fun main() { printSum(-1, 8) } ``` See [Functions](functions.html). ## Variables In Kotlin, you declare a variable starting with a keyword, `val` or `var`, followed by the name of the variable. Use the `val` keyword to declare variables that are assigned a value only once. These are immutable, read-only local variables that can't be reassigned a different value after initialization: ```KOTLIN fun main() { //sampleStart // Declares the variable x and initializes it with the value of 5 val x: Int = 5 // 5 //sampleEnd println(x) } ``` Use the `var` keyword to declare variables that can be reassigned. These are mutable variables, and you can change their values after initialization: ```KOTLIN fun main() { //sampleStart // Declares the variable x and initializes it with the value of 5 var x: Int = 5 // Reassigns a new value of 6 to the variable x x += 1 // 6 //sampleEnd println(x) } ``` Kotlin supports type inference and automatically identifies the data type of a declared variable. When declaring a variable, you can omit the type after the variable name: ```KOTLIN fun main() { //sampleStart // Declares the variable x with the value of 5;`Int` type is inferred val x = 5 // 5 //sampleEnd println(x) } ``` You can use variables only after initializing them. You can either initialize a variable at the moment of declaration or declare a variable first and initialize it later. In the second case, you must specify the data type: ```KOTLIN fun main() { //sampleStart // Initializes the variable x at the moment of declaration; type is not required val x = 5 // Declares the variable c without initialization; type is required val c: Int // Initializes the variable c after declaration c = 3 // 5 // 3 //sampleEnd println(x) println(c) } ``` You can declare variables at the top level: ```KOTLIN //sampleStart val PI = 3.14 var x = 0 fun incrementX() { x += 1 } // x = 0; PI = 3.14 // incrementX() // x = 1; PI = 3.14 //sampleEnd fun main() { println("x = $x; PI = $PI") incrementX() println("incrementX()") println("x = $x; PI = $PI") } ``` For information about declaring properties, see [Properties](properties.html). ## Creating classes and instances To define a class, use the `class` keyword: ```KOTLIN class Shape ``` Properties of a class can be listed in its declaration or body: ```KOTLIN class Rectangle(val height: Double, val length: Double) { val perimeter = (height + length) * 2 } ``` The default constructor with parameters listed in the class declaration is available automatically: ```KOTLIN class Rectangle(val height: Double, val length: Double) { val perimeter = (height + length) * 2 } fun main() { val rectangle = Rectangle(5.0, 2.0) println("The perimeter is ${rectangle.perimeter}") } ``` Inheritance between classes is declared by a colon (`:`). Classes are `final` by default; to make a class inheritable, mark it as `open`: ```KOTLIN open class Shape class Rectangle(val height: Double, val length: Double): Shape() { val perimeter = (height + length) * 2 } ``` For more information about constructors and inheritance, see [Classes](classes.html) and [Objects and instances](object-declarations.html). ## Comments Just like most modern languages, Kotlin supports single-line (or end-of-line) and multi-line (block) comments: ```KOTLIN // This is an end-of-line comment /* This is a block comment on multiple lines. */ ``` Block comments in Kotlin can be nested: ```KOTLIN /* The comment starts here /* contains a nested comment *​/ and ends here. */ ``` See [Documenting Kotlin Code](kotlin-doc.html) for information on the documentation comment syntax. ## String templates ```KOTLIN 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) } ``` See [String templates](strings.html#string-templates) for details. ## Conditional expressions ```KOTLIN //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)}") } ``` In Kotlin, `if` can also be used as an expression: ```KOTLIN //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)}") } ``` See [if-expressions](control-flow.html#if-expression). ## for loop ```KOTLIN fun main() { //sampleStart val items = listOf("apple", "banana", "kiwifruit") for (item in items) { println(item) } //sampleEnd } ``` or: ```KOTLIN fun main() { //sampleStart val items = listOf("apple", "banana", "kiwifruit") for (index in items.indices) { println("item at $index is ${items[index]}") } //sampleEnd } ``` See [for loop](control-flow.html#for-loops). ## while loop ```KOTLIN 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 } ``` See [while loop](control-flow.html#while-loops). ## when expression ```KOTLIN //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")) } ``` See [when expressions and statements](control-flow.html#when-expressions-and-statements). ## Ranges Check if a number is within a range using `in` operator: ```KOTLIN fun main() { //sampleStart val x = 10 val y = 9 if (x in 1..y+1) { println("fits in range") } //sampleEnd } ``` Check if a number is out of range: ```KOTLIN 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 } ``` Iterate over a range: ```KOTLIN fun main() { //sampleStart for (x in 1..5) { print(x) } //sampleEnd } ``` Or over a progression: ```KOTLIN fun main() { //sampleStart for (x in 1..10 step 2) { print(x) } println() for (x in 9 downTo 0 step 3) { print(x) } //sampleEnd } ``` See [Ranges and progressions](ranges.html). ## Collections Iterate over a collection: ```KOTLIN fun main() { val items = listOf("apple", "banana", "kiwifruit") //sampleStart for (item in items) { println(item) } //sampleEnd } ``` Check if a collection contains an object using `in` operator: ```KOTLIN fun main() { val items = setOf("apple", "banana", "kiwifruit") //sampleStart when { "orange" in items -> println("juicy") "apple" in items -> println("apple is fine too") } //sampleEnd } ``` Use [lambda expressions](lambdas.html) to filter and map collections: ```KOTLIN fun main() { //sampleStart val fruits = listOf("banana", "avocado", "apple", "kiwifruit") fruits .filter { it.startsWith("a") } .sortedBy { it } .map { it.uppercase() } .forEach { println(it) } //sampleEnd } ``` See [Collections overview](collections-overview.html). ## Nullable values and null checks A reference must be explicitly marked as nullable when a `null` value is possible. Nullable type names have `?` at the end. For example, `Int?`. Return `null` if `str` does not hold an integer: ```KOTLIN fun parseInt(str: String): Int? { return str.toIntOrNull() } ``` Use a function returning nullable value: ```KOTLIN 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") } ``` or: ```KOTLIN 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") } ``` See [Null-safety](null-safety.html). ## Type checks and automatic casts 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: ```KOTLIN //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())) } ``` or: ```KOTLIN //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())) } ``` or even: ```KOTLIN //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) } ``` See [Classes](classes.html) and [Type casts](typecasts.html). # Keywords and operators ## Hard keywords The following tokens are always interpreted as keywords and cannot be used as identifiers: * `as` * is used for [type casts](typecasts.html#unsafe-cast-operator). * specifies an [alias for an import](packages.html#imports) * `as?` is used for [safe type casts](typecasts.html#unsafe-cast-operator). * `break` [terminates the execution of a loop](returns.html). * `class` declares a [class](classes.html). * `continue` [proceeds to the next step of the nearest enclosing loop](returns.html). * `do` begins a [do/while loop](control-flow.html#while-loops) (a loop with a postcondition). * `else` defines the branch of an [if expression](control-flow.html#if-expression) that is executed when the condition is false. * `false` specifies the 'false' value of the [Boolean type](booleans.html). * `for` begins a [for loop](control-flow.html#for-loops). * `fun` declares a [function](functions.html). * `if` begins an [if expression](control-flow.html#if-expression). * `in` * specifies the object being iterated in a [for loop](control-flow.html#for-loops). * is used as an infix operator to check that a value belongs to [a range](ranges.html), a collection, or another entity that [defines a 'contains' method](operator-overloading.html#in-operator). * is used in [when expressions](control-flow.html#when-expressions-and-statements) for the same purpose. * marks a type parameter as [contravariant](generics.html#declaration-site-variance). * `!in` * is used as an operator to check that a value does NOT belong to [a range](ranges.html), a collection, or another entity that [defines a 'contains' method](operator-overloading.html#in-operator). * is used in [when expressions](control-flow.html#when-expressions-and-statements) for the same purpose. * `interface` declares an [interface](interfaces.html). * `is` * checks that [a value has a certain type](typecasts.html#is-and-is-operators). * is used in [when expressions](control-flow.html#when-expressions-and-statements) for the same purpose. * `!is` * checks that [a value does NOT have a certain type](typecasts.html#is-and-is-operators). * is used in [when expressions](control-flow.html#when-expressions-and-statements) for the same purpose. * `null` is a constant representing an object reference that doesn't point to any object. * `object` declares [a class and its instance at the same time](object-declarations.html). * `package` specifies the [package for the current file](packages.html). * `return` [returns from the nearest enclosing function or anonymous function](returns.html). * `super` * [refers to the superclass implementation of a method or property](inheritance.html#calling-the-superclass-implementation). * [calls the superclass constructor from a secondary constructor](classes.html#inheritance). * `this` * refers to [the current receiver](this-expressions.html). * [calls another constructor of the same class from a secondary constructor](classes.html#constructors-and-initializer-blocks). * `throw` [throws an exception](exceptions.html). * `true` specifies the 'true' value of the [Boolean type](booleans.html). * `try` [begins an exception-handling block](exceptions.html). * `typealias` declares a [type alias](type-aliases.html). * `typeof` is reserved for future use. * `val` declares a read-only [property](properties.html) or [local variable](basic-syntax.html#variables). * `var` declares a mutable [property](properties.html) or [local variable](basic-syntax.html#variables). * `when` begins a [when expression](control-flow.html#when-expressions-and-statements) (executes one of the given branches). * `while` begins a [while loop](control-flow.html#while-loops) (a loop with a precondition). ## Soft keywords The following tokens act as keywords in the context in which they are applicable, and they can be used as identifiers in other contexts: * `by` * [delegates the implementation of an interface to another object](delegation.html). * [delegates the implementation of the accessors for a property to another object](delegated-properties.html). * `catch` begins a block that [handles a specific exception type](exceptions.html). * `constructor` declares a [primary or secondary constructor](classes.html#constructors-and-initializer-blocks). * `delegate` is used as an [annotation use-site target](annotations.html#annotation-use-site-targets). * `dynamic` references a [dynamic type](dynamic-type.html) in Kotlin/JS code. * `field` * declares an [explicit backing field](properties.html#explicit-backing-fields). * is used as an [annotation use-site target](annotations.html#annotation-use-site-targets). * `file` is used as an [annotation use-site target](annotations.html#annotation-use-site-targets). * `finally` begins a block that [is always executed when a try block exits](exceptions.html). * `get` * declares the [getter of a property](properties.html). * is used as an [annotation use-site target](annotations.html#annotation-use-site-targets). * `import` [imports a declaration from another package into the current file](packages.html). * `init` begins an [initializer block](classes.html#constructors-and-initializer-blocks). * `param` is used as an [annotation use-site target](annotations.html#annotation-use-site-targets). * `property` is used as an [annotation use-site target](annotations.html#annotation-use-site-targets). * `receiver` is used as an [annotation use-site target](annotations.html#annotation-use-site-targets). * `set` * declares the [setter of a property](properties.html). * is used as an [annotation use-site target](annotations.html#annotation-use-site-targets). * `setparam` is used as an [annotation use-site target](annotations.html#annotation-use-site-targets). * `value` with the `class` keyword declares an [inline class](inline-classes.html). * `where` specifies the [constraints for a generic type parameter](generics.html#upper-bounds). ## Modifier keywords The following tokens act as keywords in modifier lists of declarations, and they can be used as identifiers in other contexts: * `abstract` marks a class or member as [abstract](classes.html#abstract-classes). * `actual` denotes a platform-specific implementation in [multiplatform projects](https://kotlinlang.org/docs/multiplatform/multiplatform-expect-actual.html). * `annotation` declares an [annotation class](annotations.html). * `companion` declares a [companion object](object-declarations.html#companion-objects). * `const` marks a property as a [compile-time constant](properties.html#compile-time-constants). * `crossinline` forbids [non-local returns in a lambda passed to an inline function](inline-functions.html#returns). * `data` instructs the compiler to [generate canonical members for a class](data-classes.html). * `enum` declares an [enumeration](enum-classes.html). * `expect` marks a declaration as [platform-specific](https://kotlinlang.org/docs/multiplatform/multiplatform-expect-actual.html), expecting an implementation in platform modules. * `external` marks a declaration as implemented outside of Kotlin (accessible through [JNI](java-interop.html#using-jni-with-kotlin) or in [JavaScript](js-interop.html#external-modifier)). * `final` forbids [overriding a member](inheritance.html#overriding-methods). * `infix` allows calling a function using [infix notation](functions.html#infix-notation). * `inline` tells the compiler to [inline a function and the lambdas passed to it at the call site](inline-functions.html). * `inner` allows referring to an outer class instance from a [nested class](nested-classes.html). * `internal` marks a declaration as [visible in the current module](visibility-modifiers.html). * `lateinit` allows initializing a [non-nullable property outside of a constructor](properties.html#late-initialized-properties-and-variables). * `noinline` turns off [inlining of a lambda passed to an inline function](inline-functions.html#noinline). * `open` allows [subclassing a class or overriding a member](classes.html#inheritance). * `operator` marks a function as [overloading an operator or implementing a convention](operator-overloading.html). * `out` marks a type parameter as [covariant](generics.html#declaration-site-variance). * `override` marks a member as an [override of a superclass member](inheritance.html#overriding-methods). * `private` marks a declaration as [visible in the current class or file](visibility-modifiers.html). * `protected` marks a declaration as [visible in the current class and its subclasses](visibility-modifiers.html). * `public` marks a declaration as [visible anywhere](visibility-modifiers.html). * `reified` marks a type parameter of an inline function as [accessible at runtime](inline-functions.html#reified-type-parameters). * `sealed` declares a [sealed class](sealed-classes.html) (a class with restricted subclassing). * `suspend` marks a function or lambda as suspending (usable as a [coroutine](coroutines-overview.html)). * `tailrec` marks a function as [tail-recursive](functions.html#tail-recursive-functions) (allowing the compiler to replace recursion with iteration). * `vararg` allows [passing a variable number of arguments for a parameter](functions.html#variable-number-of-arguments-varargs). ## Special identifiers The following identifiers are defined by the compiler in specific contexts, and they can be used as regular identifiers in other contexts: * `field` is used inside a property accessor to refer to the [backing field of the property](properties.html#backing-fields). * `it` is used inside a lambda to [refer to its parameter implicitly](lambdas.html#it-implicit-name-of-a-single-parameter). ## Operators and special symbols Kotlin supports the following operators and special symbols: * `+`, `-`, `*`, `/`, `%` - mathematical operators * `*` is also used to [pass an array to a vararg parameter](functions.html#variable-number-of-arguments-varargs). * `=` * assignment operator. * is used to specify [default values for parameters](functions.html#parameters-with-default-values). * `+=`, `-=`, `*=`, `/=`, `%=` - [augmented assignment operators](operator-overloading.html#augmented-assignments). * `++`, `--` - [increment and decrement operators](operator-overloading.html#increments-and-decrements). * `&&`, `||`, `!` - logical 'and', 'or', 'not' operators (for bitwise operations, use the corresponding [infix functions](numbers.html#bitwise-operations) instead). * `==`, `!=` - [equality operators](operator-overloading.html#equality-and-inequality-operators) (translated to calls of `equals()` for non-primitive types). * `===`, `!==` - [referential equality operators](equality.html#referential-equality). * `<`, `>`, `<=`, `>=` - [comparison operators](operator-overloading.html#comparison-operators) (translated to calls of `compareTo()` for non-primitive types). * `[`, `]` - [indexed access operator](operator-overloading.html#indexed-access-operator) (translated to calls of `get` and `set`). * `!!` [asserts that an expression is non-nullable](null-safety.html#not-null-assertion-operator). * `?.` performs a [safe call](null-safety.html#safe-call-operator) (calls a method or accesses a property if the receiver is non-nullable). * `?:` takes the right-hand value if the left-hand value is null (the [elvis operator](null-safety.html#elvis-operator)). * `::` creates a [member reference](reflection.html#function-references) or a [class reference](reflection.html#class-references). * `.` * accesses [members](classes.html), including [nested classes](nested-classes.html) and [enum entries](enum-classes.html#working-with-enum-constants). * defines and calls [extensions](extensions.html). * qualifies names and [packages](packages.html). * separates the integer and fractional parts of a [floating-point literal](numbers.html#floating-point-types). * `..`, `..<` create [ranges](ranges.html). * `:` separates a name from a type in a declaration. * `?` marks a type as [nullable](null-safety.html#nullable-types-and-non-nullable-types). * `->` * separates the parameters and body of a [lambda expression](lambdas.html#lambda-expression-syntax). * separates the parameters and return type declaration in a [function type](lambdas.html#function-types). * separates the condition and body of a [when expression](control-flow.html#when-expressions-and-statements) branch. * `@` * introduces an [annotation](annotations.html#usage). * introduces or references a [loop label](returns.html#break-and-continue-labels). * introduces or references a [lambda label](returns.html#return-to-labels). * references a ['this' expression from an outer scope](this-expressions.html#qualified-this). * references an [outer superclass](inheritance.html#calling-the-superclass-implementation). * `;` separates multiple statements on the same line. * `$` references a variable or expression in a [string template](strings.html#string-templates). * `_` * substitutes an unused parameter in a [lambda expression](lambdas.html#underscore-for-unused-variables). * substitutes an unused parameter in a [destructuring declaration](destructuring-declarations.html#underscore-for-unused-variables). For operator precedence, see [this reference](https://kotlinlang.org/grammar/#expressions) in Kotlin grammar. # Packages and imports In a Kotlin project, code is organized using packages and imports: * A package is a container for one or more Kotlin files. Files are linked to a package using a `package` header. * An import is a directive that makes entities from other packages available in the current file. ## Package headers A source file may start with a package header: ```KOTLIN package org.example fun printMessage() { /*...*/ } class Message(val text: String) { /*...*/ } ``` All contents of the source file, such as classes and functions, belong to this package. Their fully qualified name combines the package name with the entity's name. In this example: * The fully qualified name of `printMessage()` is `org.example.printMessage`. * The fully qualified name of `Message` is `org.example.Message`. If a file has no package header, its contents belong to the root package. ## Imports To use an entity from a file in a different package, use an `import` directive. In addition to the default imports, each file may declare its own imports. ### Import a single entity Import a specific entity so you can use it without qualification: ```KOTLIN // Message is accessible without qualification import org.example.Message fun main() { val message = Message("Hello") println(message.text) } ``` ### Import the contents of a scope Star imports, ending in an asterisk `*`, import all named entities inside the corresponding scope: ```KOTLIN // Everything in org.example is accessible import org.example.* fun main() { printMessage() val message = Message("Hi") } ``` If you import an entity with both a star import and an explicit import, the explicit import takes priority during overload resolution. ### Resolve name clashes with aliases If two imported entities have the same name, use the `as` keyword to locally rename one of them: ```KOTLIN // Message refers to org.example.Message import org.example.Message // TestMessage refers to org.test.Message import org.test.Message as TestMessage fun main() { val a = Message("from example") val b = TestMessage("from test") } ``` ### What you can import The `import` keyword is not limited to classes. You can import any of the following entities, whether they come from a package, a class, an object, or an enum: * Top-level functions and properties declared directly inside a package: ```KOTLIN import org.example.printMessage // Top-level function import org.example.VERSION // Top-level property ``` * Functions and properties from [object declarations](object-declarations.html#object-declarations-overview): ```KOTLIN import org.example.Config.DEFAULT_TIMEOUT // Property from an object import org.example.Config.loadSettings // Function from an object ``` * Members of a [companion object](object-declarations.html#companion-objects), referenced through the enclosing class name: ```KOTLIN import org.example.MyClass.create // Refers to MyClass.Companion.create ``` * [Enum constants](enum-classes.html): ```KOTLIN import org.example.Color.RED import org.example.Color.GREEN ``` * Nested classes: ```KOTLIN import org.example.Outer.Nested ``` ## Default imports Kotlin includes the following imports by default: * [kotlin.*](https://kotlinlang.org/api/core/kotlin-stdlib/kotlin/index.html) * [kotlin.annotation.*](https://kotlinlang.org/api/core/kotlin-stdlib/kotlin.annotation/index.html) * [kotlin.collections.*](https://kotlinlang.org/api/core/kotlin-stdlib/kotlin.collections/index.html) * [kotlin.comparisons.*](https://kotlinlang.org/api/core/kotlin-stdlib/kotlin.comparisons/index.html) * [kotlin.io.*](https://kotlinlang.org/api/core/kotlin-stdlib/kotlin.io/index.html) * [kotlin.ranges.*](https://kotlinlang.org/api/core/kotlin-stdlib/kotlin.ranges/index.html) * [kotlin.sequences.*](https://kotlinlang.org/api/core/kotlin-stdlib/kotlin.sequences/index.html) * [kotlin.text.*](https://kotlinlang.org/api/core/kotlin-stdlib/kotlin.text/index.html) * [kotlin.math.*](https://kotlinlang.org/api/core/kotlin-stdlib/kotlin.math/index.html) Kotlin imports additional packages depending on the target platform: * JVM: * [java.lang.*](https://docs.oracle.com/javase/8/docs/api/java/lang/package-summary.html) * [kotlin.jvm.*](https://kotlinlang.org/api/core/kotlin-stdlib/kotlin.jvm/index.html) * JS: * [kotlin.js.*](https://kotlinlang.org/api/core/kotlin-stdlib/kotlin.js/index.html) ## Visibility and imports The ability to import an entity depends on its [visibility modifiers](visibility-modifiers.html): * `public` entities can be imported anywhere. * `internal` entities can be imported only within the same module. * `protected` entities cannot be imported. * Top-level `private` entities are only accessible within their declaring file. * Other `private` entities cannot be imported. # Annotations Annotations are tags that you can use to attach metadata to elements in your code. Tools and frameworks process this metadata during compilation and runtime, and perform different actions based on it. You can annotate your code to simplify and automate common tasks, such as generating boilerplate code, enforcing coding standards or writing documentation. Tip: If you want to develop your own annotation processors, you can use the [Kotlin Symbol Processing (KSP)](ksp-overview.html) API. ## Declaration Annotations are a special type of class. To declare an annotation, use the `annotation` keyword before the class declaration: ```KOTLIN annotation class Fancy ``` Additional attributes of the annotation can be specified by annotating the annotation class with meta-annotations: * [@Target](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.annotation/-target/index.html) specifies the possible kinds of elements which can be annotated with the annotation (such as classes, functions, properties, and expressions); * [@Retention](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.annotation/-retention/index.html) specifies whether the annotation is stored in the compiled class files and whether it's visible through reflection at runtime (by default, both are true); * [@Repeatable](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.annotation/-repeatable/index.html) allows using the same annotation on a single element multiple times; * [@MustBeDocumented](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.annotation/-must-be-documented/index.html) specifies that the annotation is part of the public API and should be included in the class or method signature shown in the generated API documentation. ```KOTLIN @Target(AnnotationTarget.CLASS, AnnotationTarget.FUNCTION, AnnotationTarget.TYPE_PARAMETER, AnnotationTarget.VALUE_PARAMETER, AnnotationTarget.EXPRESSION) @Retention(AnnotationRetention.SOURCE) @MustBeDocumented annotation class Fancy ``` ## Usage ```KOTLIN @Fancy class Foo { @Fancy fun baz(@Fancy foo: Int): Int { return (@Fancy 1) } } ``` If you need to annotate the primary constructor of a class, you need to add the `constructor` keyword to the constructor declaration, and add the annotations before it: ```KOTLIN class Foo @Inject constructor(dependency: MyDependency) { ... } ``` You can also annotate property accessors: ```KOTLIN class Foo { var x: MyDependency? = null @Inject set } ``` ## Constructors Annotations can have constructors that take parameters. ```KOTLIN annotation class Special(val why: String) @Special("example") class Foo {} ``` Allowed parameter types are: * Types that correspond to Java primitive types (Int, Long etc.) * Strings * Classes (`Foo::class`) * Enums * Other annotations * Arrays of the types listed above Annotation parameters cannot have nullable types, because the JVM does not support storing `null` as a value of an annotation attribute. If an annotation is used as a parameter of another annotation, its name is not prefixed with the `@` character: ```KOTLIN annotation class ReplaceWith(val expression: String) annotation class Deprecated( val message: String, val replaceWith: ReplaceWith = ReplaceWith("")) @Deprecated("This function is deprecated, use === instead", ReplaceWith("this === other")) ``` If you need to specify a class as an argument of an annotation, use a Kotlin class ([KClass](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.reflect/-k-class/index.html)). The Kotlin compiler will automatically convert it to a Java class, so that the Java code can access the annotations and arguments normally. ```KOTLIN import kotlin.reflect.KClass annotation class Ann(val arg1: KClass<*>, val arg2: KClass) @Ann(String::class, Int::class) class MyClass ``` ## Instantiation In Java, an annotation type is a form of an interface, so you can implement it and use an instance. As an alternative to this mechanism, Kotlin lets you call a constructor of an annotation class in arbitrary code and similarly use the resulting instance. ```KOTLIN annotation class InfoMarker(val info: String) fun processInfo(marker: InfoMarker): Unit = TODO() fun main(args: Array) { if (args.isNotEmpty()) processInfo(getAnnotationReflective(args)) else processInfo(InfoMarker("default")) } ``` Learn more about instantiation of annotation classes in [this KEEP](https://github.com/Kotlin/KEEP/blob/master/proposals/annotation-instantiation.md). ## Lambdas Annotations can also be used on lambdas. They will be applied to the `invoke()` method into which the body of the lambda is generated. This is useful for frameworks like [Quasar](https://docs.paralleluniverse.co/quasar/), which uses annotations for concurrency control. ```KOTLIN annotation class Suspendable val f = @Suspendable { Fiber.sleep(10) } ``` ## Annotation use-site targets When you're annotating a property or a primary constructor parameter, there are multiple Java elements that are generated from the corresponding Kotlin element, and therefore multiple possible locations for the annotation in the generated Java bytecode. To specify how exactly the annotation should be generated, use the following syntax: ```KOTLIN class Example(@field:Ann val foo, // annotate only the Java field @get:Ann val bar, // annotate only the Java getter @param:Ann val quux) // annotate only the Java constructor parameter ``` The same syntax can be used to annotate the entire file. To do this, put an annotation with the target `file` at the top level of a file, before the package directive or before all imports if the file is in the default package: ```KOTLIN @file:JvmName("Foo") package org.jetbrains.demo ``` If you have multiple annotations with the same target, you can avoid repeating the target by adding brackets after the target and putting all the annotations inside the brackets (except for the `all` meta-target): ```KOTLIN class Example { @set:[Inject VisibleForTesting] var collaborator: Collaborator } ``` The full list of supported use-site targets is: * `file` * `field` * `property` (annotations with this target are not visible to Java) * `get` (property getter) * `set` (property setter) * `all` (a meta-target for properties, see the [all meta-target](#all-meta-target) section for more information) * `receiver` (receiver parameter of an extension function or property) To annotate the receiver parameter of an extension function, use the following syntax: ```KOTLIN fun @receiver:Fancy String.myExtension() { ... } ``` * `param` (constructor parameter) * `setparam` (property setter parameter) * `delegate` (the field storing the delegate instance for a delegated property) ### Defaults when no use-site targets are specified If you don't specify a use-site target, the compiler chooses the target according to the `@Target` annotation of the annotation you use. If there are multiple applicable targets, the compiler chooses one or more of them in the following order: * The constructor parameter target (`param`). * The property target (`property`). * The field target (`field`), if it's applicable and the property target (`property`) isn't. If none of `param`, `property`, or `field` are applicable, the annotation is invalid, and you need to specify a use-site target explicitly. Let's use the [@Email annotation from Jakarta Bean Validation](https://jakarta.ee/specifications/bean-validation/3.0/apidocs/jakarta/validation/constraints/email): ```JAVA @Target(value={METHOD,FIELD,ANNOTATION_TYPE,CONSTRUCTOR,PARAMETER,TYPE_USE}) public @interface Email { } ``` With this annotation, consider the following example: ```KOTLIN data class User(val username: String, // @Email is now equivalent to @param:Email @field:Email @Email val email: String) { // @Email is still equivalent to @field:Email @Email val secondaryEmail: String? = null } ``` In this example, the `@Email` annotation applies to both the constructor parameter and the field targets for the `email` property because the property: * Is declared in the primary constructor. * Has no custom getter or setter, so the compiler generates a backing field. The `@Email` annotation only applies to the field target for the `secondaryEmail` property because the property: * Isn't declared in the primary constructor. * Has no custom getter or setter, so the compiler generates a backing field. ### `all` meta-target The `all` target makes it easier to apply the same annotation not only to the parameter and the property or field, but also to the corresponding getter and setter. Specifically, the annotation marked with `all` is propagated, if applicable: * To the constructor parameter (`param`) if the property is defined in the primary constructor. * To the property itself (`property`). * To the backing field (`field`) if the property has one. * To the getter (`get`). * To the setter parameter (`setparam`) if the property is defined as `var`. * To the Java-only target `RECORD_COMPONENT` if the class has the `@JvmRecord` annotation. Let's use the [@Email annotation from Jakarta Bean Validation](https://jakarta.ee/specifications/bean-validation/3.0/apidocs/jakarta/validation/constraints/email), which is defined as follows: ```JAVA @Target(value={METHOD,FIELD,ANNOTATION_TYPE,CONSTRUCTOR,PARAMETER,TYPE_USE}) public @interface Email { } ``` In the example below, this `@Email` annotation is applied to all relevant targets: ```KOTLIN data class User( val username: String, // Applies @Email to param, field, and get @all:Email val email: String, // Applies @Email to param, field, get, and setparam @all:Email var name: String, ) { // Applies @Email to field and getter (not param since it's not in the constructor) @all:Email val secondaryEmail: String? = null } ``` You can use the `all` meta-target with any property, both inside and outside the primary constructor. #### Limitations The `all` target comes with some limitations: * It does not propagate an annotation to types, potential extension receivers, or context receivers or parameters. * It cannot be used with multiple annotations: ```KOTLIN @all:[A B] // forbidden, use @all:A @all:B val x: Int = 5 ``` * It cannot be used with [delegated properties](delegated-properties.html). ## Java annotations Java annotations are 100% compatible with Kotlin: ```KOTLIN import org.junit.Test import org.junit.Assert.* import org.junit.Rule import org.junit.rules.* class Tests { // apply @Rule annotation to property getter @get:Rule val tempFolder = TemporaryFolder() @Test fun simple() { val f = tempFolder.newFile() assertEquals(42, getTheAnswer()) } } ``` Since the order of parameters for an annotation written in Java is not defined, you can't use a regular function call syntax for passing the arguments. Instead, you need to use the named argument syntax: ```JAVA // Java public @interface Ann { int intValue(); String stringValue(); } ``` ```KOTLIN // Kotlin @Ann(intValue = 1, stringValue = "abc") class C ``` Just like in Java, a special case is the `value` parameter; its value can be specified without an explicit name: ```JAVA // Java public @interface AnnWithValue { String value(); } ``` ```KOTLIN // Kotlin @AnnWithValue("abc") class C ``` ### Arrays as annotation parameters If the `value` argument in Java has an array type, it becomes a `vararg` parameter in Kotlin: ```JAVA // Java public @interface AnnWithArrayValue { String[] value(); } ``` ```KOTLIN // Kotlin @AnnWithArrayValue("abc", "foo", "bar") class C ``` For other arguments that have an array type, you need to use the array literal syntax or `arrayOf(...)`: ```JAVA // Java public @interface AnnWithArrayMethod { String[] names(); } ``` ```KOTLIN @AnnWithArrayMethod(names = ["abc", "foo", "bar"]) class C ``` ### Accessing properties of an annotation instance Values of an annotation instance are exposed as properties to Kotlin code: ```JAVA // Java public @interface Ann { int value(); } ``` ```KOTLIN // Kotlin fun foo(ann: Ann) { val i = ann.value } ``` ### Ability to not generate JVM 1.8+ annotation targets If a Kotlin annotation has `TYPE` among its Kotlin targets, the annotation maps to `java.lang.annotation.ElementType.TYPE_USE` in its list of Java annotation targets. This is just like how the `TYPE_PARAMETER` Kotlin target maps to the `java.lang.annotation.ElementType.TYPE_PARAMETER` Java target. This is an issue for Android clients with API levels less than 26, which don't have these targets in the API. To avoid generating the `TYPE_USE` and `TYPE_PARAMETER` annotation targets, use the new compiler argument `-Xno-new-java-annotation-targets`. ## Repeatable annotations Just like [in Java](https://docs.oracle.com/javase/tutorial/java/annotations/repeating.html), Kotlin has repeatable annotations, which can be applied to a single code element multiple times. To make your annotation repeatable, mark its declaration with the [@kotlin.annotation.Repeatable](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.annotation/-repeatable/) meta-annotation. This will make it repeatable both in Kotlin and Java. Java repeatable annotations are also supported from the Kotlin side. The main difference with the scheme used in Java is the absence of a containing annotation, which the Kotlin compiler generates automatically with a predefined name. For an annotation in the example below, it will generate the containing annotation `@Tag.Container`: ```KOTLIN @Repeatable annotation class Tag(val name: String) // The compiler generates the @Tag.Container containing annotation ``` You can set a custom name for a containing annotation by applying the [@kotlin.jvm.JvmRepeatable](https://kotlinlang.org/api/core/kotlin-stdlib/kotlin.jvm/-jvm-repeatable/) meta-annotation and passing an explicitly declared containing annotation class as an argument: ```KOTLIN @JvmRepeatable(Tags::class) annotation class Tag(val name: String) annotation class Tags(val value: Array) ``` To extract Kotlin or Java repeatable annotations via reflection, use the [KAnnotatedElement.findAnnotations()](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.reflect.full/find-annotations.html) function. Learn more about Kotlin repeatable annotations in [this KEEP](https://github.com/Kotlin/KEEP/blob/master/proposals/repeatable-annotations.md). # Visibility modifiers Classes, objects, interfaces, constructors, and functions, as well as properties and their setters, can have visibility modifiers. Getters always have the same visibility as their properties. There are four visibility modifiers in Kotlin: `private`, `protected`, `internal`, and `public`. The default visibility is `public`. On this page, you'll learn how the modifiers apply to different types of declaring scopes. ## Packages Functions, properties, classes, objects, and interfaces can be declared at the "top-level" directly inside a package: ```KOTLIN // file name: example.kt package foo fun baz() { ... } class Bar { ... } ``` * If you don't use a visibility modifier, `public` is used by default, which means that your declarations will be visible everywhere. * If you mark a declaration as `private`, it will only be visible inside the file that contains the declaration. * If you mark it as `internal`, it will be visible everywhere in the same [module](#modules). * The `protected` modifier is not available for top-level declarations. Note: To use a visible top-level declaration from another package, you should [import](packages.html#imports) it. Examples: ```KOTLIN // file name: example.kt package foo private fun foo() { ... } // visible inside example.kt public var bar: Int = 5 // property is visible everywhere private set // setter is visible only in example.kt internal val baz = 6 // visible inside the same module ``` ## Class members For members declared inside a class: * `private` means that the member is visible inside this class only (including all its members). * `protected` means that the member has the same visibility as one marked as `private`, but that it is also visible in subclasses. * `internal` means that any client inside this module who sees the declaring class sees its `internal` members. * `public` means that any client who sees the declaring class sees its `public` members. Note: In Kotlin, an outer class does not see private members of its inner classes. If you override a `protected` or an `internal` member and do not specify the visibility explicitly, the overriding member will also have the same visibility as the original. Examples: ```KOTLIN open class Outer { private val a = 1 protected open val b = 2 internal open val c = 3 val d = 4 // public by default protected class Nested { public val e: Int = 5 } } class Subclass : Outer() { // a is not visible // b, c and d are visible // Nested and e are visible override val b = 5 // 'b' is protected override val c = 7 // 'c' is internal } class Unrelated(o: Outer) { // o.a, o.b are not visible // o.c and o.d are visible (same module) // Outer.Nested is not visible, and Nested::e is not visible either } ``` ### Constructors Use the following syntax to specify the visibility of the primary constructor of a class: Note: You need to add an explicit `constructor` keyword. ```KOTLIN class C private constructor(a: Int) { ... } ``` Here the constructor is `private`. By default, all constructors are `public`, which effectively amounts to them being visible everywhere the class is visible (this means that a constructor of an `internal` class is only visible within the same module). For sealed classes, constructors are `protected` by default. For more information, see [Sealed classes](sealed-classes.html#constructors). ### Local declarations Local variables, functions, and classes can't have visibility modifiers. ## Modules The `internal` visibility modifier means that the member is visible within the same module. More specifically, a module is a set of Kotlin files compiled together, for example: * An IntelliJ IDEA module. * A Maven project. * A Gradle source set (with the exception that the `test` source set can access the internal declarations of `main`). # 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](https://www.jetbrains.com/idea/) and [Android Studio](https://developer.android.com/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 to Settings/Preferences | Editor | Code Style | Kotlin. 2. Click Set from.... 3. Select Kotlin style guide . ### Verify that your code follows the style guide 1. Go to Settings/Preferences | Editor | Inspections | General. 2. Switch on Incorrect formatting inspection. Additional inspections that verify other issues described in the style guide (such as naming conventions) are enabled by default. For more information, see the [Migrate to Kotlin code style with IntelliJ IDEA](code-style-migration-guide.html) guide. ## 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 the `org.example.kotlin` package and its subpackages, files with the `org.example.kotlin` package should be placed directly under the source root, and files in `org.example.kotlin.network.socket` should be in the `network/socket` subdirectory of the source root. Note: 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. Use [upper camel case](https://en.wikipedia.org/wiki/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 as `Util` 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 both `Platform.kt` files are in the same package, so the Kotlin JVM compiler produces two file facades, both of which have FQN `myPackage.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. Tip: 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: * 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 camel case (`org.example.myProject`). * Names of classes and objects use upper camel case: ```KOTLIN open class DeclarationProcessor { /*...*/ } object EmptyDeclarationProcessor : DeclarationProcessor() { /*...*/ } ``` ### Function names Names of functions, properties, and local variables start with a lowercase letter and use camel case without underscores: ```KOTLIN fun processDeclarations() { /*...*/ } var declarationCount = 1 ``` ### Names for class-like functions There are two exceptions where function names should follow class-naming convention instead. Functions of this kind are usually defined at the top level. * Factory functions that create class instances can have the same name as the abstract return type: ```KOTLIN interface Foo { /*...*/ } class FooImpl : Foo { /*...*/ } fun Foo(): Foo { return FooImpl() } ``` * `@Composable` functions that return `Unit`: ```KOTLIN @Composable fun TabHeader { /*...*/ } ``` ### Names for test methods 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. ```KOTLIN class MyTestCase { @Test fun `ensure everything works`() { /*...*/ } @Test fun ensureEverythingWorks_onAndroid() { /*...*/ } } ``` ### Property names 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 all uppercase, underscore-separated names following the [screaming snake case](https://en.wikipedia.org/wiki/Snake_case) convention: ```KOTLIN const val MAX_COUNT = 8 val USER_NAME_FIELD = "UserName" ``` Names of top-level or object properties which hold objects with behavior or mutable data should use camel case names: ```KOTLIN val mutableCollection: MutableSet = HashSet() ``` Names of properties holding references to singleton objects can use the same naming style as `object` declarations: ```KOTLIN val PersonComparator: Comparator = /*...*/ ``` For enum constants, it's OK to use either all uppercase, underscore-separated ([screaming snake case](https://en.wikipedia.org/wiki/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: ```KOTLIN class C { private val _elementList = mutableListOf() val elementList: List get() = _elementList } ``` ### Choose good names 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, 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` or `HttpInputStream`. ## 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. ```KOTLIN if (elements != null) { for (element in elements) { // ... } } ``` Note: 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 * Put spaces around binary operators (`a + b`). Exception: don't put spaces around the "range to" operator (`0..i`). * Do not put spaces around unary operators (`a++`). * Put spaces between control flow keywords (`if`, `when`, `for`, and `while`) and the corresponding opening parenthesis. * Do not put a space before an opening parenthesis in a primary constructor declaration, method declaration or method call. ```KOTLIN class A(val x: Int) fun foo(x: Int) { ... } fun bar() { foo(1) } ``` * Never put a space after `(`, `[`, or before `]`, `)`. * Never put a space around `.` or `?.`: `foo.bar().filter { it > 2 }.joinToString()`, `foo?.bar()`. * Put a space after `//`: `// This is a comment`. * Do not put spaces around angle brackets used to specify type parameters: `class Map { ... }`. * Do not put spaces around `::`: `Foo::class`, `String::length`. * Do not put a space before `?` used to mark a nullable type: `String?`. 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: * When it's used to separate a type and a supertype. * When delegating to a superclass constructor or a different constructor of the same class. * After the `object` keyword. Don't put a space before `:` when it separates a declaration and its type. Always put a space after `:`. ```KOTLIN abstract class Foo : IFoo { abstract fun foo(a: Int): T } class FooImpl : Foo() { constructor(x: String) : this(x) { /*...*/ } val x = object : IFoo { /*...*/ } } ``` ### Class headers Classes with a few primary constructor parameters can be written in a single line: ```KOTLIN class Person(id: Int, name: String) ``` 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: ```KOTLIN class Person( id: Int, name: String, surname: String ) : Human(id, name) { /*...*/ } ``` For multiple interfaces, the superclass constructor call should be located first and then each interface should be located in a different line: ```KOTLIN class Person( id: Int, name: String, surname: String ) : Human(id, name), KotlinMaker { /*...*/ } ``` For classes with a long supertype list, put a line break after the colon and align all supertype names horizontally: ```KOTLIN class MyFavouriteVeryLongClassHolder : MyLongHolder(), SomeOtherInterface, AndAnotherOne { fun foo() { /*...*/ } } ``` 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: ```KOTLIN class MyFavouriteVeryLongClassHolder : MyLongHolder(), SomeOtherInterface, AndAnotherOne { fun foo() { /*...*/ } } ``` 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: ```KOTLIN public / protected / private / internal expect / actual final / open / abstract / sealed / const external override lateinit tailrec vararg suspend inner enum / annotation / fun // as a modifier in `fun interface` companion inline / value infix operator data ``` Place all annotations before modifiers: ```KOTLIN @Named("Foo") private val foo: Foo ``` 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: ```KOTLIN @Target(AnnotationTarget.PROPERTY) annotation class JsonExclude ``` Annotations without arguments may be placed on the same line: ```KOTLIN @JsonExclude @JvmField var x: String ``` A single annotation without arguments may be placed on the same line as the corresponding declaration: ```KOTLIN @Test fun foo() { /*...*/ } ``` ### File annotations 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). ```KOTLIN /** License, copyright and whatever */ @file:JvmName("FooBar") package foo.bar ``` ### Functions If the function signature doesn't fit on a single line, use the following syntax: ```KOTLIN fun longMethodName( argument: ArgumentType = defaultValue, argument2: AnotherArgumentType, ): ReturnType { // body } ``` 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. ```KOTLIN fun foo(): Int { // bad return 1 } fun foo() = 1 // good ``` ### 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. ```KOTLIN fun f(x: String, y: String, z: String) = veryLongFunctionCallWithManyWords(andLongParametersToo(), x, y, z) ``` ### Properties For very simple read-only properties, consider one-line formatting: ```KOTLIN val isEmpty: Boolean get() = size == 0 ``` For more complex properties, always put `get` and `set` keywords on separate lines: ```KOTLIN val foo: String get() { /*...*/ } ``` For properties with an initializer, if the initializer is long, add a line break after the `=` sign and indent the initializer by four spaces: ```KOTLIN private val defaultCharset: Charset? = EncodingRegistry.getInstance().getDefaultCharsetForPropertiesFiles(file) ``` ### Control flow statements 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: ```KOTLIN if (!component.isSyncing && !hasAnyKotlinRuntimeInScope(module) ) { return createKotlinNotConfiguredPanel(module) } ``` This helps align the condition and statement bodies. Put the `else`, `catch`, `finally` keywords, as well as the `while` keyword of a `do-while` loop, on the same line as the preceding curly brace: ```KOTLIN if (condition) { // body } else { // else part } try { // body } finally { // cleanup } ``` In a `when` statement, if a branch is more than a single line, consider separating it from adjacent case blocks with a blank line: ```KOTLIN 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. ```KOTLIN when (foo) { true -> bar() // good false -> { baz() } // bad } ``` ### 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. ```KOTLIN drawSquare( x = 10, y = 10, width = 100, height = 100, fill = true ) ``` 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: ```KOTLIN val anchor = owner ?.firstChild!! .siblings(forward = true) .dropWhile { it is PsiComment || it is PsiWhiteSpace } ``` 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. ```KOTLIN list.filter { it > 10 } ``` If assigning a label for a lambda, do not put a space between the label and the opening curly brace: ```KOTLIN fun foo() { ints.forEach lit@{ // ... } } ``` When declaring parameter names in a multiline lambda, put the names on the first line, followed by the arrow and the newline: ```KOTLIN 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: ```KOTLIN foo { context: Context, environment: Env -> context.configureEnv(environment) } ``` ### Trailing commas A trailing comma is a comma symbol after the last item in a series of elements: ```KOTLIN 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. To enable trailing commas in the IntelliJ IDEA formatter, go to Settings/Preferences | Editor | Code Style | Kotlin, open the Other tab and select the Use trailing comma option. #### Enumerations ```KOTLIN enum class Direction { NORTH, SOUTH, WEST, EAST, // trailing comma } ``` #### Value arguments ```KOTLIN fun shift(x: Int, y: Int) { /*...*/ } shift( 25, 20, // trailing comma ) val colors = listOf( "red", "green", "blue", // trailing comma ) ``` #### Class properties and parameters ```KOTLIN class Customer( val name: String, val lastName: String, // trailing comma ) class Customer( val name: String, lastName: String, // trailing comma ) ``` #### Function value parameters ```KOTLIN fun powerOf( number: Int, exponent: Int, // trailing comma ) { /*...*/ } constructor( x: Comparable, y: Iterable, // trailing comma ) {} fun print( vararg quantity: Int, description: String, // trailing comma ) {} ``` #### Parameters with optional type (including setters) ```KOTLIN val sum: (Int, Int, Int) -> Int = fun( x, y, z, // trailing comma ): Int { return x + y + x } println(sum(8, 8, 8)) ``` #### Indexing suffix ```KOTLIN class Surface { operator fun get(x: Int, y: Int) = 2 * x + 4 * y - 10 } fun getZValue(mySurface: Surface, xValue: Int, yValue: Int) = mySurface[ xValue, yValue, // trailing comma ] ``` #### Parameters in lambdas ```KOTLIN fun main() { val x = { x: Comparable, y: Iterable, // trailing comma -> println("1") } println(x) } ``` #### when entry ```KOTLIN fun isReferenceApplicable(myReference: KClass<*>) = when (myReference) { Comparable::class, Iterable::class, String::class, // trailing comma -> true else -> false } ``` #### Collection literals (in annotations) ```KOTLIN annotation class ApplicableFor(val services: Array) @ApplicableFor([ "serializer", "balancer", "database", "inMemoryCache", // trailing comma ]) fun run() {} ``` #### Type arguments ```KOTLIN fun foo() {} fun main() { foo< Comparable, Iterable, // trailing comma >() } ``` #### Type parameters ```KOTLIN class MyMap< MyKey, MyValue, // trailing comma > {} ``` #### Destructuring declarations ```KOTLIN data class Car(val manufacturer: String, val model: String, val year: Int) val myCar = Car("Tesla", "Y", 2019) val ( manufacturer, model, year, // trailing comma ) = myCar val cars = listOf() fun printMeanValue() { var meanValue: Int = 0 for (( _, _, year, // trailing comma ) in cars) { meanValue += year } println(meanValue/cars.size) } printMeanValue() ``` ## Documentation comments For longer documentation comments, place the opening `/**` on a separate line and begin each subsequent line with an asterisk: ```KOTLIN /** * This is a documentation comment * on multiple lines. */ ``` Short comments can be placed on a single line: ```KOTLIN /** 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. ```KOTLIN // 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 { /*...*/ } ``` ## 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: ```KOTLIN fun foo() { // ": Unit" is omitted here } ``` ### 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: ```KOTLIN println("$name has ${children.size} children") ``` Use [multi-dollar string interpolation](strings.html#multi-dollar-string-interpolation) to treat the dollar sign chars `$` as string literals: ```KOTLIN val KClass<*>.jsonSchema : String get() = $$""" { "$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 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: ```KOTLIN // Bad: use of a mutable collection type for value which will not be mutated fun validateValue(actualValue: String, allowedValues: HashSet) { ... } // Good: immutable collection type used instead fun validateValue(actualValue: String, allowedValues: Set) { ... } // Bad: arrayListOf() returns ArrayList, which is a mutable collection type val allowedValues = arrayListOf("a", "b", "c") // Good: listOf() returns List val allowedValues = listOf("a", "b", "c") ``` ### Default parameter values Prefer declaring functions with default parameter values to declaring overloaded functions. ```KOTLIN // Bad fun foo() = foo("a") fun foo(a: String) { /*...*/ } // Good fun 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: ```KOTLIN typealias MouseClickHandler = (Any, MouseEvent) -> Unit typealias PersonIndex = Map ``` If you use a private or internal type alias for avoiding name collision, prefer the `import ... as ...` mentioned in [Packages and Imports](packages.html). ### Lambda parameters 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. ### 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 of `Boolean` type, unless the meaning of all parameters is absolutely clear from context. ```KOTLIN drawSquare(x = 10, y = 10, width = 100, height = 100, fill = true) ``` ### Conditional statements Prefer using the expression form of `try`, `if`, and `when`. ```KOTLIN return if (x) foo() else bar() ``` ```KOTLIN return when(x) { 0 -> "zero" else -> "nonzero" } ``` The above is preferable to: ```KOTLIN if (x) return foo() else return bar() ``` ```KOTLIN when(x) { 0 -> return "zero" else -> return "nonzero" } ``` ### if versus when Prefer using `if` for binary conditions instead of `when`. For example, use this syntax with `if`: ```KOTLIN if (x == null) ... else ... ``` Instead of this one with `when`: ```KOTLIN when (x) { null -> // ... else -> // ... } ``` Prefer using `when` if there are three or more options. ### Guard conditions in when expression Use parentheses when combining multiple boolean expressions in `when` expressions or statements with [guard conditions](control-flow.html#guard-conditions-in-when-expressions): ```KOTLIN when (status) { is Status.Ok if (status.info.isEmpty() || status.info.id == null) -> "no information" } ``` Instead of: ```KOTLIN 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 nullable `Boolean` in a conditional statement, use `if (value == true)` or `if (value == false)` checks. ### Loops 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. ### Loops on ranges Use the `..<` operator to loop over an open-ended range: ```KOTLIN for (i in 0..n - 1) { /*...*/ } // bad for (i in 0.. 1) { | return a |}""".trimMargin() println(a) //sampleEnd } ``` Learn the difference between [Java and Kotlin multiline strings](java-to-kotlin-idioms-strings.html#use-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 as `infix` 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 as `infix` 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. ```KOTLIN 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: ```KOTLIN 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: ```KOTLIN 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: ```KOTLIN 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`, and `also`. For the guidance on choosing the right scope function for your case, refer to [Scope Functions](scope-functions.html). ## 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). * Provide [KDoc](kotlin-doc.html) 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 the [Library authors' guidelines](api-guidelines-introduction.html). # Idioms A collection of random and frequently used idioms in Kotlin. If you have a favorite idiom, contribute it by sending a pull request. ## Create DTOs (POJOs/POCOs) ```KOTLIN data class Customer(val name: String, val email: String) ``` provides a `Customer` class with the following functionality: * getters (and setters in case of `var`s) for all properties * `equals()` * `hashCode()` * `toString()` * `copy()` * `component1()`, `component2()`, ..., for all properties (see [Data classes](data-classes.html)) ## Default values for function parameters ```KOTLIN fun foo(a: Int = 0, b: String = "") { ... } ``` ## Filter a list ```KOTLIN val positives = list.filter { x -> x > 0 } ``` Or alternatively, even shorter: ```KOTLIN val positives = list.filter { it > 0 } ``` Learn the difference between [Java and Kotlin filtering](java-to-kotlin-collections-guide.html#filter-elements). ## Check the presence of an element in a collection ```KOTLIN if ("john@example.com" in emailsList) { ... } if ("jane@example.com" !in emailsList) { ... } ``` ## String interpolation ```KOTLIN println("Name $name") ``` Learn the difference between [Java and Kotlin string concatenation](java-to-kotlin-idioms-strings.html#concatenate-strings). ## Read standard input safely ```KOTLIN // Reads a string and returns null if the input can't be converted into an integer. For example: Hi there! val wrongInt = readln().toIntOrNull() println(wrongInt) // null // Reads a string that can be converted into an integer and returns an integer. For example: 13 val correctInt = readln().toIntOrNull() println(correctInt) // 13 ``` For more information, see [Read standard input.](read-standard-input.html) ## Instance checks ```KOTLIN when (x) { is Foo -> ... is Bar -> ... else -> ... } ``` ## Read-only list ```KOTLIN val list = listOf("a", "b", "c") ``` ## Read-only map ```KOTLIN val map = mapOf("a" to 1, "b" to 2, "c" to 3) ``` ## Access a map entry ```KOTLIN println(map["key"]) map["key"] = value ``` ## Traverse a map or a list of pairs ```KOTLIN for ((k, v) in map) { println("$k -> $v") } ``` `k` and `v` can be any convenient names, such as `name` and `age`. ## Iterate over a range ```KOTLIN for (i in 1..100) { ... } // closed-ended range: includes 100 for (i in 1..<100) { ... } // open-ended range: does not include 100 for (x in 2..10 step 2) { ... } for (x in 10 downTo 1) { ... } (1..10).forEach { ... } ``` ## Lazy property ```KOTLIN val p: String by lazy { // the value is computed only on first access // compute the string } ``` ## Extension functions ```KOTLIN fun String.spaceToCamelCase() { ... } "Convert this to camelcase".spaceToCamelCase() ``` ## Create a singleton ```KOTLIN object Resource { val name = "Name" } ``` ## Use inline value classes for type-safe values ```KOTLIN @JvmInline value class EmployeeId(private val id: String) @JvmInline value class CustomerId(private val id: String) ``` If you accidentally mix up `EmployeeId` and `CustomerId`, a compilation error is triggered. Note: The `@JvmInline` annotation is only needed for JVM backends. ## Instantiate an abstract class ```KOTLIN abstract class MyAbstractClass { abstract fun doSomething() abstract fun sleep() } fun main() { val myObject = object : MyAbstractClass() { override fun doSomething() { // ... } override fun sleep() { // ... } } myObject.doSomething() } ``` ## If-not-null shorthand ```KOTLIN val files = File("Test").listFiles() println(files?.size) // size is printed if files is not null ``` ## If-not-null-else shorthand ```KOTLIN val files = File("Test").listFiles() // For simple fallback values: println(files?.size ?: "empty") // if files is null, this prints "empty" // To calculate a more complicated fallback value in a code block, use `run` val filesSize = files?.size ?: run { val someSize = getSomeSize() someSize * 2 } println(filesSize) ``` ## Execute an expression if null ```KOTLIN val values = ... val email = values["email"] ?: throw IllegalStateException("Email is missing!") ``` ## Get first item of a possibly empty collection ```KOTLIN val emails = ... // might be empty val mainEmail = emails.firstOrNull() ?: "" ``` Learn the difference between [Java and Kotlin first item getting](java-to-kotlin-collections-guide.html#get-the-first-and-the-last-items-of-a-possibly-empty-collection). ## Execute if not null ```KOTLIN val value = ... value?.let { ... // execute this block if not null } ``` ## Map nullable value if not null ```KOTLIN val value = ... val mapped = value?.let { transformValue(it) } ?: defaultValue // defaultValue is returned if the value or the transform result is null. ``` ## Return on when statement ```KOTLIN fun transform(color: String): Int { return when (color) { "Red" -> 0 "Green" -> 1 "Blue" -> 2 else -> throw IllegalArgumentException("Invalid color param value") } } ``` ## try-catch expression ```KOTLIN fun test() { val result = try { count() } catch (e: ArithmeticException) { throw IllegalStateException(e) } // Working with result } ``` ## if expression ```KOTLIN val y = if (x == 1) { "one" } else if (x == 2) { "two" } else { "other" } ``` ## Builder-style usage of methods that return Unit ```KOTLIN fun arrayOfMinusOnes(size: Int): IntArray { return IntArray(size).apply { fill(-1) } } ``` ## Single-expression functions ```KOTLIN fun theAnswer() = 42 ``` This is equivalent to ```KOTLIN fun theAnswer(): Int { return 42 } ``` This can be effectively combined with other idioms, leading to shorter code. For example, with the `when` expression: ```KOTLIN fun transform(color: String): Int = when (color) { "Red" -> 0 "Green" -> 1 "Blue" -> 2 else -> throw IllegalArgumentException("Invalid color param value") } ``` ## Call multiple methods on an object instance (with) ```KOTLIN class Turtle { fun penDown() fun penUp() fun turn(degrees: Double) fun forward(pixels: Double) } val myTurtle = Turtle() with(myTurtle) { //draw a 100 pix square penDown() for (i in 1..4) { forward(100.0) turn(90.0) } penUp() } ``` ## Configure properties of an object (apply) ```KOTLIN val myRectangle = Rectangle().apply { length = 4 breadth = 5 color = 0xFAFAFA } ``` This is useful for configuring properties that aren't present in the object constructor. ## Java 7's try-with-resources ```KOTLIN val stream = Files.newInputStream(Paths.get("/some/file.txt")) stream.buffered().reader().use { reader -> println(reader.readText()) } ``` ## Generic function that requires the generic type information ```KOTLIN // public final class Gson { // ... // public T fromJson(JsonElement json, Class classOfT) throws JsonSyntaxException { // ... inline fun Gson.fromJson(json: JsonElement): T = this.fromJson(json, T::class.java) ``` ## Swap two variables ```KOTLIN var a = 1 var b = 2 a = b.also { b = a } ``` ## Mark code as incomplete (TODO) Kotlin's standard library has a `TODO()` function that will always throw a `NotImplementedError`. Its return type is `Nothing` so it can be used regardless of expected type. There's also an overload that accepts a reason parameter: ```KOTLIN fun calcTaxes(): BigDecimal = TODO("Waiting for feedback from accounting") ``` IntelliJ IDEA's kotlin plugin understands the semantics of `TODO()` and automatically adds a code pointer in the TODO tool window. ## What's next? * Solve [Advent of Code puzzles](advent-of-code.html) using the idiomatic Kotlin style. * Learn how to perform [typical tasks with strings in Java and Kotlin](java-to-kotlin-idioms-strings.html). * Learn how to perform [typical tasks with collections in Java and Kotlin](java-to-kotlin-collections-guide.html). * Learn how to [handle nullability in Java and Kotlin](java-to-kotlin-nullability-guide.html). # Types overview In Kotlin, everything is an object in the sense that you can call member functions and properties on any variable. While certain types have an optimized internal representation as primitive values at runtime (such as numbers, characters, and booleans), they appear and behave like regular classes to you. This section describes the basic types used in Kotlin: * [Numbers](numbers.html) and their [unsigned counterparts](unsigned-integer-types.html) * [Booleans](booleans.html) * [Characters](characters.html) * [Strings](strings.html) * [Arrays](arrays.html) To learn about other Kotlin types, such as `Nothing`, `Any`, and `Unit`, look through the Kotlin API reference: * [Any](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-any/) * [Nothing](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-nothing.html) * [Unit](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-unit/) Kotlin also has non-denotable types. They are the types that you can't write directly in the Kotlin code. Instead, the compiler uses them internally, for example, for interoperability with other languages. Kotlin creates non-denotable types to represent type information that is more precise than what Kotlin source syntax allows. Even though you can't declare non-denotable types yourself, you may encounter them in compiler diagnostics, IDE tooltips, or inferred type displays. Learn more about non-denotable types in: * [Platform types](java-interop.html#null-safety-and-platform-types) * [Intersection types](typecasts.html#intersection-types) * [Integer literal types](numbers.html#integer-literal-types) * [Captured types](generics.html#captured-types) * [Kotlin language specification: Type system](https://kotlinlang.org/spec/type-system.html) Tip: [Learn how to perform type checks and casts in Kotlin](typecasts.html). # Numbers The Kotlin number types represent: * Integer values ([Byte](https://kotlinlang.org/api/core/kotlin-stdlib/kotlin/-byte/), [Short](https://kotlinlang.org/api/core/kotlin-stdlib/kotlin/-short/), [Int](https://kotlinlang.org/api/core/kotlin-stdlib/kotlin/-int/), and [Long](https://kotlinlang.org/api/core/kotlin-stdlib/kotlin/-long/)) * Floating-point values ([Float](https://kotlinlang.org/api/core/kotlin-stdlib/kotlin/-float/) and [Double](https://kotlinlang.org/api/core/kotlin-stdlib/kotlin/-double/)) Use number types to store and process numeric data, for example, in arithmetic, counters, measurements, and other calculations. ## Choose a number type In most cases, you can refer to the following rules to determine the correct number type for your task: * Use `Int` for whole numbers. * Use `Long` for whole numbers outside the `Int` range. * Use `Double` for decimal numbers. * Use `Float` when lower precision is acceptable or required. * Use `Byte` and `Short` when an API or data format requires them. Tip: Kotlin also provides [Unsigned integer types](unsigned-integer-types.html) as a Beta feature. ## Integer types Kotlin provides four integer types with different sizes and value ranges: | Type |Size (bits) |Min value |Max value | ------------------------------------------- | `Byte` |8 |-128 |127 | | `Short` |16 |-32768 |32767 | | `Int` |32 |-2,147,483,648 (-231) |2,147,483,647 (231 - 1) | | `Long` |64 |-9,223,372,036,854,775,808 (-263) |9,223,372,036,854,775,807 (263 - 1) | ### Declare integer values Kotlin supports the following literal forms for integer values: * Decimals: `123` * Hexadecimals: `0x0F` * Binaries: `0b00001011` Note: Kotlin does not support octal literals. To declare a numeric value, specify the type explicitly: ```KOTLIN val one: Int = 1 // Use underscores to improve readability val oneBillion: Long = 1_000_000_000 val hexBytes: Int = 0x7F_EC_DE_5E val bytes: Int = 0b01010010_01101001_10010100_10010010 val oneByte: Byte = 1 val oneShort: Short = 1 ``` You can also append the `L` suffix, to declare a `Long` value: ```KOTLIN val oneLong = 1L ``` When you declare a numeric type explicitly, the compiler checks that the value fits in the range of that type: ```KOTLIN // Value fits in Byte val oneByte: Byte = 1 // Error: the value does not fit in Byte val tooBig: Byte = 128 ``` When you do not specify a numeric type, Kotlin infers `Int` if the value fits in the `Int` range. Otherwise, Kotlin infers `Long`: ```KOTLIN val million = 1_000_000 // Int val threeBillion = 3_000_000_000 // Long ``` If a value can be absent, use nullable types: ```KOTLIN val maybeAbsent: Int? = null ``` ## Floating-point types For numbers with a fractional part, Kotlin provides `Float` and `Double`. Floating-point types follow the [IEEE 754 standard](https://en.wikipedia.org/wiki/IEEE_754). `Float` reflects the single precision. `Double` reflects the double precision. Floating-point types differ in size and precision: | Type |Size (bits) |Significant bits |Exponent bits |Decimal digits | ---------------------------------------------------------------------- | `Float` |32 |24 |8 |6-7 | | `Double` |64 |53 |11 |15-16 | ### Declare floating-point values To declare a floating-point literal, include a decimal point (`.`) or use exponent notation: ```KOTLIN val pi = 3.14 val avogadro = 6.02214076e23 ``` By default, Kotlin infers floating-point literals as `Double`. To declare a `Float`, add the `f` or `F` suffix: ```KOTLIN val pi = 3.14 // Double val eFloat = 2.7182817f // Float ``` Note: Kotlin rounds a `Float` literal that contains more precision than `Float` can store. If a value can be absent, use nullable types: ```KOTLIN val maybeAbsent: Double? = null ``` ## Arithmetic operations Kotlin supports the standard arithmetic operations on numbers: `+`, `-`, `*`, `/`, and `%`. Use these operators to perform common calculations: ```KOTLIN fun main() { //sampleStart println(1 + 2) // 3 println(2_500_000_000L - 1L) // 2499999999 println(3.14 * 2.71) // 8.5094 println(10.0 / 3) // 3.3333333333333335 //sampleEnd } ``` The result type depends on the types of the operands. Learn more in [Mixed numeric expressions](#mixed-numeric-expressions). Tip: You can override these operators in custom number classes. For more information, see [Operator overloading](operator-overloading.html). ### Integer division Division between integer values always returns an integer result. The compiler discards the fractional part: ```KOTLIN fun main() { //sampleStart val intValue = 5 / 2 println(intValue) // 2 val longValue = 5L / 2 println(longValue) // 2 //sampleEnd } ``` To return a floating-point result, make at least one operand a `Float` or `Double`: ```KOTLIN fun main() { //sampleStart val a = 5 / 2.0 println(a) // 2.5 val b = 5 / 2.toDouble() println(b) // 2.5 //sampleEnd } ``` ## Type conversion Numeric types are not subtypes of one another. Kotlin requires explicit conversions to avoid silent data loss and unexpected behavior. For example, a function that expects `Double` cannot accept an `Int` or a `Float` value without conversion: ```KOTLIN fun main() { //sampleStart fun printDouble(x: Double) { print(x) } val x = 1.0 val xInt = 1 val xFloat = 1.0f val one: Double = 1 // Error: initializer type mismatch printDouble(x) // OK printDouble(xInt) // Error: argument type mismatch printDouble(xFloat) // Error: argument type mismatch //sampleEnd } ``` All number types support conversions to other number types. To convert a number to another type, use an explicit conversion function: * `toByte()` * `toShort()` * `toInt()` * `toLong()` * `toFloat()` * `toDouble()` For example, the following code converts an `Int` value to `Double`: ```KOTLIN fun main() { //sampleStart val intValue: Int = 1 val doubleValue = intValue.toDouble() println(doubleValue) // 1.0 //sampleEnd } ``` When you convert a floating-point value to an integer type, the compiler discards the fractional part: ```KOTLIN fun main() { //sampleStart val d: Double = 1.5 val l: Long = d.toLong() println(l) // 1 //sampleEnd } ``` ### Mixed numeric expressions Kotlin does not support implicit conversion for assignments or function arguments. However, you can combine different numeric types in arithmetic expressions. In such cases, Kotlin determines a result type based on the operand types, and arithmetic operators handle the conversion automatically: ```KOTLIN val intNumber: Int = 1 val longNumber: Long = 1000 val result = intNumber + longNumber // 1001, Long ``` If you try to assign the result to a smaller type, the compiler reports an error: ```KOTLIN val intNumber: Int = 1 val longNumber: Long = 1000 val result: Int = intNumber + longNumber // Error: Initializer type mismatch ``` ### Integer literal types During type inference, Kotlin treats unsuffixed integer literals as a special [Integer Literal Type (ILT)](https://kotlinlang.org/spec/type-system.html#integer-literal-types) until the surrounding context determines a specific type: ```KOTLIN //sampleStart fun List.log() { println(joinToString(" | ") { it::class.simpleName ?: "Unknown" }) } fun main() { listOf(1, 2).log() // Int | Int listOf(1L, 2L).log() // Long | Long // Compiler interprets 1 as an ILT and resolves it to Long listOf(1, 2L).log() // Long | Long // .toInt() converts the literal to Int listOf(1.toInt(), 2L).log() // Int | Long } //sampleEnd ``` It's especially easy to miss with the `Int` and `Long` values because they have the same string representation at runtime. To avoid this, specify the expected type or convert values explicitly: ```KOTLIN //sampleStart fun List.log() { println(joinToString(" | ") { it::class.simpleName ?: "Unknown" }) } fun main() { val longValues: List = listOf(1, 2L) longValues.log() // Long | Long val numberValues: List = listOf(1.toInt(), 2L) numberValues.log() // Int | Long } //sampleEnd ``` You can also use an explicit type to catch unintended type inference: ```KOTLIN fun main() { //sampleStart val intValues: List = listOf(1, 2L) // Error: initializer type mismatch //sampleEnd } ``` Tip: Learn more about [Integer literal types](https://kotlinlang.org/spec/type-system.html#integer-literal-types). ## Data overflow Numeric types can represent only values within their defined ranges. If the result of an operation falls outside that range, overflow occurs. If you convert a value to a smaller numeric type, the converted value may not preserve the original numeric value. This behavior can affect the result of your code even when the compiler accepts it. ### Overflow in operations Each integer type can store only values within its defined range. When the result of an arithmetic operation exceeds that range, data overflow occurs: ```KOTLIN fun main(){ //sampleStart val intNumber: Int = 2147483647 // Max Int value is 2147483647 println(intNumber + 1) // -2147483648 //sampleEnd } ``` Here, the result wraps around because the value no longer fits in `Int`. Note: The compiler does not automatically produce an error when integer overflow occurs. ### Overflow in negation Overflow can also occur during negation. For example, you cannot represent the positive counterpart of `Int.MIN_VALUE` as an `Int`. ```KOTLIN fun main(){ //sampleStart val min = Int.MIN_VALUE println(-min) // -2147483648 //sampleEnd } ``` ### Narrowing conversions When you convert a value to a smaller integer type, the result may not preserve the original numeric value: ```KOTLIN fun main() { //sampleStart val large: Int = 130 val narrowed: Byte = large.toByte() println(narrowed) // -126 //sampleEnd } ``` However, since floating-point types follow the [IEEE 754 Standard](https://en.wikipedia.org/wiki/IEEE_754), very large results can become `Infinity`: ```KOTLIN fun main() { //sampleStart println(Double.MAX_VALUE * 2) // Infinity //sampleEnd } ``` ## Bitwise operations Kotlin provides bitwise operations for `Int` and `Long`. These operations are represented by a set of [infix functions](functions.html#infix-notation) and `inv()`. ```KOTLIN fun main() { //sampleStart val x = 1 println(x shl 2) // 4 println(x and 0x000FF000) // 0 //sampleEnd } ``` Bitwise operations include: * `shl()` – signed shift left * `shr()` – signed shift right * `ushr()` – unsigned shift right * `and()` – bitwise AND * `or()` – bitwise OR * `xor()` – bitwise XOR * `inv()` – bitwise inversion ## Floating-point number comparison In Kotlin, floating-point comparison depends on the static type of the operands. When the operands are statically known to be `Float` or `Double`, operations on the numbers and the range that they form follow the [IEEE 754 Standard for Floating-Point Arithmetic](https://en.wikipedia.org/wiki/IEEE_754). However, in generic use cases (such as `Any`, `Comparable<...>`, or `Collection`), behavior differs for operands that are not statically typed as floating-point numbers. In these cases, Kotlin uses the `equals()` and `compareTo()` implementations for `Float` and `Double`. As a result: * `NaN` is considered equal to itself * `NaN` is considered greater than any other element including `POSITIVE_INFINITY` * `-0.0` is considered less than `0.0` The following example shows the difference between operands statically typed as floating-point numbers and operands used through generic types: ```KOTLIN //sampleStart fun generalizedEquals(a: Any, b: Any): Boolean { return a == b } fun main() { // Operands statically typed as floating-point numbers println(Double.NaN == Double.NaN) // false println(0.0 == -0.0) // true // Operands used through a non-floating-point static type println(generalizedEquals(Double.NaN, Double.NaN)) // true println(generalizedEquals(0.0, -0.0)) // false } //sampleEnd ``` ## Boxing and caching numbers on the JVM On the JVM, non-nullable numeric values are usually stored using primitive types, such as `int`, `long`, or `double`. However, when you use [generic types](generics.html) or nullable numeric types like `Int?`, the value is boxed and represented as an object. The JVM applies a [memory optimization technique](https://docs.oracle.com/javase/specs/jls/se22/html/jls-5.html#jls-5.1.7) to small numbers by caching their boxed representations. As a result, boxed numbers with the same value can be [referentially equal](equality.html#referential-equality). For example, the JVM caches boxed `Integer` values in the range `-128` to `127`. Therefore, the following code returns `true`: ```KOTLIN fun main() { //sampleStart val score: Int = 100 val savedScore: Int? = score val displayedScore: Int? = score println(savedScore === displayedScore) // true //sampleEnd } ``` For values outside the cached range, boxed values are separate objects. In that case, they are not referentially equal, even if their values are [structurally equal](equality.html#structural-equality). For this reason, use `==` to compare numeric values: ```KOTLIN fun main() { //sampleStart val score: Int = 10000 val savedScore: Int? = score val displayedScore: Int? = score println(savedScore === displayedScore) // false println(savedScore == displayedScore) // true //sampleEnd } ``` # Unsigned integer types In addition to [integer types](numbers.html#integer-types), Kotlin provides the following types for unsigned integer numbers: | Type |Size (bits) |Min value |Max value | ------------------------------------------- | `UByte` |8 |0 |255 | | `UShort` |16 |0 |65,535 | | `UInt` |32 |0 |4,294,967,295 (232 - 1) | | `ULong` |64 |0 |18,446,744,073,709,551,615 (264 - 1) | Unsigned types support most of the operations of their signed counterparts. Note: Unsigned numbers are implemented as [inline classes](inline-classes.html) with a single storage property that contains the corresponding signed counterpart type of the same width. If you want to convert between unsigned and signed integer types, make sure you update your code so that any function calls and operations support the new type. ## Unsigned arrays and ranges Warning: Unsigned arrays and operations on them are in [Beta](components-stability.html). They can be changed incompatibly at any time. Opt-in is required (see the details below). Same as for primitives, each unsigned type has a corresponding type that represents arrays of that type: * `UByteArray`: an array of unsigned bytes. * `UShortArray`: an array of unsigned shorts. * `UIntArray`: an array of unsigned ints. * `ULongArray`: an array of unsigned longs. Same as for signed integer arrays, they provide a similar API to the `Array` class without boxing overhead. When you use unsigned arrays, you receive a warning that indicates that this feature is not stable yet. To remove the warning, opt-in with the `@ExperimentalUnsignedTypes` annotation. It's up to you to decide if your clients have to explicitly opt-in into usage of your API, but keep in mind that unsigned arrays are not a stable feature, so an API that uses them can be broken by changes in the language. [Learn more about opt-in requirements](opt-in-requirements.html). [Ranges and progressions](ranges.html) are supported for `UInt` and `ULong` by classes `UIntRange`,`UIntProgression`, `ULongRange`, and `ULongProgression`. Together with the unsigned integer types, these classes are stable. ## Unsigned integers literals To make unsigned integers easier to use, you can append a suffix to an integer literal indicating a specific unsigned type (similarly to `F` for `Float` or `L` for `Long`): * `u` and `U` letters signify unsigned literals without specifying the exact type. If no expected type is provided, the compiler uses `UInt` or `ULong` depending on the size of the literal: ```KOTLIN val b: UByte = 1u // UByte, expected type provided val s: UShort = 1u // UShort, expected type provided val l: ULong = 1u // ULong, expected type provided val a1 = 42u // UInt: no expected type provided, constant fits in UInt val a2 = 0xFFFF_FFFF_FFFFu // ULong: no expected type provided, constant doesn't fit in UInt ``` * `uL` and `UL` explicitly specify that literal should be an unsigned long: ```KOTLIN val a = 1UL // ULong, even though no expected type provided and the constant fits into UInt ``` ## Use cases The main use case of unsigned numbers is utilizing the full bit range of an integer to represent positive values. For example, to represent hexadecimal constants that do not fit in signed types such as color in 32-bit `AARRGGBB` format: ```KOTLIN data class Color(val representation: UInt) val yellow = Color(0xFFCC00CCu) ``` You can use unsigned numbers to initialize byte arrays without explicit `toByte()` literal casts: ```KOTLIN val byteOrderMarkUtf8 = ubyteArrayOf(0xEFu, 0xBBu, 0xBFu) ``` Another use case is interoperability with native APIs. Kotlin allows representing native declarations that contain unsigned types in the signature. The mapping won't substitute unsigned integers with signed ones keeping the semantics unaltered. ### Non-goals While unsigned integers can only represent positive numbers and zero, it's not a goal to use them where application domain requires non-negative integers. For example, as a type of collection size or collection index value. There are a couple of reasons: * Using signed integers can help to detect accidental overflows and signal error conditions, such as [List.lastIndex](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.collections/last-index.html) being -1 for an empty list. * Unsigned integers cannot be treated as a range-limited version of signed ones because their range of values is not a subset of the signed integers range. Neither signed nor unsigned integers are subtypes of each other. # Booleans The [Boolean](https://kotlinlang.org/api/core/kotlin-stdlib/kotlin/-boolean/) type represents logical values: `true` and `false`. Use `Boolean` values in functions that answer yes-or-no questions, and in the `while`, `if`, and `when` conditions. ## Declare a `Boolean` variable To declare a `Boolean` variable, assign it `true` or `false`. You can specify the `Boolean` type explicitly or let Kotlin infer it from the value: ```KOTLIN val isTrue: Boolean = true val isFalse = false // Kotlin infers Boolean ``` If a value can be `null`, use `Boolean?`: ```KOTLIN val isEnabled: Boolean? = null ``` Note: You cannot assign an integer value to a `Boolean` variable. In Kotlin, `0` and `1` are not `Boolean` values. ## Produce `Boolean` values You can use comparison expressions and functions to produce `Boolean` values: ```KOTLIN fun main() { //sampleStart val number = 10 val isPositive = number > 0 println(isPositive) // true val language = "Kotlin" val isEmpty = language.isEmpty() println(isEmpty) // false //sampleEnd } ``` You can use the results in conditions and other expressions as well: ```KOTLIN fun main() { //sampleStart val number = 10 val isPositive = number > 0 // true if (isPositive) { println("The number is positive.") } //sampleEnd } ``` ## `Boolean` operations Kotlin provides operators and infix functions for working with `Boolean` values. You can use them to invert a `Boolean` value or combine multiple `Boolean` values into a single result. ### Negation (NOT) The NOT operator inverts a `Boolean` value. To use NOT, place the `!` operator before a `Boolean` value: ```KOTLIN val isOn = true val isOff = !isOn // isOff is false ``` ### Logical AND The AND operator returns `true` only if both operands are `true`. To use logical AND, place the `&&` operator between operands: ```KOTLIN val a = false && false // false val b = false && true // false val c = true && false // false val d = true && true // true ``` Note: If the first operand is `false`, the `&&` operator skips the second operand. To evaluate both operands, use the `and` [infix function](functions.html#infix-notation) instead. ### Logical OR The OR operator returns `true` if at least one operand is `true`. To use logical OR, place the `||` operator between operands: ```KOTLIN val a = false || false // false val b = false || true // true val c = true || false // true val d = true || true // true ``` Note: If the first operand is `true`, the `||` operator skips the second operand. To evaluate both operands, use the `or` [infix function](functions.html#infix-notation) instead. ### Exclusive OR (XOR) The exclusive OR (XOR) operation returns `true` if the operands have different values. To use XOR, write `xor` between operands: ```KOTLIN val a = false xor false // false val b = false xor true // true val c = true xor false // true val d = true xor true // false ``` Note: `xor` is an [infix function](functions.html#infix-notation), not an operator. Learn more about `Boolean` functions in the [API Reference](https://kotlinlang.org/api/core/kotlin-stdlib/kotlin/-boolean/). ## Operator precedence If an expression contains multiple logical operations and no parentheses to specify the evaluation order, Kotlin applies precedence rules. Operations with higher precedence are evaluated before operations with lower precedence. For the `Boolean` operations described in this section, the precedence order is as follows: 1. `!` 2. `xor` (and other infix functions) 3. `&&` 4. `||` In the following example, the compiler evaluates `&&` before `||`: ```KOTLIN fun main() { //sampleStart val result = true || false && false println(result) // true //sampleEnd } ``` To make evaluation order explicit, use parentheses: ```KOTLIN fun main() { //sampleStart val result = (true || false) && false println(result) // false //sampleEnd } ``` ## `Boolean` in conditions [if](control-flow.html#if-expression), [when](control-flow.html#when-expressions-and-statements), and [while](control-flow.html#while-loops) evaluate `Boolean` expressions to direct program flow. ### `if` expressions ```KOTLIN fun main() { //sampleStart val number = 4 val isEven = number % 2 == 0 // Condition already has the `Boolean` type // You do not need to compare it to `true` or `false` if (isEven) { println("The number is even.") } else { println("The number is odd.") } //sampleEnd } ``` ### `when` expressions ```KOTLIN fun main() { //sampleStart val number = 3 when { number > 0 -> println("The number is positive.") number < 0 -> println("The number is negative.") else -> println("The number is zero.") } //sampleEnd } ``` ### `while` loops ```KOTLIN fun main() { //sampleStart var isCalculating = true while (isCalculating) { println("Calculating...") isCalculating = false } //sampleEnd } ``` # Characters The [Char](https://kotlinlang.org/api/core/kotlin-stdlib/kotlin/-char/) type represents a single character as a UTF-16 code unit. Use `Char` for individual character values, such as letters, digits, punctuation marks, or whitespace. For sequences of characters, use [String](strings.html). Tip: `Char` is not a numeric type, but each character has a numeric Unicode value that you can access. See [Character conversion](#character-conversion). ## Syntax To declare a character, enclose the value in single quotes (`' '`). You can specify the `Char` type explicitly or let Kotlin infer it from the value: ```KOTLIN val letter: Char = 'a' // Kotlin infers Char because the values are written in single quotes val digit = '1' val symbol = '!' val space = ' ' val separator = ':' ``` A character literal must contain exactly one character. Otherwise, the Kotlin compiler reports an error: ```KOTLIN val invalid = 'AB' // Error val invalidEmpty = '' // Error ``` ### Nullable values To store a nullable value, use `Char?`: ```KOTLIN val maybeAbsent: Char? = null ``` Note: On the JVM, nullable `Char` values are boxed when needed. The same applies to [numeric types](numbers.html#boxing-and-caching-numbers-on-the-jvm). ## Unicode support Kotlin represents `Char` values as UTF-16 code units. This means that a single `Char` stores one UTF-16 code unit, not necessarily one complete Unicode character. ### Basic Multilingual Plane A single `Char` can store values in the range from `\u0000` to `\uFFFF`. This range covers the Basic Multilingual Plane (BMP) that includes characters for almost all modern languages and a large number of symbols. To specify a character by the Unicode value, use `\u` followed by four-digit hexadecimal value from the [Unicode table](https://www.unicode.org/charts/): ```KOTLIN val unicodeNumber = '\u0031' // Equals '1' ``` ### Supplementary characters Unicode characters outside the BMP, such as emojis and some historic scripts, cannot be represented by a single `Char`. In UTF-16, they are encoded as a surrogate pair, where two `Char` values together represent one Unicode character in a `String`: ```KOTLIN fun main() { //sampleStart val emoji = "🥦" println(emoji.length) // 2 println(emoji[0]) // First surrogate println(emoji[1]) // Second surrogate //sampleEnd } ``` Tip: To handle 32-bit symbols individually, use Unicode code points stored as `Int` values. ## Escape sequences Use escape sequences for special characters that are difficult to write directly in source code or have a special meaning. Every escape sequence begins with a backslash (`\`). | Supported sequence |Description | ----------------------------------- | `\t` |Tab | | `\b` |Backspace | | `\n` |New Line (LF) | | `\r` |Carriage Return (CR) | | `\'` |Single quotation mark | | `\"` |Double quotation mark | | `\\` |Backslash | | `\$` |Dollar sign | For example: ```KOTLIN val newLine = '\n' val dollar = '\$' val backslash = '\\' ``` ## Operations `Char` supports comparison, inspection, case conversion, and explicit numeric conversion. ### Character comparison To compare `Char` values, use standard [comparison operators](keyword-reference.html#operators-and-special-symbols) such as `==`, `!=`, `<`, `>`, `<=`, and `>=`. Kotlin compares `Char` values by their numeric Unicode values and returns a `Boolean` value: ```KOTLIN val before = 'a' < 'b' // true val after = 'c' > 'd' // false val different = 'A' == 'a' // false val equal = 'A' == 'A' // true ``` ### Character processing Kotlin provides functions for inspection and case conversion of character values. For example: ```KOTLIN fun main() { //sampleStart val myChar = 'A' // Checks if the character represents a digit println(myChar.isDigit()) // false // Checks if the character represents an uppercase letter println(myChar.isUpperCase()) // true // Returns a lowercase version println(myChar.lowercaseChar()) // 'a' //sampleEnd } ``` Note: Learn more about available functions in the [API Reference](https://kotlinlang.org/api/core/kotlin-stdlib/kotlin/-char/). ### Character arithmetic You can create another character value by adding or subtracting an integer: ```KOTLIN fun main() { //sampleStart val a = 'a' println(a + 1) // b println(a + 2) // c println(a - 32) // A //sampleEnd } ``` Note: These operations follow Unicode values, not language-specific alphabet rules. You can also use the increment (`++`) and decrement (`--`) operators in the prefix and postfix forms with mutable variables: ```KOTLIN fun main() { //sampleStart var a = 'A' a += 10 println(a) // 'K' println(++a) // 'L' prefix increment println(a++) // 'L' postfix increment println(a) // 'M' println(--a) // 'L' prefix decrement println(a--) // 'L' postfix decrement println(a) // 'K' //sampleEnd } ``` ### Character conversion To convert `Char` to a numeric type, use explicit conversion: * Use `.code` to get the numeric Unicode value of a character: ```KOTLIN fun main() { //sampleStart val letter = 'A' println(letter.code) // 65 //sampleEnd } ``` * If a character represents a decimal digit, use `digitToInt()`: ```KOTLIN fun main() { //sampleStart val digit = '7' println(digit.digitToInt()) // 7 //sampleEnd } ``` Tip: If the character may not be a valid digit, use `digitToIntOrNull()`. # Strings The [String](https://kotlinlang.org/api/core/kotlin-stdlib/kotlin/-string/) type represents a sequence of [characters](characters.html). You can use it for text values, such as words, sentences, messages, or structured text. The `String` type is immutable. After you create a `String` object, its contents stay the same for the rest of its lifetime. Any operation that appears to modify the string actually creates a new string. ## Declare strings To declare a `String` literal, enclose the value in double quotes (`""`). You can specify the `String` type explicitly or let Kotlin infer it from the value: ```KOTLIN val name: String = "Kotlin" val message = "Hello, world!" // Kotlin infers String ``` Double-quoted string literals support [escape sequences](characters.html#escape-sequences) such as `\n` or `\t`: ```KOTLIN val message = "Hello,\nworld!" val quote = "Kotlin says, \"Hi\"." ``` ### Multiline strings To store text that consists of multiple lines or contains quotes that you don't want to escape, use a multiline string enclosed in triple quotes (`""" """`): ```KOTLIN val text = """ Hello, Kotlin """ val quote = """Kotlin says, "Hi".""" ``` Note: Multiline strings don't support escape sequences. Kotlin treats these characters as regular text. Multiline strings preserve line breaks and indentations as written in the source code. This behavior is useful when you want the runtime value to match the text layout in your file. In the following example, the spaces before each line are part of the resulting string: ```KOTLIN val text = """ Hello, Kotlin """ ``` To remove common leading indentation, use the [trimIndent()](https://kotlinlang.org/api/core/kotlin-stdlib/kotlin.text/trim-indent.html) function. It detects the common minimal indent of non-empty lines and removes it: ```KOTLIN fun main() { //sampleStart val text = """ Hello, Kotlin """.trimIndent() println(text) //sampleEnd } ``` To control indentation removal more explicitly, use the [trimMargin()](https://kotlinlang.org/api/core/kotlin-stdlib/kotlin.text/trim-margin.html) function. It removes everything before and including the margin prefix on each line: ```KOTLIN fun main() { //sampleStart val text = """ |Hello, |Kotlin """.trimMargin() println(text) //sampleEnd } ``` By default, the `trimMargin()` function uses a pipe symbol (`|`) as the margin prefix, but you can pass another character as a parameter. For example: `trimMargin(">")`. Note: When you process a string with functions like `trimIndent()` or `trimMargin()`, the resulting string uses only newline (`\n`) separators, regardless of the platform. ## String templates String templates let you embed variables and expressions directly inside a `String` literal. This process is called interpolation. You can use string templates in both regular and multiline strings. To insert a variable into a string, use the `$` symbol: ```KOTLIN fun main() { //sampleStart val name = "Kotlin" println("Hello, $name") // Hello, Kotlin //sampleEnd } ``` To insert an expression into a string or to place a variable directly next to other text, use `${}`: ```KOTLIN fun main() { //sampleStart val text = "abc" println("The length of $text is ${text.length}") // The length of abc is 3 val language = "Kotlin" println("${language}Lang") // KotlinLang //sampleEnd } ``` Tip: You can also combine strings with the `+` operator. However, string templates are usually easier to read and more idiomatic. Template expressions can also contain double-quoted strings without escaping: ```KOTLIN // Double-quoted string val test = "${"test".uppercase()}" // Multiline string val result = """ Result: ${"OK".lowercase()} """ ``` ### Nullable values in string templates If an interpolated expression or variable evaluates to `null`, the Kotlin compiler inserts the text `null` into the resulting string. To replace `null` with another value, use the [Elvis operator](null-safety.html#elvis-operator) (`?:`): ```KOTLIN fun main(){ //sampleStart val text: String? = null println("Hello, $text") // Hello, null println("Hello, ${text ?: "Kotlin"}") // Hello, Kotlin //sampleEnd } ``` ### Multi-dollar string interpolation In regular string templates, a single dollar sign (`$`) starts interpolation. If you need to include literal dollar signs in a string, use multi-dollar string interpolation. Multi-dollar string interpolation allows you to specify how many consecutive dollar signs are required to trigger interpolation. Dollar signs below that number are treated as literal characters. For example, when you use `$$` before a string literal, interpolation begins only with two consecutive dollar signs: ```KOTLIN val KClass<*>.jsonSchema : String get() = $$""" { "$schema": "https://json-schema.org/draft/2020-12/schema", "$id": "https://example.com/product.schema.json", "$dynamicAnchor": "meta", "title": "$${simpleName ?: qualifiedName ?: "unknown"}", "type": "object" } """ ``` Tip: If you use single-dollar string interpolation, multi-dollar string interpolation doesn't affect your code. You can continue using a single `$` and apply multi-dollar signs when needed. ## Basic string operations Kotlin provides a range of operations for working with strings. This section introduces some of the most commonly used operations. Tip: Learn more about all available functions in the [API Reference](https://kotlinlang.org/api/core/kotlin-stdlib/kotlin/-string/). ### Get string length To get the number of characters in a string, use the [length](https://kotlinlang.org/api/core/kotlin-stdlib/kotlin/-string/length.html) property: ```KOTLIN fun main (){ //sampleStart val language = "Kotlin" println(language.length) // 6 //sampleEnd } ``` ### Access characters You can access an individual character in a string with the indexing operator (`[]`): ```KOTLIN fun main (){ //sampleStart val language = "Kotlin" println(language[0]) // K println(language[5]) // n //sampleEnd } ``` Tip: A string index starts at zero. If you try to access an index outside the valid range, Kotlin throws an exception. You can also iterate over the characters in a string: ```KOTLIN fun main(){ //sampleStart for (char in "Kotlin") { println(char) } //sampleEnd } ``` ### Extract parts of a string To extract parts of a string, use one of the following functions: * [substring()](https://kotlinlang.org/api/core/kotlin-stdlib/kotlin.text/substring.html) to return a new string with the selected part of the original text. * [subSequence()](https://kotlinlang.org/api/core/kotlin-stdlib/kotlin.text/sub-sequence.html) to return a `CharSequence` with the selected part of the original text. For example: ```KOTLIN fun main() { //sampleStart val text = "Kotlin" println(text.substring(1)) // otlin println(text.substring(1, 5)) // otli println(text.subSequence(1, 5)) // otli //sampleEnd } ``` Since the `String` type is immutable, these functions don't modify the original string. ### Compare strings You can check whether two strings have the same content with the `==` operator: ```KOTLIN fun main(){ //sampleStart println("kotlin" == "kotlin") // true println("kotlin" == "Kotlin") // false //sampleEnd } ``` You can also compare strings lexicographically (character by character) with the [compareTo()](https://kotlinlang.org/api/core/kotlin-stdlib/kotlin/-string/compare-to.html) function. It scans both strings until it finds the first differing pair of characters and returns: * `0` when the strings are equal. * A value less than `0` when the receiver is smaller than the argument. * A value greater than `0` when the receiver is greater than the argument. ```KOTLIN fun main() { //sampleStart println("abc".compareTo("abd") < 0) // true println("abc".compareTo("ABC") > 0) // true // Pass true to ignore case differences println("abc".compareTo("ABC", ignoreCase = true) == 0) // true //sampleEnd } ``` ### Work with string content If you want to change the content of a string, create a modified copy of it with functions like [.trim()](https://kotlinlang.org/api/core/kotlin-stdlib/kotlin.text/trim.html), [.replace()](https://kotlinlang.org/api/core/kotlin-stdlib/kotlin.text/replace.html), [.uppercase()](https://kotlinlang.org/api/core/kotlin-stdlib/kotlin.text/uppercase.html), and [.lowercase()](https://kotlinlang.org/api/core/kotlin-stdlib/kotlin.text/lowercase.html): ```KOTLIN fun main() { //sampleStart val text = " Hello, Kotlin " println(text.trim()) // Hello, Kotlin println(text.replace("Kotlin", "world")) // Hello, world println(text.uppercase()) // HELLO, KOTLIN println(text.lowercase()) // hello, kotlin //sampleEnd } ``` You can also inspect the string content with the [contains()](https://kotlinlang.org/api/core/kotlin-stdlib/kotlin.text/contains.html), [startsWith()](https://kotlinlang.org/api/core/kotlin-stdlib/kotlin.text/starts-with.html), and [endsWith()](https://kotlinlang.org/api/core/kotlin-stdlib/kotlin.text/ends-with.html) functions: ```KOTLIN fun main() { //sampleStart val domain = "kotlinlang.org" // Checks if the string contains "." println(domain.contains(".")) // true // Checks if the string starts with "kotlin" println(domain.startsWith("kotlin")) // true // Checks if the string ends with ".org" println(domain.endsWith(".org")) // true //sampleEnd } ``` ### Split strings You can divide a string into parts around a delimiter with the [split()](https://kotlinlang.org/api/core/kotlin-stdlib/kotlin.text/split.html) function: ```KOTLIN fun main() { //sampleStart val numbers = "one, two, three" println(numbers.split(", ")) // [one, two, three] //sampleEnd } ``` If you want to split a string into individual lines, use the [lines()](https://kotlinlang.org/api/core/kotlin-stdlib/kotlin.text/lines.html) function: ```KOTLIN fun main() { //sampleStart val numbers = "one\ntwo\nthree" println(numbers.lines()) // [one, two, three] //sampleEnd } ``` ### Build and format strings Tip: For most formatting tasks in Kotlin, use [string templates](#string-templates). When you concatenate strings with the `+` operator, Kotlin creates a new `String` object for each operation. However, this approach may not be beneficial in loops or when you assemble many pieces. To avoid such issues, you can use the `buildString()` function or `StringBuilder`. They collect all pieces in a single mutable buffer and produce only one string at the end. Use the [buildString()](https://kotlinlang.org/api/core/kotlin-stdlib/kotlin.text/build-string.html) function when the logic that determines what to append is complex. For example, when you have multiple conditions that contribute a different fragment. With `buildString()`, you don't handle the buffer directly. The function creates a `StringBuilder` internally, runs your block, and returns the resulting string. ```KOTLIN fun main() { //sampleStart val hasErrors = true val hasWarnings = true val isComplete = false // buildString creates an empty buffer val status = buildString { // Appends "Errors found" to the buffer if (hasErrors) append("Errors found") if (hasWarnings) { // The buffer is not empty, appends "; " if (isNotEmpty()) append("; ") // Appends "Warnings found" append("Warnings found") } // isComplete = false, nothing to append if (isComplete) { if (isNotEmpty()) append("; ") append("Completed") } // The buffer is not empty, skips the fallback if (isEmpty()) append("OK") } println(status) // Errors found; Warnings found //sampleEnd } ``` Use [StringBuilder](https://kotlinlang.org/api/core/kotlin-stdlib/kotlin.text/-string-builder/) when you need the buffer as an explicit value. For example, to change the existing text: ```KOTLIN fun main() { //sampleStart val text = "Hello, Kotlin" val builder = StringBuilder(text) builder.replace(7, 13, "world") println(builder.toString()) // Hello, world //sampleEnd } ``` On the JVM, you can also format a string with the [String.format()](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.text/format.html) function: ```KOTLIN val text = String.format("Hello, %s", "Kotlin") ``` Note: Use the `String.format()` function only when you specifically need formatter-style specifiers on the JVM. Learn more about format specifiers in the [Java Class Formatter documentation](https://docs.oracle.com/javase/8/docs/api/java/util/Formatter.html#summary). ## String conversion Often you may use strings to represent values of other types, such as numbers, `Boolean` values, or identifiers from the input. Kotlin provides functions for converting values to strings and for parsing strings into other types. To return a string representation of a value, use the [toString()](https://kotlinlang.org/api/core/kotlin-stdlib/kotlin/-string/to-string.html) function: ```KOTLIN val number = 10 val text = number.toString() ``` In string templates and string concatenation, Kotlin converts values to strings automatically. To convert a string to another type, use the corresponding parsing functions: * For integer values: [toByte()](https://kotlinlang.org/api/core/kotlin-stdlib/kotlin.text/to-byte.html), [toShort()](https://kotlinlang.org/api/core/kotlin-stdlib/kotlin.text/to-short.html), [toInt()](https://kotlinlang.org/api/core/kotlin-stdlib/kotlin.text/to-int.html), [toLong()](https://kotlinlang.org/api/core/kotlin-stdlib/kotlin.text/to-long.html) * For floating-point values: [toDouble()](https://kotlinlang.org/api/core/kotlin-stdlib/kotlin.text/to-double.html), [toFloat()](https://kotlinlang.org/api/core/kotlin-stdlib/kotlin.text/to-float.html) * For booleans: [toBoolean()](https://kotlinlang.org/api/core/kotlin-stdlib/kotlin.text/to-boolean.html), [toBooleanStrict()](https://kotlinlang.org/api/core/kotlin-stdlib/kotlin.text/to-boolean-strict.html) These functions return a value of the requested type if the string has a valid format. If the input may be invalid, use the `OrNull` variants. These functions return `null` instead of throwing an exception making them safe for user input or data that you don't fully control: ```KOTLIN val toInt = "10".toInt() // 10 // 1000000000000 exceeds maximum value of Int val toIntInvalid = "1000000000000".toIntOrNull() val toBoolean = "true".toBooleanStrict() // true val toBooleanInvalid = "yes".toBooleanStrictOrNull() // null ``` # Arrays An array is a data structure that holds a fixed number of values of the same type or its subtypes. Array elements are ordered and accessed by index. Kotlin provides the [Array<T>](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-array/) class and [primitive-type arrays](#primitive-type-arrays). ## When to use arrays Use arrays for interoperability with Java APIs or low-level requirements. For example, if you have performance requirements beyond what is needed for regular applications, or you need to build custom data structures. For most use cases, prefer [collections](collections-overview.html) instead. | Functionality |Arrays |Collections | -------------------------------------- | Size |Fixed |Depends on the type | | Read-only variant |No, always mutable |Yes (`List` and `Set`) | | Adding and removing elements |No native support. Allocate and copy to a new array |Yes (mutable collections) | | Structural equality with `==` |No, compares references. Use [.contentEquals()](https://kotlinlang.org/api/core/kotlin-stdlib/kotlin.collections/content-equals.html) instead |Yes | | Primitive values |Primitive-type arrays store values without boxing |Usually boxed | | Java interoperability |Maps to `T[]` |Maps to `java.util.List` and `java.util.Set` | | Functional-style filtering and transformations |Limited |Extensive | Learn how to [convert arrays to collections](#convert-to-collections). ## Create arrays To create arrays, you can use: * The [arrayOf()](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/array-of.html), [arrayOfNulls()](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/array-of-nulls.html#kotlin$arrayOfNulls(kotlin.Int)), or [emptyArray()](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/empty-array.html) functions. * The `Array` constructor. Note: Declaring an array with `val` only prevents reassigning the variable but doesn't make the contents read-only. Elements are mutable in both `val` and `var` arrays. The distinction only affects the reference, not the contents. For a read-only view, use [collections](collections-overview.html) instead. ### Array with values To create a typed array from a known set of values, use the [arrayOf()](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/array-of.html) function. Kotlin infers the type automatically: ```KOTLIN fun main() { //sampleStart val simpleArray = arrayOf(1, 2, 3) // Array println(simpleArray.joinToString()) // 1, 2, 3 //sampleEnd } ``` ### Empty array To create an array with no elements, use the [emptyArray()](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/empty-array.html) function. You can specify the type of elements on the left-hand or right-hand side of the assignment: ```KOTLIN val emptyArrayRight = emptyArray() val emptyArrayLeft: Array = emptyArray() ``` Learn [how to add elements](#add-and-remove-elements) to an array. ### Array with nulls To create an array of a given size filled with `null` elements, use the [arrayOfNulls()](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/array-of-nulls.html#kotlin$arrayOfNulls(kotlin.Int)) function: ```KOTLIN fun main() { //sampleStart val nullArray: Array = arrayOfNulls(3) println(nullArray.joinToString()) // null, null, null //sampleEnd } ``` ### Array constructor The `Array` constructor takes the array size and a function that returns values of array elements: ```KOTLIN fun main() { //sampleStart val zeroes = Array(3) { 0 } println(zeroes.joinToString()) // 0, 0, 0 val squares = Array(5) { i -> i * i } println(squares.joinToString()) // 0, 1, 4, 9, 16 //sampleEnd } ``` ### Nested arrays To create a nested or multidimensional array, use an array of arrays. Nested arrays don't have to be the same type or the same size. ```KOTLIN fun main() { //sampleStart // Creates a two-dimensional array val twoDArray = Array(2) { Array(2) { 0 } } println(twoDArray.contentDeepToString()) // [[0, 0], [0, 0]] // Creates a three-dimensional array val threeDArray = Array(3) { Array(3) { Array(3) { 0 } } } println(threeDArray.contentDeepToString()) // [[[0, 0, 0], [0, 0, 0], [0, 0, 0]], [[0, 0, 0], [0, 0, 0], [0, 0, 0]], [[0, 0, 0], [0, 0, 0], [0, 0, 0]]] //sampleEnd } ``` ### Primitive-type arrays If you use the `Array` class with primitive values, the compiler boxes these values into objects. To avoid boxing overhead, you can use dedicated primitive-type arrays. They are not subclasses of the [Array<T>](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-array/) class, but they provide a similar set of functions and properties. | Kotlin type |Java equivalent | -------------------------------- | [BooleanArray](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-boolean-array/) |`boolean[]` | | [ByteArray](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-byte-array/) |`byte[]` | | [CharArray](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-char-array/) |`char[]` | | [DoubleArray](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-double-array/) |`double[]` | | [FloatArray](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-float-array/) |`float[]` | | [IntArray](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-int-array/) |`int[]` | | [LongArray](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-long-array/) |`long[]` | | [ShortArray](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-short-array/) |`short[]` | Note: Kotlin doesn't have a dedicated `StringArray` type. `String` is not a primitive, so use the [arrayOf()](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/array-of.html) or `arrayOf()` functions with inferred type instead. To create a primitive-type array, use one of the following options: * Constructor functions: ```KOTLIN fun main() { //sampleStart // Creates an Int array of size 5 with the values initialized to zero val primitiveTypeArray = IntArray(5) println(primitiveTypeArray.joinToString()) // 0, 0, 0, 0, 0 // Creates an Int array and takes an initializer function val squares = IntArray(5) { i -> i * i } println(squares.joinToString()) // 0, 1, 4, 9, 16 //sampleEnd } ``` * Factory functions: ```KOTLIN fun main() { //sampleStart // Creates an Int array with 5 elements val numbers = intArrayOf(1, 2, 3, 4, 5) println(numbers.joinToString()) // 1, 2, 3, 4, 5 // Creates a Char array with 3 elements val characters = charArrayOf('K', 't', 'l') println(characters.joinToString()) // K, t, l // Creates a Double array with 3 elements val doubles = doubleArrayOf(0.22, 4.16, 0.5) println(doubles.joinToString()) // 0.22, 4.16, 0.5 //sampleEnd } ``` Note: To convert primitive-type arrays to object-type arrays, use the [.toTypedArray()](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.collections/to-typed-array.html) function. To convert object-type arrays to primitive-type arrays, use [.toBooleanArray()](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.collections/to-boolean-array.html), [.toByteArray()](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.collections/to-byte-array.html), [.toCharArray()](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.collections/to-char-array.html), and so on. ## Work with arrays Arrays support many of the same operations as collections, including iteration, searching, sorting, and transformations. In Kotlin, you can work with arrays by using them to pass a variable number of arguments to a function or perform operations on the arrays themselves. Find the most common properties and functions in the following table: | Member |Returns | ------------------- | [size](https://kotlinlang.org/api/core/kotlin-stdlib/kotlin/-array/size.html) |The number of elements | | [indices](https://kotlinlang.org/api/core/kotlin-stdlib/kotlin.collections/indices.html) |The range of valid indices | | [lastIndex](https://kotlinlang.org/api/core/kotlin-stdlib/kotlin.collections/last-index.html) |The last valid index | | [first()](https://kotlinlang.org/api/core/kotlin-stdlib/kotlin.collections/first.html) and [last()](https://kotlinlang.org/api/core/kotlin-stdlib/kotlin.collections/last.html) |First and last element | | [isEmpty()](https://kotlinlang.org/api/core/kotlin-stdlib/kotlin.collections/is-empty.html) and [isNotEmpty()](https://kotlinlang.org/api/core/kotlin-stdlib/kotlin.collections/is-not-empty.html) |`true` if array is empty or not empty | | [contains()](https://kotlinlang.org/api/core/kotlin-stdlib/kotlin.collections/contains.html) |`true` if array has the element | Tip: Learn more about array properties and functions in the [API reference](https://kotlinlang.org/api/core/kotlin-stdlib/kotlin/-array/). This section introduces some of the most commonly used operations. ### Access and modify elements To access and modify elements in an array, use the [indexed access operator](operator-overloading.html#indexed-access-operator) (`[]`): ```KOTLIN fun main() { //sampleStart val simpleArray = arrayOf(1, 2, 3) val twoDArray = Array(2) { Array(2) { 0 } } // Accesses the element and modifies it simpleArray[0] = 10 twoDArray[0][0] = 2 // Prints the modified element println(simpleArray[0]) // 10 println(twoDArray[0][0]) // 2 //sampleEnd } ``` Note: If you try to access an index outside the bounds of an array, Kotlin throws `ArrayIndexOutOfBoundsException` at runtime. You can also use the [fill(element, fromIndex, toIndex)](https://kotlinlang.org/api/core/kotlin-stdlib/kotlin.collections/fill.html) function to replace elements in a range in place. `fromIndex` is inclusive, and `toIndex` is exclusive: ```KOTLIN fun main() { //sampleStart val arr = IntArray(3) println(arr.joinToString()) // 0, 0, 0 arr.fill(1) println(arr.joinToString()) // 1, 1, 1 arr.fill(0, 0, 2) println(arr.joinToString()) // 0, 0, 1 //sampleEnd } ``` In Kotlin, arrays are invariant. This means that `Array` is not a subtype of `Array`. This prevents possible runtime type failures. To express covariance, use the `Array` [type projection](generics.html#type-projections): ```KOTLIN fun main() { //sampleStart fun printArr(arr: Array) { for (item in arr) print("$item, ") } printArr(arrayOf("k", "t", "n")) // k, t, n, //sampleEnd } ``` ### Add and remove elements Since arrays have a fixed size, they don't support the `.add()` and `.remove()` functions. To perform these operations, you need to create a new array. For that, you can use one of the following options: * Use the [.copyOf](https://kotlinlang.org/api/core/kotlin-stdlib/kotlin.collections/copy-of.html) function: ```KOTLIN fun main() { //sampleStart var arr = intArrayOf(0, 1, 2) arr = arr.copyOf(arr.size + 1) println(arr.joinToString()) // 0, 1, 2, 0 arr[arr.lastIndex] = 3 println(arr.joinToString()) // 0, 1, 2, 3 //sampleEnd } ``` * Use the `+` or `+=` operators: ```KOTLIN fun main() { //sampleStart var arr = intArrayOf(0, 1, 2) arr += 3 println(arr.joinToString()) // 0, 1, 2, 3 arr = arr + intArrayOf(4, 5) println(arr.joinToString()) // 0, 1, 2, 3, 4, 5 //sampleEnd } ``` Tip: If you need to frequently add or remove elements, use [mutable collections](collections-overview.html#collection-types) instead. ### Compare arrays To compare whether two arrays have the same elements in the same order, use the [.contentEquals()](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.collections/content-equals.html) and [.contentDeepEquals()](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.collections/content-deep-equals.html) functions: ```KOTLIN fun main() { //sampleStart val simpleArray = arrayOf(1, 2, 3) val anotherArray = arrayOf(1, 2, 3) // Compares contents of arrays println(simpleArray.contentEquals(anotherArray)) // true // Using infix notation, compares contents of arrays after an element // is changed simpleArray[0] = 10 println(simpleArray contentEquals anotherArray) // false //sampleEnd } ``` Warning: Don't use equality (`==`) and inequality (`!=`) [operators](equality.html#structural-equality) to compare the contents of arrays. These operators check whether the assigned variables point to the same object. To learn more about why arrays in Kotlin behave this way, see our [blog post](https://blog.jetbrains.com/kotlin/2015/09/feedback-request-limitations-on-data-classes/#Appendix.Comparingarrays). ### Transform arrays Kotlin has many useful functions to transform arrays. This section highlights some of them. See the complete list in our [API reference](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-array/). #### Sum To return the sum of all elements in an array, use the [.sum()](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.collections/sum.html) function: ```KOTLIN fun main() { //sampleStart val sumArray = arrayOf(1, 2, 3) println(sumArray.sum()) // 6 //sampleEnd } ``` Note: The `.sum()` function can only be used with arrays of [numeric data types](numbers.html), such as `Int`. #### Sort and shuffle You can sort the elements in the array according to their natural order with the [.sort()](https://kotlinlang.org/api/core/kotlin-stdlib/kotlin.collections/sort.html) function or randomly shuffle them with the [.shuffle()](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.collections/shuffle.html) function: ```KOTLIN fun main() { //sampleStart val simpleArray = arrayOf(1, 2, 3) // Randomly shuffles elements simpleArray.shuffle() println(simpleArray.joinToString()) // Sorts elements simpleArray.sort() println(simpleArray.joinToString()) // 1, 2, 3 //sampleEnd } ``` To get a new sorted array without modifying the original, use the [.sortedArray()](https://kotlinlang.org/api/core/kotlin-stdlib/kotlin.collections/sorted-array.html) function instead. ### Pass variable number of arguments to a function In Kotlin, you can pass a variable number of arguments to a function via the [vararg](functions.html#variable-number-of-arguments-varargs) parameter. This is useful when you don't know the number of arguments in advance, like when formatting a message or creating an SQL query. To pass an array containing a variable number of arguments to a function, use the spread operator (`*`). The spread operator passes each element of the array as individual arguments to your chosen function: ```KOTLIN fun main() { val lettersArray = arrayOf("c", "d") printAllStrings("a", "b", *lettersArray) // abcd } fun printAllStrings(vararg strings: String) { for (string in strings) { print(string) } } ``` For more information, see [Variable number of arguments (varargs)](functions.html#variable-number-of-arguments-varargs). ## Convert to collections If you work with different APIs where some use arrays and some use collections, you can convert your arrays to collections and vice versa. For that, use the [.toList()](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.collections/to-list.html), [.toSet()](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.collections/to-set.html), and [.toMap()](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.collections/to-map.html) functions. These functions copy the content from your array to the independent copy. They don't reflect subsequent changes to the array. ### Convert to List or Set To convert an array to a `List` or `Set`, use the [.toList()](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.collections/to-list.html) and [.toSet()](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.collections/to-set.html) functions: ```KOTLIN fun main() { //sampleStart val simpleArray = arrayOf("a", "b", "c", "c") // Converts to a Set println(simpleArray.toSet()) // [a, b, c] // Converts to a List println(simpleArray.toList()) // [a, b, c, c] //sampleEnd } ``` Unless you are completely sure that the original array isn't changed or shared elsewhere, don't use [.asList()](https://kotlinlang.org/api/core/kotlin-stdlib/kotlin.collections/as-list.html) and related `as*` functions. These functions wrap the original array instead of copying it. Therefore, changes to the array are reflected in the list and vice versa. ```KOTLIN fun main() { //sampleStart val simpleArray = arrayOf("a", "b", "c") val list = simpleArray.asList() simpleArray[0] = "d" println(list) // [d, b, c] //sampleEnd } ``` ### Convert to Map To convert an array to a `Map`, use the [.toMap()](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.collections/to-map.html) function. You can convert only an array of [Pair<K,V>](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-pair/) to a `Map`. The first value of a `Pair` instance becomes a key, and the second becomes a value. If the same key appears more than once, the last value is used. This example uses the [infix notation](functions.html#infix-notation) to call the [.to](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/to.html) function to create tuples of `Pair`: ```KOTLIN fun main() { //sampleStart val pairArray = arrayOf("apple" to 120, "banana" to 150, "cherry" to 90, "apple" to 140) // Converts to a Map // Fruits are keys, calorie numbers are values // The latest "apple" value overwrites the first one println(pairArray.toMap()) // {apple=140, banana=150, cherry=90} //sampleEnd } ``` ## What's next? * Learn more about why we recommend using collections for most use cases in the [Collections overview](collections-overview.html). * Learn about other [basic types](types-overview.html). * If you are a Java developer, read our [Java to Kotlin migration guide for Collections](java-to-kotlin-collections-guide.html). # Type checks and casts In Kotlin, you can do two things with types at runtime: check whether an object is a specific type, or convert it to another type. Type checks help you confirm the kind of object you're dealing with, while type casts attempt to convert the object to another type. Tip: To learn specifically about generics type checks and casts, for example `List`, `Map`, see [Generics type checks and casts](generics.html#generics-type-checks-and-casts). ## Checks with `is` and `!is` operators Use the `is` operator (or `!is` to negate it) to check if an object matches a type at runtime: ```KOTLIN fun main() { val input: Any = "Hello, Kotlin" if (input is String) { println("Message length: ${input.length}") // Message length: 13 } if (input !is String) { // Same as !(input is String) println("Input is not a valid message") } else { println("Processing message: ${input.length} characters") // Processing message: 13 characters } } ``` You can also use `is` and `!is` operators to check if an object matches a subtype: ```KOTLIN interface Animal { val name: String fun speak() } class Dog(override val name: String) : Animal { override fun speak() = println("$name says: Woof!") } class Cat(override val name: String) : Animal { override fun speak() = println("$name says: Meow!") } //sampleStart fun handleAnimal(animal: Animal) { println("Handling animal: ${animal.name}") animal.speak() // Use is operator to check for subtypes if (animal is Dog) { println("Special care instructions: This is a dog.") } else if (animal is Cat) { println("Special care instructions: This is a cat.") } } //sampleEnd fun main() { val pets: List = listOf( Dog("Buddy"), Cat("Whiskers"), Dog("Rex") ) for (pet in pets) { handleAnimal(pet) println("---") } // Handling animal: Buddy // Buddy says: Woof! // Special care instructions: This is a dog. // --- // Handling animal: Whiskers // Whiskers says: Meow! // Special care instructions: This is a cat. // --- // Handling animal: Rex // Rex says: Woof! // Special care instructions: This is a dog. // --- } ``` This example uses the `is` operator to check if the `Animal` class instance has subtype `Dog` or `Cat` to print the relevant care instructions. You can check if an object is a supertype of its declared type, but it's not worthwhile because the answer is always true. Every class instance is already an instance of its supertypes. Tip: To identify the type of an object at runtime, see [Reflection](reflection.html). ## Type casts To convert the type of an object in Kotlin to another type is called casting. In some cases, the compiler automatically casts objects for you. This is called smart-casting. If you need to explicitly cast a type, use `as?` or `as` [cast operators](#unsafe-cast-operator). ## Smart casts The compiler tracks the type checks and [explicit casts](#unsafe-cast-operator) for immutable values and inserts implicit (safe) casts automatically: ```KOTLIN fun logMessage(data: Any) { // data is automatically cast to String if (data is String) { println("Received text: ${data.length} characters") } } fun main() { logMessage("Server started") // Received text: 14 characters logMessage(404) } ``` The compiler is even smart enough to know that a cast is safe if a negative check leads to a return: ```KOTLIN fun logMessage(data: Any) { // data is automatically cast to String if (data !is String) return println("Received text: ${data.length} characters") } fun main() { logMessage("User signed in") // Received text: 14 characters logMessage(true) } ``` ### Control flow Smart casts work not only for `if` conditional expressions, but also for [when expressions](control-flow.html#when-expressions-and-statements): ```KOTLIN fun processInput(data: Any) { when (data) { // data is automatically cast to Int is Int -> println("Log: Assigned new ID ${data + 1}") // data is automatically cast to String is String -> println("Log: Received message \"$data\"") // data is automatically cast to IntArray is IntArray -> println("Log: Processed scores, total = ${data.sum()}") } } fun main() { processInput(1001) // Log: Assigned new ID 1002 processInput("System rebooted") // Log: Received message "System rebooted" processInput(intArrayOf(10, 20, 30)) // Log: Processed scores, total = 60 } ``` And for [while loops](control-flow.html#while-loops): ```KOTLIN sealed interface Status data class Ok(val currentRoom: String) : Status data object Error : Status class RobotVacuum(val rooms: List) { var index = 0 fun status(): Status = if (index < rooms.size) Ok(rooms[index]) else Error fun clean(): Status { println("Finished cleaning ${rooms[index]}") index++ return status() } } fun main() { //sampleStart val robo = RobotVacuum(listOf("Living Room", "Kitchen", "Hallway")) var status: Status = robo.status() while (status is Ok) { // The compiler smart casts status to OK type, so the currentRoom // property is accessible. println("Cleaning ${status.currentRoom}...") status = robo.clean() } // Cleaning Living Room... // Finished cleaning Living Room // Cleaning Kitchen... // Finished cleaning Kitchen // Cleaning Hallway... // Finished cleaning Hallway //sampleEnd } ``` In this example, the sealed interface `Status` has two implementations: the data class `Ok` and the data object `Error`. Only the `Ok` data class has the `currentRoom` property. When the `while` loop condition evaluates to true, the compiler smart casts the `status` variable to `Ok` type, making the `currentRoom` property accessible within the loop body. If you declare a variable of `Boolean` type before using it in your `if`, `when`, or `while` condition, any information collected by the compiler about the variable is accessible in the corresponding block for smart-casting. This can be useful when you want to do things like extract boolean conditions into variables. Then, you can give the variable a meaningful name, which improves your code readability and makes it possible to reuse the variable later in your code. For example: ```KOTLIN class Cat { fun purr() { println("Purr purr") } } //sampleStart fun petAnimal(animal: Any) { val isCat = animal is Cat if (isCat) { // The compiler can access information about // isCat, so it knows that animal was smart-cast // to the type Cat. // Therefore, the purr() function can be called. animal.purr() } } fun main(){ val kitty = Cat() petAnimal(kitty) // Purr purr } //sampleEnd ``` ### Logical operators The compiler can perform smart casts on the right-hand side of `&&` or `||` operators if there is a type check (regular or negative) on the left-hand side: ```KOTLIN // x is automatically cast to String on the right-hand side of `||` if (x !is String || x.length == 0) return // x is automatically cast to String on the right-hand side of `&&` if (x is String && x.length > 0) { print(x.length) // x is automatically cast to String } ``` If you combine type checks for objects with an `and` operator (`&&`), the compiler smart-casts the object to all checked types simultaneously. Learn more in [Intersection types](#intersection-types). If you combine type checks for objects with an `or` operator (`||`), a smart cast is made to their closest common supertype: ```KOTLIN interface Status { fun signal() {} } interface Ok : Status interface Postponed : Status interface Declined : Status fun signalCheck(signalStatus: Any) { if (signalStatus is Postponed || signalStatus is Declined) { // signalStatus is smart-cast to a common supertype Status signalStatus.signal() } } ``` Note: The common supertype is an approximation of a [union type](https://en.wikipedia.org/wiki/Union_type). Union types are [not currently supported in Kotlin](https://youtrack.jetbrains.com/issue/KT-13108/Denotable-union-and-intersection-types). ### Intersection types When the compiler smart-casts an object through multiple `&&` checks, it infers an [intersection type](https://kotlinlang.org/spec/type-system.html#intersection-types). This is an internal type that simultaneously satisfies all the checked constraints: ```KOTLIN interface Bird { fun fly() } interface Fish { fun swim() } fun describe(animal: Any) { // Infers the Bird and Fish types if (animal is Bird && animal is Fish) { // Accesses fly() and swim() without additional checks or casts animal.fly() animal.swim() } } ``` Intersection types are non-denotable. They only exist in the compiler's internal type system to preserve type information during type checking. You can't write them directly in Kotlin code. You may encounter intersection types in compiler error messages and IDE tooltips, typically displayed as `A & B`. The one exception is `T & Any` that declares a [definitely non-nullable type](generics.html#definitely-non-nullable-types). This syntax is reserved specifically to combine a type parameter with `Any`. ```KOTLIN fun T.assertNotNull(): T & Any = this ?: throw IllegalStateException("null value") ``` ### Inline functions The compiler can smart-cast variables captured within lambda functions that are passed to [inline functions](inline-functions.html). Inline functions are treated as having an implicit [callsInPlace](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.contracts/-contract-builder/calls-in-place.html) contract. This means that any lambda functions passed to an inline function are called in place. Since lambda functions are called in place, the compiler knows that a lambda function can't leak references to any variables contained within its function body. The compiler uses this knowledge, along with other analyses, to decide whether it's safe to smart-cast any of the captured variables. For example: ```KOTLIN interface Processor { fun process() } inline fun inlineAction(f: () -> Unit) = f() fun nextProcessor(): Processor? = null fun runProcessor(): Processor? { var processor: Processor? = null inlineAction { // The compiler knows that processor is a local variable and inlineAction() // is an inline function, so references to processor can't be leaked. // Therefore, it's safe to smart-cast processor. // If processor isn't null, processor is smart-cast if (processor != null) { // The compiler knows that processor isn't null, so no safe call // is needed processor.process() } processor = nextProcessor() } return processor } ``` ### Exception handling Smart cast information is passed on to `catch` and `finally` blocks. This makes your code safer as the compiler tracks whether your object has a nullable type. For example: ```KOTLIN //sampleStart fun testString() { var stringInput: String? = null // stringInput is smart-cast to String type stringInput = "" try { // The compiler knows that stringInput isn't null println(stringInput.length) // 0 // The compiler rejects previous smart cast information for // stringInput. Now stringInput has the String? type. stringInput = null // Trigger an exception if (2 > 1) throw Exception() stringInput = "" } catch (exception: Exception) { // The compiler knows stringInput can be null // so stringInput stays nullable. println(stringInput?.length) // null } } //sampleEnd fun main() { testString() } ``` ### Smart cast prerequisites Smart casts work only when the compiler can guarantee that the variable won't change between the check and its usage. They can be used in the following conditions: | `val` local variables | Always, except [local delegated properties](delegated-properties.html). | | `val` properties | If the property is `private`, `internal`, or if the check is performed in the same [module](visibility-modifiers.html#modules) where the property is declared. Smart casts can't be used on `open` properties or properties that have custom getters. | | `var` local variables | If the variable is not modified between the check and its usage, is not captured in a lambda that modifies it, and is not a local delegated property. | | `var` properties | Never, because the variable can be modified at any time by other code. | ## `as` and `as?` cast operators Kotlin has two cast operators: `as` and `as?`. You can use both to cast, but they have different behaviors. If a cast fails with the `as` operator, a `ClassCastException` is thrown at runtime. That's why it's also called the unsafe operator. You can use `as` when casting to a non-null type: ```KOTLIN fun main() { val rawInput: Any = "user-1234" // Casts to String successfully val userId = rawInput as String println("Logging in user with ID: $userId") // Logging in user with ID: user-1234 // Triggers ClassCastException val wrongCast = rawInput as Int println("wrongCast contains: $wrongCast") // Exception in thread "main" java.lang.ClassCastException } ``` If you use the `as?` operator instead, and the cast fails, the operator returns `null`. That's why it's also called the safe operator: ```KOTLIN fun main() { val rawInput: Any = "user-1234" // Casts to String successfully val userId = rawInput as? String println("Logging in user with ID: $userId") // Logging in user with ID: user-1234 // Assigns a null value to wrongCast val wrongCast = rawInput as? Int println("wrongCast contains: $wrongCast") // wrongCast contains: null } ``` To cast a nullable type safely, use the `as?` operator to prevent triggering a `ClassCastException` if the cast fails. You can use `as` with a nullable type. This allows the result to be `null`, but it still throws a `ClassCastException` if the cast is unsuccessful. For this reason, `as?` is the safer option: ```KOTLIN fun main() { val config: Map = mapOf( "username" to "kodee", "alias" to null, "loginAttempts" to 3 ) // Unsafely casts to a nullable String val username: String? = config["username"] as String? println("Username: $username") // Username: kodee // Unsafely casts a null value to a nullable String val alias: String? = config["alias"] as String? println("Alias: $alias") // Alias: null // Fails to cast to nullable String and throws ClassCastException // val unsafeAttempts: String? = config["loginAttempts"] as String? // println("Login attempts (unsafe): $unsafeAttempts") // Exception in thread "main" java.lang.ClassCastException // Fails to cast to nullable String and returns null val safeAttempts: String? = config["loginAttempts"] as? String println("Login attempts (safe): $safeAttempts") // Login attempts (safe): null } ``` ### Up and downcasting In Kotlin, you can cast objects to supertypes and subtypes. Casting an object to an instance of its superclass is called upcasting. Upcasting doesn't need any special syntax or cast operators. For example: ```KOTLIN interface Animal { fun makeSound() } class Dog : Animal { // Implements behavior for makeSound() override fun makeSound() { println("Dog says woof!") } } fun printAnimalInfo(animal: Animal) { animal.makeSound() } fun main() { val dog = Dog() // Upcasts Dog instance to Animal printAnimalInfo(dog) // Dog says woof! } ``` In this example, when the `printAnimalInfo()` function is called with a `Dog` instance, the compiler upcasts it to `Animal` because that's the expected parameter type. Since the actual object is still a `Dog` instance, the compiler dynamically resolves the `makeSound()` function from the `Dog` class, printing `"Dog says woof!"`. You'll often see explicit upcasting in Kotlin APIs where behavior depends on an abstract type. It's also common in Jetpack Compose and UI toolkits, which typically treat all UI elements as supertypes and later operate on specific subclasses: ```KOTLIN val textView = TextView(this) textView.text = "Hello, View!" // Upcasts from TextView to View val view: View = textView // Use View functions view.setPadding(20, 20, 20, 20) // Activity expects a View type setContentView(view) ``` Casting an object to an instance of a subclass is called downcasting. Because downcasting can be unsafe, you need to use explicit cast operators. To avoid throwing exceptions on failed casts, we recommend using the safe cast operator `as?`, to return `null` if the cast fails: ```KOTLIN interface Animal { fun makeSound() } class Dog : Animal { override fun makeSound() { println("Dog says woof!") } fun bark() { println("BARK!") } } fun main() { // Creates animal as a Dog instance with Animal // type val animal: Animal = Dog() // Safely downcasts animal to Dog type val dog: Dog? = animal as? Dog // Uses a safe call to call bark() if dog isn't null dog?.bark() // "BARK!" } ``` In this example, `animal` is declared as type `Animal`, but it holds a `Dog` instance. The code safely casts `animal` to `Dog` type and uses a [safe call](null-safety.html#safe-call-operator) (`?.`) to access the `bark()` function. You'll use downcasting in serialization when deserializing a base class to a specific subtype. It's also common when working with Java libraries that return supertype objects, which you may need to downcast in Kotlin. # Type aliases Type aliases provide alternative names for existing types. They can make long or frequently used type expressions shorter and easier to understand. For example, you can create aliases for generic types, function types, and nested or inner classes: ```KOTLIN // Generic types typealias UserIndex = Map typealias FileTable = MutableMap> // Function types typealias RequestHandler = (Request) -> Response typealias Predicate = (T) -> Boolean // Inner and nested classes class Database { inner class Transaction } typealias DatabaseTransaction = Database.Transaction ``` A type alias doesn't create a new type. It introduces an alternative name for an existing type. The alias and its underlying type are interchangeable. For example, when you add `typealias Predicate` and use `Predicate`, the compiler expands it to `(Int) -> Boolean`. You can use a value declared with the alias wherever the underlying type is expected, and the other way around: ```KOTLIN typealias Predicate = (T) -> Boolean fun evaluate(predicate: Predicate) = predicate(42) fun main() { val isPositive: (Int) -> Boolean = { it > 0 } println(evaluate(isPositive)) // true val isValid: Predicate = { it > 0 } println(listOf(1, -2).filter(isValid)) // [1] } ``` ## Declare type aliases You can declare a type alias: * At the top level of a Kotlin file, as a [top-level type alias](#top-level-type-aliases). * Inside a class, interface, or object, as a [nested type alias](#nested-type-aliases). You can't declare a type alias in a local scope, such as inside a function or [lambda expression](lambdas.html#lambda-expressions-and-anonymous-functions). The declaration location determines the scope of a type alias, while its visibility determines which code can access it. By default, a type alias is `public`. A [nested type alias](#nested-type-aliases) is accessible only where its containing class, interface, or object is accessible. For example, a `public` alias inside an `internal` class isn't accessible from outside the module. A type alias can't expose an underlying type with more restrictive [visibility](visibility-modifiers.html) than its own. For example, a `public` type alias can't refer to a `private` class. ### Top-level type aliases A top-level type alias is a package-level declaration. Within the same package, you can refer to an alias by its unqualified name. To use the alias from another package, import the alias or refer to it by its qualified name: ```KOTLIN // UserId.kt package org.example.users typealias UserId = Long // Refers to the alias within the same package by its unqualified name fun createUser(id: UserId) { // ... } // UserService.kt package org.example.services import org.example.users.UserId // Uses the imported alias by its unqualified name fun findUser(id: UserId) { // ... } // Uses the fully qualified name fun deleteUser(id: org.example.users.UserId) { // ... } ``` ### Nested type aliases Nested type aliases allow for cleaner, more maintainable code by improving encapsulation, reducing package-level clutter, and simplifying internal implementations. Nested type aliases follow the same scope and name-resolution rules as [nested classes](nested-classes.html). Declare a type alias inside a class, interface, or object when the alternative name is relevant only in the context of that declaration. This keeps the alias close to the code that uses it and avoids adding another name to the package scope. Within the containing declaration, you can refer to the alias by its unqualified name. Outside the declaration, qualify the alias with the name of its containing declaration: ```KOTLIN class UserRepository { typealias UserIndex = Map // Refers to the alias by its unqualified name inside UserRepository fun saveAll(users: UserIndex) { // ... } } // Refers to the alias by its qualified name outside UserRepository fun synchronizeUsers(users: UserRepository.UserIndex) { // ... } ``` Note: Nested type aliases aren't supported in Kotlin Multiplatform [expect/actual declarations](https://kotlinlang.org/docs/multiplatform/multiplatform-expect-actual.html). #### Type parameters To use type parameters in a nested type alias, add them to the alias declaration: ```KOTLIN class Graph { typealias Path = List } val cityPath: Graph.Path = listOf("London", "Berlin") ``` In this example, `Path` declares its type parameter `T`. In `Graph.Path`, `String` is the type argument for `T` and is independent of the `Node` type parameter declared by `Graph`. If you refer to a type parameter declared by its containing class or interface, the compiler reports an error: ```KOTLIN class Graph { typealias Path = List // Unresolved reference 'Node'. } ``` Here, `Path` refers to `Node` from `Graph` instead of declaring its own type parameter. # Conditions and loops Kotlin gives you flexible tools to control your program's flow. Use `if`, `when`, and loops to define clear, expressive logic for your conditions. ## If expression To use `if` in Kotlin, add the condition to check within parentheses `()` and the action to take if the result is true within curly braces `{}`. You can use `else` and `else if` for additional branches and checks. You can also write `if` as an expression, which lets you assign its returned value directly to a variable. In this form, an `else` branch is required. The `if` expression serves the same purpose as the ternary operator (`condition ? then : else`) found in other languages. For example: ```KOTLIN fun main() { val heightAlice = 160 val heightBob = 175 //sampleStart var taller = heightAlice if (heightAlice < heightBob) taller = heightBob // Uses an else branch if (heightAlice > heightBob) { taller = heightAlice } else { taller = heightBob } // Uses if as an expression taller = if (heightAlice > heightBob) heightAlice else heightBob // Uses else if as an expression: val heightLimit = 150 val heightOrLimit = if (heightLimit > heightAlice) heightLimit else if (heightAlice > heightBob) heightAlice else heightBob println("Taller height is $taller") // Taller height is 175 println("Height or limit is $heightOrLimit") // Height or limit is 175 //sampleEnd } ``` Each branch in an `if` expression can be a block, where the value of the last expression becomes the result: ```KOTLIN fun main() { //sampleStart val heightAlice = 160 val heightBob = 175 val taller = if (heightAlice > heightBob) { print("Choose Alice\n") heightAlice } else { print("Choose Bob\n") heightBob } println("Taller height is $taller") //sampleEnd } ``` ## When expressions and statements `when` is a conditional expression that runs code based on multiple possible values or conditions. It's similar to the `switch` statement in Java, C, and other languages. `when` evaluates its argument and compares the result against each branch in order until one branch condition is satisfied. For example: ```KOTLIN fun main() { //sampleStart val userRole = "Editor" when (userRole) { "Viewer" -> print("User has read-only access") "Editor" -> print("User can edit content") else -> print("User role is not recognized") } // User can edit content //sampleEnd } ``` You can use `when` either as an expression or a statement. As an expression, `when` returns a value you can use later in your code. As a statement, `when` completes an action without returning a result: | Expression |Statement | ------------------------- | ```KOTLIN // Returns a string assigned to the // text variable val text = when (x) { 1 -> "x == 1" 2 -> "x == 2" else -> "x is neither 1 nor 2" } ``` | ```KOTLIN // Returns no result but triggers a // print statement when (x) { 1 -> print("x == 1") 2 -> print("x == 2") else -> print("x is neither 1 nor 2") } ``` | Secondly, you can use `when` with or without a subject. The behavior stays the same either way. Using a subject usually makes your code more readable and maintainable because it clearly shows what you're checking. | With subject `x` |Without subject | ------------------------------------- | ```KOTLIN when(x) { ... } ``` | ```KOTLIN when { ... } ``` | How you use `when` determines whether you need to cover all possible cases in your branches. Covering all possible cases is called being exhaustive. ### Statements If you use `when` as a statement, you don't need to cover all possible cases. In this example, some cases aren't covered, so no branch is triggered. However, no error occurs: ```KOTLIN fun main() { //sampleStart val deliveryStatus = "OutForDelivery" when (deliveryStatus) { // Not all cases are covered "Pending" -> print("Your order is being prepared") "Shipped" -> print("Your order is on the way") } //sampleEnd } ``` Just like with `if`, each branch can be a block, and its value is the value of the last expression in the block. ### Expressions If you use `when` as an expression, you must cover all possible cases. The value of the first matching branch becomes the value of the overall expression. If you don't cover all cases, the compiler throws an error. If your `when` expression has a subject, you can use an `else` branch to make sure that all possible cases are covered, but it isn't mandatory. For example, if your subject is a `Boolean`, [enum class](enum-classes.html), [sealed class](sealed-classes.html), or one of their nullable counterparts, you can cover all cases without an `else` branch: ```KOTLIN import kotlin.random.Random //sampleStart enum class Bit { ZERO, ONE } fun getRandomBit(): Bit { return if (Random.nextBoolean()) Bit.ONE else Bit.ZERO } fun main() { val numericValue = when (getRandomBit()) { // No else branch is needed because all cases are covered Bit.ZERO -> 0 Bit.ONE -> 1 } println("Random bit as number: $numericValue") // Random bit as number: 0 //sampleEnd } ``` Tip: To simplify `when` expressions and reduce repetition, try out context-sensitive resolution (currently in preview). This feature allows you to omit the type name when using enum entries or sealed class members in `when` expressions if the expected type is known. For more information, see [Preview of context-sensitive resolution](whatsnew22.html#preview-of-context-sensitive-resolution) or the related [KEEP proposal](https://github.com/Kotlin/KEEP/blob/improved-resolution-expected-type/proposals/context-sensitive-resolution.md). If your `when` expression doesn't have a subject, you must have an `else` branch or the compiler throws an error. The `else` branch is evaluated when none of the other branch conditions are satisfied: ```KOTLIN fun main() { //sampleStart val localFileSize = 1200 val remoteFileSize = 1200 val message = when { localFileSize > remoteFileSize -> "Local file is larger than remote file" localFileSize < remoteFileSize -> "Local file is smaller than remote file" else -> "Local and remote files are the same size" } println(message) // Local and remote files are the same size //sampleEnd } ``` ### Other ways to use when `when` expressions and statements offer different ways to simplify your code, handle multiple conditions, and perform type checks. Group multiple conditions into a single branch using commas: ```KOTLIN fun main() { val ticketPriority = "High" //sampleStart when (ticketPriority) { "Low", "Medium" -> print("Standard response time") else -> print("High-priority handling") } //sampleEnd } ``` Use expressions that evaluate to `true` or `false` as branch conditions: ```KOTLIN fun main() { val storedPin = "1234" val enteredPin = 1234 //sampleStart when (enteredPin) { // Expression storedPin.toInt() -> print("PIN is correct") else -> print("Incorrect PIN") } //sampleEnd } ``` Check whether a value is or isn't contained in a [range](ranges.html) or collection using the `in` or `!in` keywords: ```KOTLIN fun main() { val x = 7 val validNumbers = setOf(15, 16, 17) //sampleStart when (x) { in 1..10 -> print("x is in the range") in validNumbers -> print("x is valid") !in 10..20 -> print("x is outside the range") else -> print("none of the above") } //sampleEnd } ``` Check a value's type using the `is` or `!is` keywords. Due to [smart casts](typecasts.html#smart-casts), you can access the member functions and properties of the type directly: ```KOTLIN fun hasPrefix(input: Any): Boolean = when (input) { is String -> input.startsWith("ID-") else -> false } fun main() { val testInput = "ID-98345" println(hasPrefix(testInput)) // true } ``` Use `when` instead of a traditional `if`-`else` `if` chain. Without a subject, the branch conditions are simply boolean expressions. The first branch with a `true` condition runs: ```KOTLIN fun Int.isOdd() = this % 2 != 0 fun Int.isEven() = this % 2 == 0 fun main() { //sampleStart val x = 5 val y = 8 when { x.isOdd() -> print("x is odd") y.isEven() -> print("y is even") else -> print("x+y is odd") } // x is odd //sampleEnd } ``` Finally, capture the subject in a variable by using the following syntax: ```KOTLIN fun main() { val message = when (val input = "yes") { "yes" -> "You said yes" "no" -> "You said no" else -> "Unrecognized input: $input" } println(message) // You said yes } ``` The scope of a variable introduced as the subject is restricted to the body of the `when` expression or statement. ### Guard conditions Guard conditions allow you to include more than one condition to the branches of a `when` expression or statement, making complex control flow more explicit and concise. You can use guard conditions with `when` as long as it has a subject. Place a guard condition after the primary condition in the same branch, separated by `if`: ```KOTLIN sealed interface Animal { data class Cat(val mouseHunter: Boolean) : Animal data class Dog(val breed: String) : Animal } fun feedDog() = println("Feeding a dog") fun feedCat() = println("Feeding a cat") //sampleStart fun feedAnimal(animal: Animal) { when (animal) { // Branch with only primary condition // Calls feedDog() when animal is Dog is Animal.Dog -> feedDog() // Branch with both primary and guard conditions // Calls feedCat() when animal is Cat and not mouseHunter is Animal.Cat if !animal.mouseHunter -> feedCat() // Prints "Unknown animal" if none of the above conditions match else -> println("Unknown animal") } } fun main() { val animals = listOf( Animal.Dog("Beagle"), Animal.Cat(mouseHunter = false), Animal.Cat(mouseHunter = true) ) animals.forEach { feedAnimal(it) } // Feeding a dog // Feeding a cat // Unknown animal } //sampleEnd ``` You can't use guard conditions when you have multiple conditions separated by a comma. For example: ```KOTLIN 0, 1 -> print("x == 0 or x == 1") ``` In a single `when` expression or statement, you can combine branches with and without guard conditions. The code in a branch with a guard condition runs only if both the primary condition and the guard condition evaluate to `true`. If the primary condition doesn't match, the guard condition isn't evaluated. Since `when` statements don't need to cover all cases, using guard conditions in `when` statements without an `else` branch means that if no conditions match, no code is run. Unlike statements, `when` expressions must cover all cases. If you use guard conditions in `when` expressions without an `else` branch, the compiler requires you to handle every possible case to avoid runtime errors. Combine multiple guard conditions within a single branch using the boolean operators `&&` (AND) or `||` (OR). Use parentheses around the boolean expressions to [avoid confusion](coding-conventions.html#guard-conditions-in-when-expression): ```KOTLIN when (animal) { is Animal.Cat if (!animal.mouseHunter && animal.hungry) -> feedCat() } ``` Guard conditions also support `else if`: ```KOTLIN when (animal) { // Checks if `animal` is `Dog` is Animal.Dog -> feedDog() // Guard condition that checks if `animal` is `Cat` and not `mouseHunter` is Animal.Cat if !animal.mouseHunter -> feedCat() // Calls giveLettuce() if none of the above conditions match and animal.eatsPlants is true else if animal.eatsPlants -> giveLettuce() // Prints "Unknown animal" if none of the above conditions match else -> println("Unknown animal") } ``` ### Bytecode generation on the JVM When you compile Kotlin code for JVM 21 or later, the compiler generates an [invokedynamic](https://docs.oracle.com/en/java/javase/21/docs/api/java.base/java/lang/invoke/package-summary.html) instruction for eligible `when` expressions. This produces smaller bytecode, similar to the bytecode produced by Java `switch` statements. The compiler uses `invokedynamic` with the [SwitchBootstraps.typeSwitch()](https://docs.oracle.com/en/java/javase/21/docs/api/java.base/java/lang/runtime/SwitchBootstraps.html) method when all the following conditions are met: * All conditions except for `else` are `is` or `null` checks. * The `when` expression doesn't contain [guard conditions (if)](#guard-conditions-in-when-expressions). * The conditions don't include types that can't be type-checked directly, such as mutable Kotlin collections (`MutableList`) or function types (`kotlin.Function1`, `kotlin.Function2`, and so on). * The `when` expression has at least two conditions besides `else`. * All branches check the same subject of the `when` expression. For example: ```KOTLIN open class Shape class Circle : Shape() class Rectangle : Shape() class Triangle : Shape() fun countCorners(shape: Shape) = when (shape) { is Circle -> 0 is Rectangle -> 4 is Triangle -> 3 else -> -1 } ``` The `when (shape)` expression here compiles to a single `invokedynamic` type switch instead of multiple `instanceof` checks in the bytecode. ## For loops Use the `for` loop to iterate through a [collection](collections-overview.html), [array](arrays.html), or [range](ranges.html): ```KOTLIN for (item in collection) print(item) ``` The body of a `for` loop can be a block with curly braces `{}`. ```KOTLIN fun main() { val shoppingList = listOf("Milk", "Bananas", "Bread") //sampleStart println("Things to buy:") for (item in shoppingList) { println("- $item") } // Things to buy: // - Milk // - Bananas // - Bread //sampleEnd } ``` ### Ranges To iterate over a range of numbers, use a [range expression](ranges.html) with `..` and `..<` operators: ```KOTLIN fun main() { //sampleStart println("Closed-ended range:") for (i in 1..6) { print(i) } // Closed-ended range: // 123456 println("\nOpen-ended range:") for (i in 1..<6) { print(i) } // Open-ended range: // 12345 println("\nReverse order in steps of 2:") for (i in 6 downTo 0 step 2) { print(i) } // Reverse order in steps of 2: // 6420 //sampleEnd } ``` ### Arrays If you want to iterate through an array or a list with an index, you can use the `indices` property: ```KOTLIN fun main() { val routineSteps = arrayOf("Wake up", "Brush teeth", "Make coffee") //sampleStart for (i in routineSteps.indices) { println(routineSteps[i]) } // Wake up // Brush teeth // Make coffee //sampleEnd } ``` Alternatively, you can use the [.withIndex()](https://kotlinlang.org/api/core/kotlin-stdlib/kotlin.collections/with-index.html) function from the standard library: ```KOTLIN fun main() { val routineSteps = arrayOf("Wake up", "Brush teeth", "Make coffee") //sampleStart for ((index, value) in routineSteps.withIndex()) { println("The step at $index is \"$value\"") } // The step at 0 is "Wake up" // The step at 1 is "Brush teeth" // The step at 2 is "Make coffee" //sampleEnd } ``` ### Iterators The `for` loop iterates through anything that provides an [iterator](iterators.html). Collections provide iterators by default, whereas ranges and arrays are compiled into index-based loops. You can create your own iterators by providing a member or extension function called `iterator()` that returns an `Iterator<>`. The `iterator()` function must have a `next()` function and a `hasNext()` function that returns a `Boolean`. The easiest way to create your own iterator for a class is to inherit from the [Iterable<T>](https://kotlinlang.org/api/core/kotlin-stdlib/kotlin.collections/-iterable/) interface and override the `iterator()`, `next()`, and `hasNext()` functions that are already there. For example: ```KOTLIN class Booklet(val totalPages: Int) : Iterable { override fun iterator(): Iterator { return object : Iterator { var current = 1 override fun hasNext() = current <= totalPages override fun next() = current++ } } } fun main() { val booklet = Booklet(3) for (page in booklet) { println("Reading page $page") } // Reading page 1 // Reading page 2 // Reading page 3 } ``` Tip: Learn more about [interfaces](interfaces.html) and [inheritance](inheritance.html). Alternatively, you can create the functions from scratch. In this case, add the `operator` keyword to the functions: ```KOTLIN //sampleStart class Booklet(val totalPages: Int) { operator fun iterator(): Iterator { return object { var current = 1 operator fun hasNext() = current <= totalPages operator fun next() = current++ }.let { object : Iterator { override fun hasNext() = it.hasNext() override fun next() = it.next() } } } } //sampleEnd fun main() { val booklet = Booklet(3) for (page in booklet) { println("Reading page $page") } // Reading page 1 // Reading page 2 // Reading page 3 } ``` ## While loops `while` and `do-while` loops run the code in their body continuously while the condition is satisfied. The difference between them is the condition checking time: * `while` checks the condition and, if it's satisfied, runs the code in its body and then returns to the condition check. * `do-while` runs the code in its body and then checks the condition. If it's satisfied, the loop repeats. So, the body of `do-while` runs at least once, regardless of the condition. For a `while` loop, place the condition to check in parentheses `()` and the body within curly braces `{}`: ```KOTLIN fun main() { var carsInGarage = 0 val maxCapacity = 3 //sampleStart while (carsInGarage < maxCapacity) { println("Car entered. Cars now in garage: ${++carsInGarage}") } // Car entered. Cars now in garage: 1 // Car entered. Cars now in garage: 2 // Car entered. Cars now in garage: 3 println("Garage is full!") // Garage is full! //sampleEnd } ``` For a `do-while` loop, place the body within curly braces `{}` first before the condition to check in parentheses `()`: ```KOTLIN import kotlin.random.Random fun main() { var roll: Int //sampleStart do { roll = Random.nextInt(1, 7) println("Rolled a $roll") } while (roll != 6) // Rolled a 2 // Rolled a 6 println("Got a 6! Game over.") // Got a 6! Game over. //sampleEnd } ``` ## Break and continue in loops Kotlin supports traditional `break` and `continue` operators in loops. See [Returns and jumps](returns.html). # Returns and jumps Kotlin has three structural jump expressions: * `return` by default returns from the nearest enclosing function or [anonymous function](lambdas.html#anonymous-functions). * `break` terminates the nearest enclosing loop. * `continue` proceeds to the next step of the nearest enclosing loop. All of these expressions can be used as part of larger expressions: ```KOTLIN val s = person.name ?: return ``` The type of these expressions is the [Nothing type](exceptions.html#the-nothing-type). ## Break and continue labels Any expression in Kotlin may be marked with a label. Labels have the form of an identifier followed by the `@` sign, such as `abc@` or `fooBar@`. To label an expression, just add a label in front of it. ```KOTLIN loop@ for (i in 1..100) { // ... } ``` Now, you can qualify a `break` or a `continue` with a label: ```KOTLIN loop@ for (i in 1..100) { for (j in 1..100) { if (...) break@loop } } ``` A `break` qualified with a label jumps to the execution point right after the loop marked with that label. A `continue` proceeds to the next iteration of that loop. Note: In some cases, you can apply `break` and `continue` non-locally without explicitly defining labels. Such non-local usages are valid in lambda expressions used in enclosing [inline functions](inline-functions.html#break-and-continue). ## Return to labels In Kotlin, functions can be nested using function literals, local functions, and object expressions. A qualified `return` allows you to return from an outer function. The most important use case is returning from a lambda expression. To return from a lambda expression, label it and qualify the `return`: ```KOTLIN //sampleStart fun foo() { listOf(1, 2, 3, 4, 5).forEach lit@{ if (it == 3) return@lit // local return to the caller of the lambda - the forEach loop print(it) } print(" done with explicit label") } //sampleEnd fun main() { foo() } ``` Now, it returns only from the lambda expression. Often it is more convenient to use implicit labels, because such a label has the same name as the function to which the lambda is passed. ```KOTLIN //sampleStart fun foo() { listOf(1, 2, 3, 4, 5).forEach { if (it == 3) return@forEach // local return to the caller of the lambda - the forEach loop print(it) } print(" done with implicit label") } //sampleEnd fun main() { foo() } ``` Alternatively, you can replace the lambda expression with an [anonymous function](lambdas.html#anonymous-functions). A `return` statement in an anonymous function will return from the anonymous function itself. ```KOTLIN //sampleStart fun foo() { listOf(1, 2, 3, 4, 5).forEach(fun(value: Int) { if (value == 3) return // local return to the caller of the anonymous function - the forEach loop print(value) }) print(" done with anonymous function") } //sampleEnd fun main() { foo() } ``` Note that the use of local returns in the previous three examples is similar to the use of `continue` in regular loops. There is no direct equivalent for `break`, but it can be simulated by adding an outer `run` lambda and non-locally returning from it: ```KOTLIN //sampleStart fun foo() { run loop@{ listOf(1, 2, 3, 4, 5).forEach { if (it == 3) return@loop // non-local return from the lambda passed to run print(it) } } print(" done with nested loop") } //sampleEnd fun main() { foo() } ``` The non-local return here is possible since the nested `forEach()` lambda acts as an [inline function](inline-functions.html). When returning a value, the parser gives preference to the qualified return: ```KOTLIN return@a 1 ``` This means "return `1` at label `@a`" rather than "return a labeled expression `(@a 1)`". Note: In some cases, you can return from a lambda expression without using labels. Such non-local returns are located in a lambda but exit the enclosing [inline function](inline-functions.html#returns). # Exception and error handling Exceptions help your code run more predictably, even when runtime errors occur that could disrupt program execution. Kotlin treats all exceptions as unchecked by default. Unchecked exceptions simplify the exception handling process: you can catch exceptions, but you don't need to explicitly handle or [declare](java-to-kotlin-interop.html#checked-exceptions) them. Tip: Learn more about how Kotlin handles exceptions when interacting with Java, Swift, and Objective-C in the [Exception interoperability with Java, Swift, and Objective-C](#exception-interoperability-with-java-swift-and-objective-c) section. Working with exceptions consists of two primary actions: * Throwing exceptions: indicate when a problem occurs. * Catching exceptions: handle the unexpected exception manually by resolving the issue or notifying the developer or application user. Exceptions are represented by subclasses of the [Exception](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-exception/) class, which is a subclass of the [Throwable](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-throwable/) class. For more information about the hierarchy, see the [Exception hierarchy](#exception-hierarchy) section. Since `Exception` is an [open class](inheritance.html), you can create [custom exceptions](#create-custom-exceptions) to suit your application's specific needs. ## Throw exceptions You can manually throw exceptions with the `throw` keyword. Throwing an exception indicates that an unexpected runtime error has occurred in the code. Exceptions are [objects](classes.html#creating-instances), and throwing one creates an instance of an exception class. You can throw an exception without any parameters: ```KOTLIN throw IllegalArgumentException() ``` To better understand the source of the problem, include additional information, such as a custom message and the original cause: ```KOTLIN val cause = IllegalStateException("Original cause: illegal state") // Throws an IllegalArgumentException if userInput is negative // Additionally, it shows the original cause, represented by the cause IllegalStateException if (userInput < 0) { throw IllegalArgumentException("Input must be non-negative", cause) } ``` In this example, an `IllegalArgumentException` is thrown when the user inputs a negative value. You can create custom error messages and keep the original cause (`cause`) of the exception, which will be included in the [stack trace](#stack-trace). ### Throw exceptions with precondition functions Kotlin offers additional ways to automatically throw exceptions using precondition functions. Precondition functions include: | Precondition function |Use case |Exception thrown | ----------------------------------------------------- | [require()](#require-function) |Checks user input validity |[IllegalArgumentException](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-illegal-argument-exception/) | | [check()](#check-function) |Checks object or variable state validity |[IllegalStateException](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-illegal-state-exception/) | | [error()](#error-function) |Indicates an illegal state or condition |[IllegalStateException](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-illegal-state-exception/) | These functions are suitable for situations where the program's flow cannot continue if specific conditions aren't met. This streamlines your code and makes handling these checks efficient. #### require() function Use the [require()](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/require.html) function to validate input arguments when they are crucial for the function's operation, and the function can't proceed if these arguments are invalid. If the condition in `require()` is not met, it throws an [IllegalArgumentException](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-illegal-argument-exception/): ```KOTLIN fun getIndices(count: Int): List { require(count >= 0) { "Count must be non-negative. You set count to $count." } return List(count) { it + 1 } } fun main() { // This fails with an IllegalArgumentException println(getIndices(-1)) // Uncomment the line below to see a working example // println(getIndices(3)) // [1, 2, 3] } ``` Note: The `require()` function allows the compiler to perform [smart casting](typecasts.html#smart-casts). After a successful check, the variable is automatically cast to a non-nullable type. These functions are often used for nullability checks to ensure that the variable is not null before proceeding. For example: ```KOTLIN fun printNonNullString(str: String?) { // Nullability check require(str != null) // After this successful check, 'str' is guaranteed to be // non-null and is automatically smart cast to non-nullable String println(str.length) } ``` #### check() function Use the [check()](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/check.html) function to validate the state of an object or variable. If the check fails, it indicates a logic error that needs to be addressed. If the condition specified in the `check()` function is `false`, it throws an [IllegalStateException](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-illegal-state-exception/): ```KOTLIN fun main() { var someState: String? = null fun getStateValue(): String { val state = checkNotNull(someState) { "State must be set beforehand!" } check(state.isNotEmpty()) { "State must be non-empty!" } return state } // If you uncomment the line below then the program fails with IllegalStateException // getStateValue() someState = "" // If you uncomment the line below then the program fails with IllegalStateException // getStateValue() someState = "non-empty-state" // This prints "non-empty-state" println(getStateValue()) } ``` Note: The `check()` function allows the compiler to perform [smart casting](typecasts.html#smart-casts). After a successful check, the variable is automatically cast to a non-nullable type. These functions are often used for nullability checks to ensure that the variable is not null before proceeding. For example: ```KOTLIN fun printNonNullString(str: String?) { // Nullability check check(str != null) // After this successful check, 'str' is guaranteed to be // non-null and is automatically smart cast to non-nullable String println(str.length) } ``` #### error() function The [error()](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/error.html) function is used to signal an illegal state or a condition in the code that logically should not occur. It's suitable for scenarios when you want to throw an exception intentionally in your code, such as when the code encounters an unexpected state. This function is particularly useful in `when` expressions, providing a clear way to handle cases that shouldn't logically happen. In the following example, the `error()` function is used to handle an undefined user role. If the role is not one of the predefined ones, an [IllegalStateException](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-illegal-state-exception/) is thrown: ```KOTLIN class User(val name: String, val role: String) fun processUserRole(user: User) { when (user.role) { "admin" -> println("${user.name} is an admin.") "editor" -> println("${user.name} is an editor.") "viewer" -> println("${user.name} is a viewer.") else -> error("Undefined role: ${user.role}") } } fun main() { // This works as expected val user1 = User("Alice", "admin") processUserRole(user1) // Alice is an admin. // This throws an IllegalStateException val user2 = User("Bob", "guest") processUserRole(user2) } ``` ## Handle exceptions using try-catch blocks When an exception is thrown, it interrupts the normal execution of the program. You can handle exceptions gracefully with the `try` and `catch` keywords to keep your program stable. The `try` block contains the code that might throw an exception, while the `catch` block catches and handles the exception if it occurs. The exception is caught by the first `catch` block that matches its specific type or a [superclass](inheritance.html) of the exception. Here's how you can use the `try` and `catch` keywords together: ```KOTLIN try { // Code that may throw an exception } catch (e: SomeException) { // Code for handling the exception } ``` It's a common approach to use `try-catch` as an expression, so it can return a value from either the `try` block or the `catch` block: ```KOTLIN fun main() { val num: Int = try { // If count() completes successfully, its return value is assigned to num count() } catch (e: ArithmeticException) { // If count() throws an exception, the catch block returns -1, // which is assigned to num -1 } println("Result: $num") } // Simulates a function that might throw ArithmeticException fun count(): Int { // Change this value to return a different value to num val a = 0 return 10 / a } ``` You can handle an exception without using the exception instance. For example, you can provide a fallback value or a generic error message in the `catch` block. Use an underscore (`_`) instead of the exception parameter name to indicate that the exception instance is intentionally ignored: ```KOTLIN import java.io.File import java.io.IOException //sampleStart fun main() { val userSettings = try { File("user-settings.json").readText() // Catches IOException without using the exception instance } catch (_: IOException) { // Uses a fallback value if loading the file fails "{}" } println(userSettings) } //sampleEnd ``` You can use multiple `catch` handlers for the same `try` block. You can add as many `catch` blocks as needed to handle different exceptions distinctively. When you have multiple `catch` blocks, it's important to order them from the most specific to the least specific exception, following a top-to-bottom order in your code. This ordering aligns with the program's execution flow. Consider this example with [custom exceptions](#create-custom-exceptions): ```KOTLIN open class WithdrawalException(message: String) : Exception(message) class InsufficientFundsException(message: String) : WithdrawalException(message) fun processWithdrawal(amount: Double, availableFunds: Double) { if (amount > availableFunds) { throw InsufficientFundsException("Insufficient funds for the withdrawal.") } if (amount < 1 || amount % 1 != 0.0) { throw WithdrawalException("Invalid withdrawal amount.") } println("Withdrawal processed") } fun main() { val availableFunds = 500.0 // Change this value to test different scenarios val withdrawalAmount = 500.5 try { processWithdrawal(withdrawalAmount.toDouble(), availableFunds) // The order of catch blocks is important! } catch (e: InsufficientFundsException) { println("Caught an InsufficientFundsException: ${e.message}") } catch (e: WithdrawalException) { println("Caught a WithdrawalException: ${e.message}") } } ``` A general catch block handling `WithdrawalException`, catches all exceptions of its type, including specific ones like `InsufficientFundsException`, unless they are caught earlier by a more specific catch block. ### The finally block The `finally` block contains code that always executes, regardless of whether the `try` block completes successfully or throws an exception. With the `finally` block, you can clean up code after the execution of `try` and `catch` blocks. This is especially important when working with resources like files or network connections, as `finally` guarantees they are properly closed or released. Here is how you would typically use the `try-catch-finally` blocks together: ```KOTLIN try { // Code that may throw an exception } catch (e: YourException) { // Exception handler } finally { // Code that is always executed } ``` The returned value of a `try` expression is determined by the last executed expression in either the `try` or `catch` block. If no exceptions occur, the result comes from the `try` block; if an exception is handled, it comes from the `catch` block. The `finally` block is always executed, but it doesn't change the result of the `try-catch` block. Let's look at an example to demonstrate: ```KOTLIN fun divideOrNull(a: Int): Int { // The try block is always executed // An exception here (division by zero) causes an immediate jump to the catch block try { val b = 44 / a println("try block: Executing division: $b") return b } // The catch block is executed due to the ArithmeticException (division by zero if a ==0) catch (e: ArithmeticException) { println("catch block: Encountered ArithmeticException $e") return -1 } finally { println("finally block: The finally block is always executed") } } fun main() { // Change this value to get a different result. An ArithmeticException will return: -1 divideOrNull(0) } ``` Note: In Kotlin, the idiomatic way to manage resources that implement the [AutoClosable](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-auto-closeable/) interface, such as file streams like `FileInputStream` or `FileOutputStream`, is to use the [.use()](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/use.html) function. This function automatically closes the resource when the block of code completes, regardless of whether an exception is thrown, thereby eliminating the need for a `finally` block. Consequently, Kotlin does not require a special syntax like [Java's try-with-resources](https://docs.oracle.com/javase/tutorial/essential/exceptions/tryResourceClose.html) for resource management. ```KOTLIN FileWriter("test.txt").use { writer -> writer.write("some text") // After this block, the .use function automatically calls writer.close(), similar to a finally block } ``` If your code requires resource cleanup without handling exceptions, you can also use `try` with the `finally` block without `catch` blocks: ```KOTLIN class MockResource { fun use() { println("Resource being used") // Simulate a resource being used // This throws an ArithmeticException if division by zero occurs val result = 100 / 0 // This line is not executed if an exception is thrown println("Result: $result") } fun close() { println("Resource closed") } } fun main() { val resource = MockResource() //sampleStart try { // Attempts to use the resource resource.use() } finally { // Ensures that the resource is always closed, even if an exception occurs resource.close() } // This line is not printed if an exception is thrown println("End of the program") //sampleEnd } ``` As you can see, the `finally` block guarantees that the resource is closed, regardless of whether an exception occurs. In Kotlin, you have the flexibility to use only a `catch` block, only a `finally` block, or both, depending on your specific needs, but a `try` block must always be accompanied by at least one `catch` block or a `finally` block. ## Create custom exceptions In Kotlin, you can define custom exceptions by creating classes that extend the built-in `Exception` class. This allows you to create more specific error types tailored to your application's needs. To create one, you can define a class that extends `Exception`: ```KOTLIN class MyException: Exception("My message") ``` In this example, there is a default error message, "My message", but you can leave it blank if you want. Tip: Exceptions in Kotlin are stateful objects, carrying information specific to the context of their creation, referred to as the [stack trace](#stack-trace). Avoid creating exceptions using [object declarations](object-declarations.html#object-declarations-overview). Instead, create a new instance of the exception every time you need one. This way, you can ensure the exception's state accurately reflects the specific context. Custom exceptions can also be a subclass of any pre-existent exception subclass, like the `ArithmeticException` subclass: ```KOTLIN class NumberTooLargeException: ArithmeticException("My message") ``` Note: If you want to create subclasses of custom exceptions, you must declare the parent class as `open` because [classes are final by default](inheritance.html) and cannot be subclassed otherwise. For example: ```KOTLIN // Declares a custom exception as an open class, making it subclassable open class MyCustomException(message: String): Exception(message) // Creates a subclass of the custom exception class SpecificCustomException: MyCustomException("Specific error message") ``` Custom exceptions behave just like built-in exceptions. You can throw them using the `throw` keyword, and handle them with `try-catch-finally` blocks. Let's look at an example to demonstrate: ```KOTLIN class NegativeNumberException: Exception("Parameter is less than zero.") class NonNegativeNumberException: Exception("Parameter is a non-negative number.") fun myFunction(number: Int) { if (number < 0) throw NegativeNumberException() else if (number >= 0) throw NonNegativeNumberException() } fun main() { // Change the value in this function to a get a different exception myFunction(1) } ``` In applications with diverse error scenarios, creating a hierarchy of exceptions can help make the code clearer and more specific. You can achieve this by using an [abstract class](classes.html#abstract-classes) or a [sealed class](sealed-classes.html#constructors) as a base for common exception features and creating specific subclasses for detailed exception types. Additionally, custom exceptions including parameters with default values offer flexibility, allowing initialization with varied messages, which enables more granular error handling. Let's look at an example using the sealed class `AccountException` as the base for an exception hierarchy, and class `APIKeyExpiredException`, a subclass, which showcases the use of parameters with default values for improved exception detail: ```KOTLIN //sampleStart // Creates a sealed class as the base for an exception hierarchy for account-related errors sealed class AccountException(message: String, cause: Throwable? = null): Exception(message, cause) // Creates a subclass of AccountException class InvalidAccountCredentialsException : AccountException("Invalid account credentials detected") // Creates a subclass of AccountException, which allows the addition of custom messages and causes class APIKeyExpiredException(message: String = "API key expired", cause: Throwable? = null) : AccountException(message, cause) // Change values of placeholder functions to get different results fun areCredentialsValid(): Boolean = true fun isAPIKeyExpired(): Boolean = true //sampleEnd // Validates account credentials and API key fun validateAccount() { if (!areCredentialsValid()) throw InvalidAccountCredentialsException() if (isAPIKeyExpired()) { // Example of throwing APIKeyExpiredException with a specific cause val cause = RuntimeException("API key validation failed due to network error") throw APIKeyExpiredException(cause = cause) } } fun main() { try { validateAccount() println("Operation successful: Account credentials and API key are valid.") } catch (e: AccountException) { println("Error: ${e.message}") e.cause?.let { println("Caused by: ${it.message}") } } } ``` ## The Nothing type In Kotlin, every expression has a type. The type of the expression `throw IllegalArgumentException()` is [Nothing](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-nothing.html), a built-in type that is a subtype of all other types, also known as [the bottom type](https://en.wikipedia.org/wiki/Bottom_type). This means `Nothing` can be used as a return type or generic type where any other type is expected, without causing type errors. `Nothing` is a special type in Kotlin used to represent functions or expressions that never complete successfully, either because they always throw an exception or enter an endless execution path like an infinite loop. You can use `Nothing` to mark functions that are not yet implemented or are designed to always throw an exception, clearly indicating your intentions to both the compiler and code readers. If the compiler infers a `Nothing` type in a function signature, it will warn you. Explicitly defining `Nothing` as the return type can eliminate this warning. This Kotlin code demonstrates the use of the `Nothing` type, where the compiler marks the code following the function call as unreachable: ```KOTLIN class Person(val name: String?) fun fail(message: String): Nothing { throw IllegalArgumentException(message) // This function will never return successfully. // It will always throw an exception. } fun main() { // Creates an instance of Person with 'name' as null val person = Person(name = null) val s: String = person.name ?: fail("Name required") // 's' is guaranteed to be initialized at this point println(s) } ``` Kotlin's [TODO()](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-t-o-d-o.html) function, which also uses the `Nothing` type, serves as a placeholder to highlight areas of the code that need future implementation: ```KOTLIN fun notImplementedFunction(): Int { TODO("This function is not yet implemented") } fun main() { val result = notImplementedFunction() // This throws a NotImplementedError println(result) } ``` As you can see, the `TODO()` function always throws a [NotImplementedError](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-not-implemented-error/) exception. ## Exception classes Let's explore some common exception types found in Kotlin, which are all subclasses of the [RuntimeException](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-runtime-exception/) class: * [ArithmeticException](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-arithmetic-exception/): This exception occurs when an arithmetic operation is impossible to perform, like division by zero. ```KOTLIN val example = 2 / 0 // throws ArithmeticException ``` * [IndexOutOfBoundsException](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-index-out-of-bounds-exception/): This exception is thrown to indicate that an index of some sort, such as an array or string, is out of range. ```KOTLIN val myList = mutableListOf(1, 2, 3) myList.removeAt(3) // throws IndexOutOfBoundsException ``` Note: To avoid this exception, use a safer alternative, such as the [getOrNull()](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.collections/get-or-null.html) function: ```KOTLIN val myList = listOf(1, 2, 3) // Returns null, instead of IndexOutOfBoundsException val element = myList.getOrNull(3) println("Element at index 3: $element") ``` * [NoSuchElementException](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-no-such-element-exception/): This exception is thrown when an element that does not exist in a particular collection is accessed. It occurs when using methods that expect a specific element, such as [first()](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.collections/first.html) or [last()](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.collections/last.html). ```KOTLIN val emptyList = listOf() val firstElement = emptyList.first() // throws NoSuchElementException ``` Note: To avoid this exception, use a safer alternative, such as the [firstOrNull()](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.collections/first-or-null.html) function: ```KOTLIN val emptyList = listOf() // Returns null, instead of NoSuchElementException val firstElement = emptyList.firstOrNull() println("First element in empty list: $firstElement") ``` * [NumberFormatException](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-number-format-exception/): This exception occurs when attempting to convert a string to a numeric type, but the string doesn't have an appropriate format. ```KOTLIN val string = "This is not a number" val number = string.toInt() // throws NumberFormatException ``` Note: To avoid this exception, use a safer alternative, such as the [toIntOrNull()](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.text/to-int-or-null.html) function: ```KOTLIN val nonNumericString = "not a number" // Returns null, instead of NumberFormatException val number = nonNumericString.toIntOrNull() println("Converted number: $number") ``` * [NullPointerException](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-null-pointer-exception/): This exception is thrown when an application attempts to use an object reference that has the `null` value. Even though Kotlin's null safety features significantly reduce the risk of NullPointerExceptions, they can still occur either through deliberate use of the `!!` operator or when interacting with Java, which lacks Kotlin's null safety. ```KOTLIN val text: String? = null println(text!!.length) // throws a NullPointerException ``` While all exceptions are unchecked in Kotlin, and you don't have to catch them explicitly, you still have the flexibility to catch them if desired. ### Exception hierarchy The root of the Kotlin exception hierarchy is the [Throwable](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-throwable/) class. It has two direct subclasses, [Error](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-error/) and [Exception](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-exception/): * The `Error` subclass represents serious fundamental problems that an application might not be able to recover from by itself. These are problems that you generally would not attempt to handle, such as [OutOfMemoryError](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-out-of-memory-error/) or `StackOverflowError`. * The `Exception` subclass is used for conditions that you might want to handle. Subtypes of the `Exception` type, such as the [RuntimeException](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-runtime-exception/) and `IOException` (Input/Output Exception), deal with exceptional events in applications. ![Exception hierarchy - the Throwable class](images/throwable.svg) `RuntimeException` is usually caused by insufficient checks in the program code and can be prevented programmatically. Kotlin helps prevent common `RuntimeExceptions` like `NullPointerException` and provides compile-time warnings for potential runtime errors, such as division by zero. The following picture demonstrates a hierarchy of subtypes descended from `RuntimeException`: ![Hierarchy of RuntimeExceptions](images/runtime-exception.svg) ## Stack trace The stack trace is a report generated by the runtime environment, used for debugging. It shows the sequence of function calls leading to a specific point in the program, especially where an error or exception occurred. Let's see an example where the stack trace is automatically printed because of an exception in a JVM environment: ```KOTLIN fun main() { //sampleStart throw ArithmeticException("This is an arithmetic exception!") //sampleEnd } ``` Running this code in a JVM environment produces the following output: ```TEXT Exception in thread "main" java.lang.ArithmeticException: This is an arithmetic exception! at MainKt.main(Main.kt:3) at MainKt.main(Main.kt) ``` The first line is the exception description, which includes: * Exception type: `java.lang.ArithmeticException` * Thread: `main` * Exception message: `"This is an arithmetic exception!"` Each other line that starts with an `at` after the exception description is the stack trace. A single line is called a stack trace element or a stack frame: * `at MainKt.main (Main.kt:3)`: This shows the method name (`MainKt.main`) and the source file and line number where the method was called (`Main.kt:3`). * `at MainKt.main (Main.kt)`: This shows that the exception occurs in the `main()` function of the `Main.kt` file. ## Exception interoperability with Java, Swift, and Objective-C Since Kotlin treats all exceptions as unchecked, it can lead to complications when such exceptions are called from languages that distinguish between checked and unchecked exceptions. To address this disparity in exception handling between Kotlin and languages like Java, Swift, and Objective-C, you can use the [@Throws](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-throws/) annotation. This annotation alerts callers about possible exceptions. For more information, see [Calling Kotlin from Java](java-to-kotlin-interop.html#checked-exceptions) and [Interoperability with Swift/Objective-C](native-objc-interop.html#errors-and-exceptions). # Functions To declare a function in Kotlin: * Use the `fun` keyword. * Specify the parameters in parentheses `()`. * Include the [return type](#return-types) if needed. For example: ```KOTLIN //sampleStart // 'double' is the name of the function // 'x' is a parameter of Int type // The expected return value is of Int type too fun double(x: Int): Int { return 2 * x } //sampleEnd fun main() { println(double(5)) // 10 } ``` ## Function usage Functions are called using the standard approach: ```KOTLIN val result = double(2) ``` To call a [member](classes.html) or [extension function](extensions.html#extension-functions), use a period `.`: ```KOTLIN // Creates an instance of the Stream class and calls read() Stream().read() ``` ### Parameters Declare function parameters using Pascal notation: `name: Type`. You must separate parameters using commas and give each parameter a type explicitly: ```KOTLIN fun powerOf(number: Int, exponent: Int): Int { /*...*/ } ``` When you pass an object to a function, the compiler passes a copy of the reference to that object. The copied reference points to the same object, so the function can modify the object's mutable state. Function parameters are read-only inside the function body (implicitly declared as `val`), so you can't reassign them: ```KOTLIN class Counter(var value: Int) fun reset(counter: Counter) { counter.value = 0 // Allowed: modifies the object counter = Counter(0) // Error: 'val' cannot be reassigned } ``` You can use a [trailing comma](coding-conventions.html#trailing-commas) when declaring function parameters: ```KOTLIN fun powerOf( number: Int, exponent: Int, // trailing comma ) { /*...*/ } ``` Trailing commas help with refactorings and code maintenance: you can move parameters within the declaration without worrying about which is going to be the last one. Note: Kotlin functions can receive other functions as parameters — and be passed as arguments. For more information, see [Higher-order functions and lambdas](lambdas.html). ### Parameters with default values You can make a function parameter optional by specifying a default value for it. Kotlin uses the default value when you call the function without providing an argument that corresponds to that parameter. Parameters with default values are also known as optional parameters. Optional parameters reduce the need for multiple overloads, since you don't have to declare different versions of a function just to allow skipping a parameter with a reasonable default. Set a default value by appending `=` to the parameter declaration: ```KOTLIN fun read( b: ByteArray, // The default value of 'off' is 0 off: Int = 0, // The default value of 'len' is calculated // as the size of the 'b' array len: Int = b.size, ) { /*...*/ } ``` When you declare a parameter with a default value before a parameter without a default value, you can only use the default value by [naming the argument](#named-arguments): ```KOTLIN fun greeting( userId: Int = 0, message: String, ) { /*...*/ } fun main() { // Uses 0 as the default value for 'userId' greeting(message = "Hello!") // Error: No value passed for parameter 'message' greeting("Hello!") } ``` [Trailing lambdas](lambdas.html#passing-trailing-lambdas) are an exception to this rule, since the last parameter must correspond to the passed function: ```KOTLIN fun main () { //sampleStart fun greeting( userId: Int = 0, message: () -> Unit, ) { println(userId) message() } // Uses the default value for 'userId' greeting() { println ("Hello!") } // 0 // Hello! //sampleEnd } ``` [Overriding methods](inheritance.html#overriding-methods) always use the base method's default parameter values. When you override a method that has default parameter values, you must omit the default parameter values from the signature: ```KOTLIN open class Shape { open fun draw(width: Int = 10, height: Int = 5) { /*...*/ } } class Rectangle : Shape() { // It's not allowed to specify default values here // but this function also uses 10 for 'width' and 5 for 'height' // by default. override fun draw(width: Int, height: Int) { /*...*/ } } ``` #### Non-constant expressions as default values You can assign a parameter a default value that isn't constant. For example, the default can be the result of a function call or a calculation that uses the values of other arguments, like the `len` parameter in this example: ```KOTLIN fun read( b: ByteArray, off: Int = 0, len: Int = b.size, ) { /*...*/ } ``` Parameters that refer to the values of other parameters must be declared later in the order. In this example, `len` must be declared after `b`. In general, you can assign any expression as the default value of a parameter. However, default values are only evaluated when the function is called without the corresponding parameter and a default value needs to be assigned. For example, this function prints out a line only when it is called without the `print` parameter: ```KOTLIN fun main() { //sampleStart fun read( b: Int, print: Unit? = println("No argument passed for 'print'") ) { println(b) } // Prints "No argument passed for 'print'", then "1" read(1) // Prints only "1" read(1, null) //sampleEnd } ``` If the last parameter in a function declaration has a functional type, you can pass the corresponding [lambda](lambdas.html#lambda-expression-syntax) argument either as a named argument or [outside the parentheses](lambdas.html#passing-trailing-lambdas): ```KOTLIN fun main() { //sampleStart fun log( level: Int = 0, code: Int = 1, action: () -> Unit, ) { println (level) println (code) action() } // Passes 1 for 'level' and uses the default value 1 for 'code' log(1) { println("Connection established") } // Uses both default values, 0 for 'level' and 1 for 'code' log(action = { println("Connection established") }) // Equivalent to the previous call, uses both default values log { println("Connection established") } //sampleEnd } ``` ### Named arguments You can name one or more of a function's arguments when calling it. This can be helpful when a function call has many arguments. In such cases, it's difficult to associate a value with an argument, especially if it's `null` or a boolean value. When you use named arguments in a function call, you can list them in any order. Consider the `reformat()` function, which has 4 arguments with default values: ```KOTLIN fun reformat( str: String, normalizeCase: Boolean = true, upperCaseFirstLetter: Boolean = true, divideByCamelHumps: Boolean = false, wordSeparator: Char = ' ', ) { /*...*/ } ``` When calling this function, you can name some of the arguments: ```KOTLIN reformat( "String!", normalizeCase = false, upperCaseFirstLetter = false, divideByCamelHumps = true, '_' ) ``` You can skip all the arguments with default values: ```KOTLIN reformat("This is a long String!") ``` You can also skip some arguments with default values, rather than omitting them all. However, after the first skipped argument, you must name all subsequent arguments: ```KOTLIN reformat( "This is a short String!", upperCaseFirstLetter = false, wordSeparator = '_' ) ``` You can pass a [variable number of arguments](#variable-number-of-arguments-varargs) (`vararg`) by naming the corresponding argument. In this example, it's an array: ```KOTLIN fun mergeStrings(vararg strings: String) { /*...*/ } mergeStrings(strings = arrayOf("a", "b", "c")) ``` Note: When calling Java functions on the JVM, you can't use the named argument syntax because Java bytecode does not always preserve the names of function parameters. ### Return types When you declare a function with a block body (by putting instructions within curly braces `{}`), you must always specify a return type explicitly. The only exception is when the function returns `Unit`,[in which case specifying the return type is optional](#unit-returning-functions). Kotlin doesn't infer return types for functions with block bodies. Their control flow can be complex, which makes the return type unclear to the reader and sometimes even to the compiler. However, Kotlin can infer the return type for [single-expression functions](#single-expression-functions) if you don't specify it. Kotlin functions return a single value, but that value can contain multiple pieces of data. For ways to represent these values, see [Return multiple values](#return-multiple-values). #### Return multiple values When you need to return multiple related values with distinct meanings, declare a [data class](data-classes.html), even if you only use it with one function: ```KOTLIN data class OrderSummary( val subtotal: Double, val tax: Double, ) fun calculateOrderSummary(prices: List): OrderSummary { val subtotal = prices.sum() val tax = subtotal * 0.2 return OrderSummary(subtotal, tax) } fun main() { val summary = calculateOrderSummary(listOf(12.50, 8.00, 4.50)) println(summary.subtotal) // 25.0 println(summary.tax) // 5.0 } ``` A data class works well when you need to return multiple values with distinct meanings. If the returned values are of the same kind and you want to handle them as a group, consider returning a collection instead: ```KOTLIN data class Person(val name: String) val friendGroups = listOf( listOf(Person("Alice"), Person("Bob")), listOf(Person("Charlie"), Person("Diana"), Person("Eve")), listOf(Person("Frank")) ) fun findLargestGroupOfFriends(): List { return friendGroups.maxByOrNull { it.size } ?: emptyList() } fun main() { val largestGroup = findLargestGroupOfFriends() println(largestGroup.map { it.name }) // [Charlie, Diana, Eve] } ``` If you need to return a fixed number of values, you can also use [Pair](https://kotlinlang.org/api/core/kotlin-stdlib/kotlin/-pair/) or [Triple](https://kotlinlang.org/api/core/kotlin-stdlib/kotlin/-triple/) data classes from the standard library. However, their properties have generic names such as `first`, `second`, and `third`, which can make the result difficult to understand. For example, although the `calculateOrderTotals()` function returns a `Pair`, it's not clear what each `Double` represents: ```KOTLIN fun calculateOrderTotals(prices: List): Pair { val subtotal = prices.sum() val tax = subtotal * 0.2 return Pair(subtotal, tax) } fun main() { val totals = calculateOrderTotals(listOf(12.50, 8.00, 4.50)) // What does 'first' mean? println(totals.first) // 25.0 // What does 'second' mean? println(totals.second) // 5.0 } ``` For results with distinct meanings, prefer a data class with descriptive property names, as demonstrated in the [OrderSummary data class example](#return-multiple-values). ### Single-expression functions When the function body consists of a single expression, you can omit the curly braces and specify the body after an `=` symbol: ```KOTLIN fun double(x: Int): Int = x * 2 ``` Most of the time you don't have to explicitly declare [the return type](#return-types): ```KOTLIN // Compiler infers that the function returns Int fun double(x: Int) = x * 2 ``` The compiler can sometimes run into problems when inferring return types from single expressions. In such cases, you should add the return type explicitly. For example, functions that are recursive or mutually recursive (calling each other) and functions with typeless expressions like `fun empty() = null` always require a return type. When you do use an inferred return type, make sure to check the actual result because the compiler may infer a type that is less useful to you. In the example above, if you want the `double()` function to return `Number` instead of `Int`, you have to declare this explicitly. If you use a `return` statement inside an expression body, you must specify the return type explicitly: ```KOTLIN fun getDisplayNameOrDefault(userId: String?): String = getDisplayName(userId ?: return "default") ``` ### Unit-returning functions If a function has a block body (instructions within curly braces `{}`) and does not return a useful value, the compiler assumes its return type is `Unit`. `Unit` is a type that has only one value, also called `Unit`. You don't have to specify `Unit` as a return type, except for functional type parameters. You never have to return `Unit` explicitly. For example, you can declare a `printHello()` function without returning `Unit`: ```KOTLIN // The declaration of the functional type parameter ('action') still // needs an explicit return type fun printHello(name: String?, action: () -> Unit) { if (name != null) println("Hello $name") else println("Hi there!") action() } fun main() { printHello("Kodee") { println("This runs after the greeting.") } // Hello Kodee // This runs after the greeting. printHello(null) { println("No name provided, but action still runs.") } // No name provided, but action still runs } ``` Which is equivalent to this verbose declaration: ```KOTLIN //sampleStart fun printHello(name: String?, action: () -> Unit): Unit { if (name != null) println("Hello $name") else println("Hi there!") action() return Unit } //sampleEnd fun main() { printHello("Kodee") { println("This runs after the greeting.") } // Hello Kodee // This runs after the greeting. printHello(null) { println("No name provided, but action still runs.") } // No name provided, but action still runs } ``` ### Variable number of arguments (varargs) To pass a variable number of arguments to a function, you can mark one of its parameters (usually the last one) with the `vararg` modifier. Inside a function, you can use a `vararg`-parameter of type `T` as an array of `T`: ```KOTLIN fun asList(vararg ts: T): List { val result = ArrayList() for (t in ts) // ts is an Array result.add(t) return result } ``` Then you can pass a variable number of arguments to the function: ```KOTLIN fun asList(vararg ts: T): List { val result = ArrayList() for (t in ts) // ts is an Array result.add(t) return result } fun main() { //sampleStart val list = asList(1, 2, 3) println(list) // [1, 2, 3] //sampleEnd } ``` Only one parameter can be marked as `vararg`. If you declare a `vararg` parameter anywhere other than last in the parameter list, you must pass values for the following parameters using named arguments. If a parameter has a function type, you can also pass its value by placing a lambda outside the parentheses. When you call a `vararg`-function, you can pass arguments individually, as in the example of `asList(1, 2, 3)`. If you already have an array and want to pass its contents to a function as a `vararg` parameter or as a part of it, use the [spread operator](arrays.html#pass-variable-number-of-arguments-to-a-function) by prefixing the array name with `*`: ```KOTLIN fun asList(vararg ts: T): List { val result = ArrayList() for (t in ts) result.add(t) return result } fun main() { //sampleStart val a = arrayOf(1, 2, 3) // The function receives the array [-1, 0, 1, 2, 3, 4] list = asList(-1, 0, *a, 4) println(list) // [-1, 0, 1, 2, 3, 4] //sampleEnd } ``` If you want to pass a [primitive type array](arrays.html#primitive-type-arrays) as `vararg`, you need to convert it to a regular (typed) array using the [.toTypedArray()](https://kotlinlang.org/api/core/kotlin-stdlib/kotlin.collections/to-typed-array.html) function: ```KOTLIN // 'a' is an IntArray, which is a primitive type array val a = intArrayOf(1, 2, 3) val list = asList(-1, 0, *a.toTypedArray(), 4) ``` ### Infix notation You can declare functions that can be called without parentheses or the period by using the `infix` keyword. This can help make simple function calls in your code easier to read. ```KOTLIN infix fun Int.shl(x: Int): Int { /*...*/ } // Calls the function using the general notation 1.shl(2) // Calls the function using the infix notation 1 shl 2 ``` Infix functions must meet the following requirements: * They must be member functions of a class or [extension functions](extensions.html). * They must have a single parameter. * The parameter must not [accept a variable number of arguments](#variable-number-of-arguments-varargs) (`vararg`) and must have no [default value](#parameters-with-default-values). Note: Infix function calls have lower precedence than arithmetic operators, type casts, and the `rangeTo` operator. The following expressions are equivalent: * `1 shl 2 + 3` is equivalent to `1 shl (2 + 3)` * `0 until n * 2` is equivalent to `0 until (n * 2)` * `xs union ys as Set<*>` is equivalent to `xs union (ys as Set<*>)` On the other hand, an infix function call's precedence is higher than that of the boolean operators `&&` and `||`, `is`- and `in`-checks, and some other operators. These expressions are equivalent as well: * `a && b xor c` is equivalent to `a && (b xor c)` * `a xor b in c` is equivalent to `(a xor b) in c` Note that infix functions always require both the receiver and the parameter to be specified. When you call a method on the current receiver using the infix notation, use `this` explicitly. This ensures unambiguous parsing. ```KOTLIN class MyStringCollection { val items = mutableListOf() infix fun add(s: String) { println("Adding: $s") items += s } fun build() { add("first") // Correct: ordinary function call this add "second" // Correct: infix call with an explicit receiver // add "third" // Compiler error: needs an explicit receiver } fun printAll() = println("Items = $items") } fun main() { val myStrings = MyStringCollection() // Adds "first" and "second" to the list myStrings.build() myStrings.printAll() // Adding: first // Adding: second // Items = [first, second] } ``` ## Function scope You can declare Kotlin functions at the top level in a file, meaning you do not need to create a class to hold a function. Functions can also be declared locally as member functions or extension functions. ### Local functions Kotlin supports local functions, which are functions declared inside other functions. For example, the following code implements the Depth-first search algorithm for a given graph. The local `dfs()` function inside the outer `dfs()` function to hide the implementation and handle recursive calls: ```KOTLIN class Person(val name: String) { val friends = mutableListOf() } class SocialGraph(val people: List) //sampleStart fun dfs(graph: SocialGraph) { fun dfs(current: Person, visited: MutableSet) { if (!visited.add(current)) return println("Visited ${current.name}") for (friend in current.friends) dfs(friend, visited) } dfs(graph.people[0], HashSet()) } //sampleEnd fun main() { val alice = Person("Alice") val bob = Person("Bob") val charlie = Person("Charlie") alice.friends += bob bob.friends += charlie charlie.friends += alice val network = SocialGraph(listOf(alice, bob, charlie)) dfs(network) } ``` A local function can access local variables of outer functions (the closure). In the case above, the `visited` function parameter can be a local variable: ```KOTLIN class Person(val name: String) { val friends = mutableListOf() } class SocialGraph(val people: List) //sampleStart fun dfs(graph: SocialGraph) { val visited = HashSet() fun dfs(current: Person) { if (!visited.add(current)) return println("Visited ${current.name}") for (friend in current.friends) dfs(friend) } dfs(graph.people[0]) } //sampleEnd fun main() { val alice = Person("Alice") val bob = Person("Bob") val charlie = Person("Charlie") alice.friends += bob bob.friends += charlie charlie.friends += alice val network = SocialGraph(listOf(alice, bob, charlie)) dfs(network) } ``` ### Member functions A member function is a function that is defined inside a class or object: ```KOTLIN class Sample { fun foo() { print("Foo") } } ``` To call member functions, write the instance or object name, then add a `.` and write the function name: ```KOTLIN // Creates an instance of the Stream class and calls read() Stream().read() ``` For more information on classes and overriding members see [Classes](classes.html) and [Inheritance](classes.html#inheritance). ## Generic functions You can specify generic parameters for a function by using angle brackets `<>` before the function name: ```KOTLIN fun singletonList(item: T): List { /*...*/ } ``` For more information on generic functions, see [Generics](generics.html). ## Tail recursive functions Kotlin supports a style of functional programming known as [tail recursion](https://en.wikipedia.org/wiki/Tail_call). For some algorithms that would normally use loops, you can use a recursive function instead without the risk of stack overflow. When a function is marked with the `tailrec` modifier and meets the required formal conditions, the compiler optimizes out the recursion, leaving behind a fast and efficient loop based version instead: ```KOTLIN import kotlin.math.cos import kotlin.math.abs // An arbitrary "good enough" precision val eps = 1E-10 tailrec fun findFixPoint(x: Double = 1.0): Double = if (abs(x - cos(x)) < eps) x else findFixPoint(cos(x)) ``` This code calculates the fixed point of cosine (a mathematical constant). The function calls `cos()` repeatedly starting at `1.0` until the result no longer changes, yielding a result of `0.7390851332151611` for the specified `eps` precision. The code is equivalent to this more traditional style: ```KOTLIN import kotlin.math.cos import kotlin.math.abs // An arbitrary "good enough" precision val eps = 1E-10 private fun findFixPoint(): Double { var x = 1.0 while (true) { val y = cos(x) if (abs(x - y) < eps) return x x = cos(x) } } ``` You can apply the `tailrec` modifier to a function only when it calls itself as its final operation. You cannot use tail recursion when there is more code after the recursive call, within [try/catch/finally blocks](exceptions.html#handle-exceptions-using-try-catch-blocks), or when the function is [open](inheritance.html). See also: * [Inline functions](inline-functions.html) * [Extension functions](extensions.html) * [Higher-order functions and lambdas](lambdas.html) # Higher-order functions and lambdas Kotlin functions are [first-class](https://en.wikipedia.org/wiki/First-class_function), which means they can be stored in variables and data structures, and can be passed as arguments to and returned from other [higher-order functions](#higher-order-functions). You can perform any operations on functions that are possible for other non-function values. To facilitate this, Kotlin, as a statically typed programming language, uses a family of [function types](#function-types) to represent functions, and provides a set of specialized language constructs, such as [lambda expressions](#lambda-expressions-and-anonymous-functions). ## Higher-order functions A higher-order function is a function that takes functions as parameters, or returns a function. A good example of a higher-order function is the [functional programming idiom fold](https://en.wikipedia.org/wiki/Fold_(higher-order_function)) for collections. It takes an initial accumulator value and a combining function and builds its return value by consecutively combining the current accumulator value with each collection element, replacing the accumulator value each time: ```KOTLIN fun Collection.fold( initial: R, combine: (acc: R, nextElement: T) -> R ): R { var accumulator: R = initial for (element: T in this) { accumulator = combine(accumulator, element) } return accumulator } ``` In the code above, the `combine` parameter has the [function type](#function-types) `(R, T) -> R`, so it accepts a function that takes two arguments of types `R` and `T` and returns a value of type `R`. It is [invoked](#invoking-a-function-type-instance) inside the `for` loop, and the return value is then assigned to `accumulator`. To call `fold`, you need to pass an [instance of the function type](#instantiating-a-function-type) to it as an argument, and lambda expressions ([described in more detail below](#lambda-expressions-and-anonymous-functions)) are widely used for this purpose at higher-order function call sites: ```KOTLIN fun main() { //sampleStart val items = listOf(1, 2, 3, 4, 5) // Lambdas are code blocks enclosed in curly braces. items.fold(0, { // When a lambda has parameters, they go first, followed by '->' acc: Int, i: Int -> print("acc = $acc, i = $i, ") val result = acc + i println("result = $result") // The last expression in a lambda is considered the return value: result }) // Parameter types in a lambda are optional if they can be inferred: val joinedToString = items.fold("Elements:", { acc, i -> acc + " " + i }) // Function references can also be used for higher-order function calls: val product = items.fold(1, Int::times) //sampleEnd println("joinedToString = $joinedToString") println("product = $product") } ``` ## Function types Kotlin uses function types, such as `(Int) -> String`, for declarations that deal with functions: `val onClick: () -> Unit = ...`. These types have a special notation that corresponds to the signatures of the functions - their parameters and return values: * All function types have a parenthesized list of parameter types and a return type: `(A, B) -> C` denotes a type that represents functions that take two arguments of types `A` and `B` and return a value of type `C`. The list of parameter types may be empty, as in `() -> A`. The [Unit return type](functions.html#unit-returning-functions) cannot be omitted. * Function types can optionally have an additional receiver type, which is specified before the dot in the notation: the type `A.(B) -> C` represents functions that can be called on a receiver object `A` with a parameter `B` and return a value `C`. [Function literals with receiver](#function-literals-with-receiver) are often used along with these types. * [Suspending functions](coroutines-basics.html) belong to a special kind of function type that have a suspend modifier in their notation, such as `suspend () -> Unit` or `suspend A.(B) -> C`. The function type notation can optionally include names for the function parameters: `(x: Int, y: Int) -> Point`. These names can be used for documenting the meaning of the parameters. To specify that a function type is [nullable](null-safety.html#nullable-types-and-non-nullable-types), use parentheses as follows: `((Int, Int) -> Int)?`. Function types can also be combined using parentheses: `(Int) -> ((Int) -> Unit)`. Note: The arrow notation is right-associative, `(Int) -> (Int) -> Unit` is equivalent to the previous example, but not to `((Int) -> (Int)) -> Unit`. You can also give a function type an alternative name by using [a type alias](type-aliases.html): ```KOTLIN typealias ClickHandler = (Button, ClickEvent) -> Unit ``` ### Instantiating a function type There are several ways to obtain an instance of a function type: * Use a code block within a function literal, in one of the following forms: * a [lambda expression](#lambda-expressions-and-anonymous-functions): `{ a, b -> a + b }`, * an [anonymous function](#anonymous-functions): `fun(s: String): Int { return s.toIntOrNull() ?: 0 }` [Function literals with receiver](#function-literals-with-receiver) can be used as values of function types with receiver. * Use a callable reference to an existing declaration: * a top-level, local, member, or extension [function](reflection.html#function-references): `::isOdd`, `String::toInt`, * a top-level, member, or extension [property](reflection.html#property-references): `List::size`, * a [constructor](reflection.html#constructor-references): `::Regex` These include [bound callable references](reflection.html#bound-function-and-property-references) that point to a member of a particular instance: `foo::toString`. * Use instances of a custom class that implements a function type as an interface: ```KOTLIN class IntTransformer: (Int) -> Int { override operator fun invoke(x: Int): Int = TODO() } val intFunction: (Int) -> Int = IntTransformer() ``` The compiler can infer the function types for variables if there is enough information: ```KOTLIN val a = { i: Int -> i + 1 } // The inferred type is (Int) -> Int ``` Non-literal values of function types with and without a receiver are interchangeable, so the receiver can stand in for the first parameter, and vice versa. For instance, a value of type `(A, B) -> C` can be passed or assigned where a value of type `A.(B) -> C` is expected, and the other way around: ```KOTLIN fun main() { //sampleStart val repeatFun: String.(Int) -> String = { times -> this.repeat(times) } val twoParameters: (String, Int) -> String = repeatFun // OK fun runTransformation(f: (String, Int) -> String): String { return f("hello", 3) } val result = runTransformation(repeatFun) // OK //sampleEnd println("result = $result") } ``` Note: A function type with no receiver is inferred by default, even if a variable is initialized with a reference to an extension function. To alter that, specify the variable type explicitly. ### Invoking a function type instance A value of a function type can be invoked by using its [invoke(...) operator](operator-overloading.html#invoke-operator): `f.invoke(x)` or just `f(x)`. If the value has a receiver type, the receiver object should be passed as the first argument. Another way to invoke a value of a function type with receiver is to prepend it with the receiver object, as if the value were an [extension function](extensions.html): `1.foo(2)`. Example: ```KOTLIN fun main() { //sampleStart val stringPlus: (String, String) -> String = String::plus val intPlus: Int.(Int) -> Int = Int::plus println(stringPlus.invoke("<-", "->")) println(stringPlus("Hello, ", "world!")) println(intPlus.invoke(1, 1)) println(intPlus(1, 2)) println(2.intPlus(3)) // extension-like call //sampleEnd } ``` ### Inline functions Sometimes it is beneficial to use [inline functions](inline-functions.html), which provide flexible control flow, for higher-order functions. ## Lambda expressions and anonymous functions Lambda expressions and anonymous functions are function literals. Function literals are functions that are not declared but are passed immediately as an expression. Consider the following example: ```KOTLIN max(strings, { a, b -> a.length < b.length }) ``` The function `max` is a higher-order function, as it takes a function value as its second argument. This second argument is an expression that is itself a function, called a function literal, which is equivalent to the following named function: ```KOTLIN fun compare(a: String, b: String): Boolean = a.length < b.length ``` You can also create a suspending lambda expression using the `suspend` keyword. A suspending lambda has the function type `suspend () -> Unit` and can call other suspending functions: ```KOTLIN val suspendingTask = suspend { doSuspendingWork() } ``` ### Lambda expression syntax The full syntactic form of lambda expressions is as follows: ```KOTLIN val sum: (Int, Int) -> Int = { x: Int, y: Int -> x + y } ``` * A lambda expression is always surrounded by curly braces. * Parameter declarations in the full syntactic form go inside curly braces and have optional type annotations. * The body goes after the `->`. * If the inferred return type of the lambda is not `Unit`, the last (or possibly single) expression inside the lambda body is treated as the return value. If you leave all the optional annotations out, what's left looks like this: ```KOTLIN val sum = { x: Int, y: Int -> x + y } ``` ### Passing trailing lambdas According to Kotlin convention, if the last parameter of a function is a function, then a lambda expression passed as the corresponding argument can be placed outside the parentheses: ```KOTLIN val product = items.fold(1) { acc, e -> acc * e } ``` Such syntax is also known as trailing lambda. If the lambda is the only argument in that call, the parentheses can be omitted entirely: ```KOTLIN run { println("...") } ``` ### it: implicit name of a single parameter It's very common for a lambda expression to have only one parameter. If the compiler can parse the signature without any parameters, the parameter does not need to be declared and `->` can be omitted. The parameter will be implicitly declared under the name `it`: ```KOTLIN ints.filter { it > 0 } // this literal is of type '(it: Int) -> Boolean' ``` ### Returning a value from a lambda expression You can explicitly return a value from the lambda using the [qualified return](returns.html#return-to-labels) syntax. Otherwise, the value of the last expression is implicitly returned. Therefore, the two following snippets are equivalent: ```KOTLIN ints.filter { val shouldFilter = it > 0 shouldFilter } ints.filter { val shouldFilter = it > 0 return@filter shouldFilter } ``` This convention, along with [passing a lambda expression outside of parentheses](#passing-trailing-lambdas), allows for [LINQ-style](https://learn.microsoft.com/en-us/dotnet/csharp/programming-guide/concepts/linq/) code: ```KOTLIN strings.filter { it.length == 5 }.sortedBy { it }.map { it.uppercase() } ``` ### Underscore for unused variables If the lambda parameter is unused, you can place an underscore instead of its name: ```KOTLIN map.forEach { (_, value) -> println("$value!") } ``` ### Destructuring in lambdas Destructuring in lambdas is described as a part of [destructuring declarations](destructuring-declarations.html#destructuring-in-lambdas). ### Anonymous functions The lambda expression syntax above is missing one thing – the ability to specify the function's return type. In most cases, this is unnecessary because the return type can be inferred automatically. However, if you do need to specify it explicitly, you can use an alternative syntax: an anonymous function. ```KOTLIN fun(x: Int, y: Int): Int = x + y ``` An anonymous function looks very much like a regular function declaration, except its name is omitted. Its body can be either an expression (as shown above) or a block: ```KOTLIN fun(x: Int, y: Int): Int { return x + y } ``` The parameters and the return type are specified in the same way as for regular functions, except the parameter types can be omitted if they can be inferred from the context: ```KOTLIN ints.filter(fun(item) = item > 0) ``` The return type inference for anonymous functions works just like for normal functions: the return type is inferred automatically for anonymous functions with an expression body, but it has to be specified explicitly (or is assumed to be `Unit`) for anonymous functions with a block body. Note: When passing anonymous functions as parameters, place them inside the parentheses. The shorthand syntax that allows you to leave the function outside the parentheses works only for lambda expressions. Another difference between lambda expressions and anonymous functions is the behavior of [non-local returns](inline-functions.html#returns). A `return` statement without a label always returns from the function declared with the `fun` keyword. This means that a `return` inside a lambda expression will return from the enclosing function, whereas a `return` inside an anonymous function will return from the anonymous function itself. ### Closures A lambda expression or anonymous function (as well as a [local function](functions.html#local-functions) and an [object expression](object-declarations.html#object-expressions)) can access its closure, which includes the variables declared in the outer scope. The variables captured in the closure can be modified in the lambda: ```KOTLIN var sum = 0 ints.filter { it > 0 }.forEach { sum += it } print(sum) ``` ### Function literals with receiver [Function types](#function-types) with receiver, such as `A.(B) -> C`, can be instantiated with a special form of function literals – function literals with receiver. As mentioned above, Kotlin provides the ability [to call an instance](#invoking-a-function-type-instance) of a function type with receiver while providing the receiver object. Inside the body of the function literal, the receiver object passed to a call becomes an implicit `this`, so that you can access the members of that receiver object without any additional qualifiers, or access the receiver object using a [this expression](this-expressions.html). This behavior is similar to that of [extension functions](extensions.html), which also allow you to access the members of the receiver object inside the function body. Here is an example of a function literal with receiver along with its type, where `plus` is called on the receiver object: ```KOTLIN val sum: Int.(Int) -> Int = { other -> plus(other) } ``` The anonymous function syntax allows you to specify the receiver type of a function literal directly. This can be useful if you need to declare a variable of a function type with receiver, and then to use it later. ```KOTLIN val sum = fun Int.(other: Int): Int = this + other ``` Lambda expressions can be used as function literals with receiver when the receiver type can be inferred from the context. One of the most important examples of their usage is [type-safe builders](type-safe-builders.html): ```KOTLIN class HTML { fun body() { ... } } fun html(init: HTML.() -> Unit): HTML { val html = HTML() // create the receiver object html.init() // pass the receiver object to the lambda return html } html { // lambda with receiver begins here body() // calling a method on the receiver object } ``` # Type-safe builders By using well-named functions as builders in combination with [function literals with receiver](lambdas.html#function-literals-with-receiver), it is possible to create type-safe, statically-typed builders in Kotlin. Type-safe builders allow creating Kotlin-based domain-specific languages (DSLs) suitable for building complex hierarchical data structures in a semi-declarative way. Sample use cases for the builders are: * Generating markup with Kotlin code, such as [HTML](https://github.com/Kotlin/kotlinx.html) or XML * Configuring routes for a web server: [Ktor](https://ktor.io/docs/routing.html) Consider the following code: ```KOTLIN package html fun main() { //sampleStart val result = html { head { title { +"HTML encoding with Kotlin" } } body { h1 { +"HTML encoding with Kotlin" } p { +"this format can be used as an" +"alternative markup to HTML" } // An element with attributes and text content a(href = "http://kotlinlang.org") { +"Kotlin" } // Mixed content p { +"This is some" b { +"mixed" } +"text. For more see the" a(href = "http://kotlinlang.org") { +"Kotlin" } +"project" } p { +"some text" ul { for (i in 1..5) li { +"${i}*2 = ${i*2}" } } } } } //sampleEnd println(result) } interface Element { fun render(builder: StringBuilder, indent: String) } class TextElement(val text: String) : Element { override fun render(builder: StringBuilder, indent: String) { builder.append("$indent$text\n") } } @DslMarker annotation class HtmlTagMarker @HtmlTagMarker abstract class Tag(val name: String) : Element { val children = arrayListOf() val attributes = hashMapOf() protected fun initTag(tag: T, init: T.() -> Unit): T { tag.init() children.add(tag) return tag } override fun render(builder: StringBuilder, indent: String) { builder.append("$indent<$name${renderAttributes()}>\n") for (c in children) { c.render(builder, indent + " ") } builder.append("$indent\n") } private fun renderAttributes(): String { val builder = StringBuilder() for ((attr, value) in attributes) { builder.append(" $attr=\"$value\"") } return builder.toString() } override fun toString(): String { val builder = StringBuilder() render(builder, "") return builder.toString() } } abstract class TagWithText(name: String) : Tag(name) { operator fun String.unaryPlus() { children.add(TextElement(this)) } } class HTML() : TagWithText("html") { fun head(init: Head.() -> Unit) = initTag(Head(), init) fun body(init: Body.() -> Unit) = initTag(Body(), init) } class Head() : TagWithText("head") { fun title(init: Title.() -> Unit) = initTag(Title(), init) } class Title() : TagWithText("title") abstract class BodyTag(name: String) : TagWithText(name) { fun b(init: B.() -> Unit) = initTag(B(), init) fun p(init: P.() -> Unit) = initTag(P(), init) fun h1(init: H1.() -> Unit) = initTag(H1(), init) fun ul(init: UL.() -> Unit) = initTag(UL(), init) fun a(href: String, init: A.() -> Unit) { val a = initTag(A(), init) a.href = href } } class Body() : BodyTag("body") class UL() : BodyTag("ul") { fun li(init: LI.() -> Unit) = initTag(LI(), init) } class B() : BodyTag("b") class LI() : BodyTag("li") class P() : BodyTag("p") class H1() : BodyTag("h1") class A : BodyTag("a") { var href: String get() = attributes["href"]!! set(value) { attributes["href"] = value } } fun html(init: HTML.() -> Unit): HTML { val html = HTML() html.init() return html } ``` ``` HTML encoding with Kotlin

HTML encoding with Kotlin

this format can be used as an alternative markup to HTML

Kotlin

This is some mixed text. For more see the Kotlin project

some text

  • 1*2 = 2
  • 2*2 = 4
  • 3*2 = 6
  • 4*2 = 8
  • 5*2 = 10

``` ## How it works Assume that you need to implement a type-safe builder in Kotlin. First of all, define the model you want to build. In this case, you need to model HTML tags. It is easily done with a bunch of classes. For example, `HTML` is a class that describes the `` tag defining children like `` and ``. (See its declaration [below](#full-definition-of-the-com-example-html-package).) Now, let's recall why you can say something like this in the code: ```KOTLIN html { // ... } ``` `html` is actually a function call that takes a [lambda expression](lambdas.html) as an argument. This function is defined as follows: ```KOTLIN fun html(init: HTML.() -> Unit): HTML { val html = HTML() html.init() return html } ``` This function takes one parameter named `init`, which is itself a function. The type of the function is `HTML.() -> Unit`, which is a function type with receiver. This means that you need to pass an instance of type `HTML` (a receiver) to the function, and you can call members of that instance inside the function. The receiver can be accessed through the `this` keyword: ```KOTLIN html { this.head { ... } this.body { ... } } ``` (`head` and `body` are member functions of `HTML`.) Now, `this` can be omitted, as usual, and you get something that looks very much like a builder already: ```KOTLIN html { head { ... } body { ... } } ``` So, what does this call do? Let's look at the body of `html` function as defined above. It creates a new instance of `HTML`, then it initializes it by calling the function that is passed as an argument (in this example, this boils down to calling `head` and `body` on the `HTML` instance), and then it returns this instance. This is exactly what a builder should do. The `head` and `body` functions in the `HTML` class are defined similarly to `html`. The only difference is that they add the built instances to the `children` collection of the enclosing `HTML` instance: ```KOTLIN fun head(init: Head.() -> Unit): Head { val head = Head() head.init() children.add(head) return head } fun body(init: Body.() -> Unit): Body { val body = Body() body.init() children.add(body) return body } ``` Actually, these two functions do just the same thing, so you can have a generic version, `initTag`: ```KOTLIN protected fun initTag(tag: T, init: T.() -> Unit): T { tag.init() children.add(tag) return tag } ``` So, now your functions are very simple: ```KOTLIN fun head(init: Head.() -> Unit) = initTag(Head(), init) fun body(init: Body.() -> Unit) = initTag(Body(), init) ``` And you can use them to build `` and `` tags. One other thing to be discussed here is how you add text to tag bodies. In the example above, you say something like: ```KOTLIN html { head { title {+"XML encoding with Kotlin"} } // ... } ``` So basically, you just put a string inside a tag body, but there is this little `+` in front of it, so it is a function call that invokes a prefix `unaryPlus()` operation. That operation is actually defined by an extension function `unaryPlus()` that is a member of the `TagWithText` abstract class (a parent of `Title`): ```KOTLIN operator fun String.unaryPlus() { children.add(TextElement(this)) } ``` So, what the prefix `+` does here is wrapping a string into an instance of `TextElement` and adding it to the `children` collection, so that it becomes a proper part of the tag tree. All this is defined in a package `com.example.html` that is imported at the top of the builder example above. In the last section, you can read through the full definition of this package. ## Scope control: @DslMarker When using DSLs, one might have come across the problem that too many functions can be called in the context. You can call methods of every available [implicit receiver](lambdas.html#function-literals-with-receiver) inside a lambda and therefore get an inconsistent result, like the tag `head` inside another `head`: ```KOTLIN html { head { head {} // should be forbidden } // ... } ``` In this example, only members of the nearest implicit receiver `this@head` must be available; `head()` is a member of the outer receiver `this@html`, so it must be illegal to call it. To address this problem, there is a special mechanism to control receiver scope. To make the compiler start controlling scopes, you only have to annotate the types of all receivers used in the DSL with the same marker annotation. For instance, for HTML Builders you declare an annotation `@HtmlTagMarker`: ```KOTLIN @DslMarker @Target(AnnotationTarget.CLASS) annotation class HtmlTagMarker ``` An annotation class is called a DSL marker if it is annotated with the `@DslMarker` annotation. The `@Target` annotation restricts where `@HtmlTagMarker` can be applied. DSL markers only affect scope control when applied to: * Type declarations (`CLASS`): classes or interfaces used as DSL receivers. * Type usages (`TYPE`): receiver types in function type signatures. * Type aliases (`TYPEALIAS`): type aliases that expand to DSL receiver types. Applying a DSL marker to other targets (such as functions or properties) has no effect on scope control. Note: For more details on how DSL marker works, see the corresponding [KEEP document](https://github.com/Kotlin/KEEP/blob/main/notes/0005-dsl-marker.md). In our DSL, all the tag classes extend the same superclass `Tag`. It's enough to annotate only the superclass with `@HtmlTagMarker` and after that the Kotlin compiler will treat all the inherited classes as annotated: ```KOTLIN @HtmlTagMarker abstract class Tag(val name: String) { ... } ``` You don't have to annotate the `HTML` or `Head` classes with `@HtmlTagMarker` because their superclass is already annotated: ```KOTLIN class HTML() : Tag("html") { ... } class Head() : Tag("head") { ... } ``` After you've added this annotation, the Kotlin compiler knows which implicit receivers are part of the same DSL and allows to call members of the nearest receivers only: ```KOTLIN html { head { head { } // error: a member of outer receiver } // ... } ``` Note that it's still possible to call the members of the outer receiver, but to do that you have to specify this receiver explicitly: ```KOTLIN html { head { this@html.head { } // possible } // ... } ``` You can also apply the `@DslMarker` annotation directly to [function types](lambdas.html#function-types). This requires including `AnnotationTarget.TYPE` in the annotation targets: ```KOTLIN @DslMarker @Target(AnnotationTarget.CLASS, AnnotationTarget.TYPE) annotation class HtmlTagMarker ``` As a result, the `@DslMarker` annotation can be applied to function types, most commonly to lambdas with receivers. For example: ```KOTLIN fun html(init: @HtmlTagMarker HTML.() -> Unit): HTML { ... } fun HTML.head(init: @HtmlTagMarker Head.() -> Unit): Head { ... } fun Head.title(init: @HtmlTagMarker Title.() -> Unit): Title { ... } ``` When you call these functions, the `@DslMarker` annotation restricts access to outer receivers in the body of a lambda marked with it unless you specify them explicitly: ```KOTLIN html { head { title { // Access to title, head or other functions of outer receivers is restricted here. } } } ``` Only the nearest receiver's members and extensions are accessible within a lambda, preventing unintended interactions between nested scopes. When both a member of an implicit receiver and a declaration from a [context parameter](context-parameters.html) are in a scope with the same name, the compiler reports a warning because the implicit receiver is shadowed by the context parameter. To resolve this, use a `this` qualifier to explicitly call the receiver, or use `contextOf()` to call the context declaration: ```KOTLIN interface HtmlTag { fun setAttribute(name: String, value: String) } // Declares a top-level function with the same name, // which is available through a context parameter context(tag: HtmlTag) fun setAttribute(name: String, value: String) { tag.setAttribute(name, value) } fun test(head: HtmlTag, extraInfo: HtmlTag) { with(head) { // Introduces a context value of the same type in an inner scope context(extraInfo) { // Reports a warning: // Uses an implicit receiver shadowed by a context parameter setAttribute("user", "1234") // Calls the receiver's member explicitly this.setAttribute("user", "1234") // Calls the context declaration explicitly contextOf().setAttribute("user", "1234") } } } ``` ### Full definition of the com.example.html package This is how the package `com.example.html` is defined (only the elements used in the example above). It builds an HTML tree. It makes heavy use of [extension functions](extensions.html) and [lambdas with receiver](lambdas.html#function-literals-with-receiver). ```KOTLIN package com.example.html interface Element { fun render(builder: StringBuilder, indent: String) } class TextElement(val text: String) : Element { override fun render(builder: StringBuilder, indent: String) { builder.append("$indent$text\n") } } @DslMarker @Target(AnnotationTarget.CLASS, AnnotationTarget.TYPE) annotation class HtmlTagMarker @HtmlTagMarker abstract class Tag(val name: String) : Element { val children = arrayListOf() val attributes = hashMapOf() protected fun initTag(tag: T, init: T.() -> Unit): T { tag.init() children.add(tag) return tag } override fun render(builder: StringBuilder, indent: String) { builder.append("$indent<$name${renderAttributes()}>\n") for (c in children) { c.render(builder, indent + " ") } builder.append("$indent\n") } private fun renderAttributes(): String { val builder = StringBuilder() for ((attr, value) in attributes) { builder.append(" $attr=\"$value\"") } return builder.toString() } override fun toString(): String { val builder = StringBuilder() render(builder, "") return builder.toString() } } abstract class TagWithText(name: String) : Tag(name) { operator fun String.unaryPlus() { children.add(TextElement(this)) } } class HTML : TagWithText("html") { fun head(init: Head.() -> Unit) = initTag(Head(), init) fun body(init: Body.() -> Unit) = initTag(Body(), init) } class Head : TagWithText("head") { fun title(init: Title.() -> Unit) = initTag(Title(), init) } class Title : TagWithText("title") abstract class BodyTag(name: String) : TagWithText(name) { fun b(init: B.() -> Unit) = initTag(B(), init) fun p(init: P.() -> Unit) = initTag(P(), init) fun h1(init: H1.() -> Unit) = initTag(H1(), init) fun a(href: String, init: A.() -> Unit) { val a = initTag(A(), init) a.href = href } } class Body : BodyTag("body") class B : BodyTag("b") class P : BodyTag("p") class H1 : BodyTag("h1") class A : BodyTag("a") { var href: String get() = attributes["href"]!! set(value) { attributes["href"] = value } } fun html(init: HTML.() -> Unit): HTML { val html = HTML() html.init() return html } ``` # Using builders with builder type inference Kotlin supports builder type inference (or builder inference), which can come in useful when you are working with generic builders. It helps the compiler infer the type arguments of a builder call based on the type information about other calls inside its lambda argument. Consider this example of [buildMap()](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.collections/build-map.html) usage: ```KOTLIN fun addEntryToMap(baseMap: Map, additionalEntry: Pair?) { val myMap = buildMap { putAll(baseMap) if (additionalEntry != null) { put(additionalEntry.first, additionalEntry.second) } } } ``` There is not enough type information here to infer type arguments in a regular way, but builder inference can analyze the calls inside the lambda argument. Based on the type information about `putAll()` and `put()` calls, the compiler can automatically infer type arguments of the `buildMap()` call into `String` and `Number`. Builder inference allows to omit type arguments while using generic builders. ## Writing your own builders ### Requirements for enabling builder inference Note: Before Kotlin 1.7.0, enabling builder inference for a builder function required `-Xenable-builder-inference` compiler option. In 1.7.0 the option is enabled by default. To let builder inference work for your own builder, make sure its declaration has a builder lambda parameter of a function type with a receiver. There are also two requirements for the receiver type: 1. It should use the type arguments that builder inference is supposed to infer. For example: ```KOTLIN fun buildList(builder: MutableList.() -> Unit) { ... } ``` Note: Note that passing the type parameter's type directly like `fun myBuilder(builder: T.() -> Unit)` is not yet supported. 2. It should provide public members or extensions that contain the corresponding type parameters in their signature. For example: ```KOTLIN class ItemHolder { private val items = mutableListOf() fun addItem(x: T) { items.add(x) } fun getLastItem(): T? = items.lastOrNull() } fun ItemHolder.addAllItems(xs: List) { xs.forEach { addItem(it) } } fun itemHolderBuilder(builder: ItemHolder.() -> Unit): ItemHolder = ItemHolder().apply(builder) fun test(s: String) { val itemHolder1 = itemHolderBuilder { // Type of itemHolder1 is ItemHolder addItem(s) } val itemHolder2 = itemHolderBuilder { // Type of itemHolder2 is ItemHolder addAllItems(listOf(s)) } val itemHolder3 = itemHolderBuilder { // Type of itemHolder3 is ItemHolder val lastItem: String? = getLastItem() // ... } } ``` ### Supported features Builder inference supports: * Inferring several type arguments ```KOTLIN fun myBuilder(builder: MutableMap.() -> Unit): Map { ... } ``` * Inferring type arguments of several builder lambdas within one call including interdependent ones ```KOTLIN fun myBuilder( listBuilder: MutableList.() -> Unit, mapBuilder: MutableMap.() -> Unit ): Pair, Map> = mutableListOf().apply(listBuilder) to mutableMapOf().apply(mapBuilder) fun main() { val result = myBuilder( { add(1) }, { put("key", 2) } ) // result has Pair, Map> type } ``` * Inferring type arguments whose type parameters are lambda's parameter or return types ```KOTLIN fun myBuilder1( mapBuilder: MutableMap.() -> K ): Map = mutableMapOf().apply { mapBuilder() } fun myBuilder2( mapBuilder: MutableMap.(K) -> Unit ): Map = mutableMapOf().apply { mapBuilder(2 as K) } fun main() { // result1 has the Map type inferred val result1 = myBuilder1 { put(1L, "value") 2 } val result2 = myBuilder2 { put(1, "value 1") // You can use `it` as "postponed type variable" type // See the details in the section below put(it, "value 2") } } ``` ## How builder inference works ### Postponed type variables Builder inference works in terms of postponed type variables, which appear inside the builder lambda during builder inference analysis. A postponed type variable is a type argument's type, which is in the process of inferring. The compiler uses it to collect type information about the type argument. Consider the example with [buildList()](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.collections/build-list.html): ```KOTLIN val result = buildList { val x = get(0) } ``` Here `x` has a type of postponed type variable: the `get()` call returns a value of type `E`, but `E` itself is not yet fixed. At this moment, a concrete type for `E` is unknown. When a value of a postponed type variable gets associated with a concrete type, builder inference collects this information to infer the resulting type of the corresponding type argument at the end of the builder inference analysis. For example: ```KOTLIN val result = buildList { val x = get(0) val y: String = x } // result has the List type inferred ``` After the postponed type variable gets assigned to a variable of the `String` type, builder inference gets the information that `x` is a subtype of `String`. This assignment is the last statement in the builder lambda, so the builder inference analysis ends with the result of inferring the type argument `E` into `String`. Note that you can always call `equals()`, `hashCode()`, and `toString()` functions with a postponed type variable as a receiver. ### Contributing to builder inference results Builder inference can collect different varieties of type information that contribute to the analysis result. It considers: * Calling methods on a lambda's receiver that use the type parameter's type ```KOTLIN val result = buildList { // Type argument is inferred into String based on the passed "value" argument add("value") } // result has the List type inferred ``` * Specifying the expected type for calls that return the type parameter's type ```KOTLIN val result = buildList { // Type argument is inferred into Float based on the expected type val x: Float = get(0) } // result has the List type ``` ```KOTLIN class Foo { val items = mutableListOf() } fun myBuilder(builder: Foo.() -> Unit): Foo = Foo().apply(builder) fun main() { val result = myBuilder { val x: List = items // ... } // result has the Foo type } ``` * Passing postponed type variables' types into methods that expect concrete types ```KOTLIN fun takeMyLong(x: Long) { ... } fun String.isMoreThan3() = length > 3 fun takeListOfStrings(x: List) { ... } fun main() { val result1 = buildList { val x = get(0) takeMyLong(x) } // result1 has the List type val result2 = buildList { val x = get(0) val isLong = x.isMoreThan3() // ... } // result2 has the List type val result3 = buildList { takeListOfStrings(this) } // result3 has the List type } ``` * Taking a callable reference to the lambda receiver's member ```KOTLIN fun main() { val result = buildList { val x: KFunction1 = ::get } // result has the List type } ``` ```KOTLIN fun takeFunction(x: KFunction1) { ... } fun main() { val result = buildList { takeFunction(::get) } // result has the List type } ``` At the end of the analysis, builder inference considers all collected type information and tries to merge it into the resulting type. See the example. ```KOTLIN val result = buildList { // Inferring postponed type variable E // Considering E is Number or a subtype of Number val n: Number? = getOrNull(0) // Considering E is Int or a supertype of Int add(1) // E gets inferred into Int } // result has the List type ``` The resulting type is the most specific type that corresponds to the type information collected during the analysis. If the given type information is contradictory and cannot be merged, the compiler reports an error. Note that the Kotlin compiler uses builder inference only if regular type inference cannot infer a type argument. This means you can contribute type information outside a builder lambda, and then builder inference analysis is not required. Consider the example: ```KOTLIN fun someMap() = mutableMapOf() fun MutableMap.f(x: MutableMap) { ... } fun main() { val x: Map = buildMap { put("", "") f(someMap()) // Type mismatch (required String, found CharSequence) } } ``` Here a type mismatch appears because the expected type of the map is specified outside the builder lambda. The compiler analyzes all the statements inside with the fixed receiver type `Map`. # Context parameters Tip: Context parameters replace an older experimental feature called [context receivers](whatsnew1620.html#prototype-of-context-receivers-for-kotlin-jvm). You can find their main differences in the [design document for context parameters](https://github.com/Kotlin/KEEP/blob/master/proposals/context-parameters.md#summary-of-changes-from-the-previous-proposal). To migrate from context receivers to context parameters, you can use assisted support in IntelliJ IDEA, as described in the related [blog post](https://blog.jetbrains.com/kotlin/2025/04/update-on-context-parameters/). Context parameters allow functions and properties to declare dependencies that are implicitly available in the surrounding context. With context parameters, you don't need to manually pass around values, such as services or dependencies, that are shared and rarely change across sets of function calls. To declare context parameters for properties and functions, use the `context` keyword followed by a list of parameters, with each parameter declared as `name: Type`. Here is an example with a dependency on the `UserService` interface: ```KOTLIN // UserService defines the dependency required in context interface UserService { fun log(message: String) fun findUserById(id: Int): String } // Declares a function with a context parameter context(users: UserService) fun outputMessage(message: String) { // Uses log from the context users.log("Log: $message") } // Declares a property with a context parameter context(users: UserService) val firstUser: String // Uses findUserById from the context get() = users.findUserById(1) fun main() { val users = object : UserService { override fun log(message: String) { println(message) } override fun findUserById(id: Int): String { return "User $id" } } context(users) { outputMessage("Looking up the first user") println(firstUser) // User 1 } } ``` You can use `_` as a context parameter name when you don't need to refer to the parameter directly. An anonymous context parameter can still satisfy the context parameters required by called functions, but you can't access it by name. To access its value explicitly, use `contextOf()`: ```KOTLIN // Uses "_" as context parameter name context(_: UserService) fun logWelcome() { // The anonymous parameter satisfies the UserService context parameter // required by outputMessage() outputMessage("Welcome!") // Retrieves the UserService value explicitly contextOf().log("Hi!") } ``` ## Context parameters resolution Kotlin resolves context parameters at the call site by searching for matching context values in the current scope. Kotlin matches them by their type. If multiple compatible values exist at the same scope level, the compiler reports an ambiguity: ```KOTLIN // UserService defines the dependency required in context interface UserService { fun log(message: String) } // Declares a function with a context parameter context(users: UserService) fun outputMessage(message: String) { users.log("Log: $message") } fun main() { // Implements UserService val serviceA = object : UserService { override fun log(message: String) = println("A: $message") } // Implements UserService val serviceB = object : UserService { override fun log(message: String) = println("B: $message") } // Both serviceA and serviceB match the expected UserService type at the call site context(serviceA, serviceB) { // This results in an ambiguity error outputMessage("This will not compile") } } ``` ### Pass context arguments explicitly When overloads differ only by context parameters, a call can become ambiguous if multiple matching context values are available. To resolve the ambiguity, pass an explicit context argument at the call site: ```KOTLIN class EmailSender class SmsSender context(emailSender: EmailSender) fun sendNotification() { println("Sent email notification") } context(smsSender: SmsSender) fun sendNotification() { println("Sent SMS notification") } context(defaultEmailSender: EmailSender, defaultSmsSender: SmsSender) fun notifyUser() { // Selects the overload with the EmailSender context parameter sendNotification(emailSender = defaultEmailSender) // Selects the overload with the SmsSender context parameter sendNotification(smsSender = defaultSmsSender) } ``` You can also use explicit context arguments to reduce nesting in some function calls: * For a single call, use explicit context arguments to make the call easier to read. * If multiple calls use the same context arguments, use the `context()` function. This feature is [Experimental](components-stability.html#stability-levels-explained). To opt in, add the following compiler option to your build file: Gradle: ```KOTLIN kotlin { compilerOptions { freeCompilerArgs.add("-Xexplicit-context-arguments") } } ``` Maven: ```XML org.jetbrains.kotlin kotlin-maven-plugin -Xexplicit-context-arguments ``` ## Restrictions Context parameters are in continuous improvement, and some of the current restrictions include: * Constructors can't declare context parameters. * Properties with context parameters can't have backing fields or initializers. * Properties with context parameters can't use delegation. Despite these restrictions, context parameters simplify managing dependencies through simplified dependency injection, improved DSL design, and scoped operations. # Inline functions Using [higher-order functions](lambdas.html) imposes certain runtime penalties: each function is an object, and it captures a closure. A closure is a scope of variables that can be accessed in the body of the function. Memory allocations (both for function objects and classes) and virtual calls introduce runtime overhead. But it appears that in many cases this kind of overhead can be eliminated by inlining the lambda expressions. The functions shown below are good examples of this situation. The `lock()` function could be easily inlined at call-sites. Consider the following case: ```KOTLIN lock(l) { foo() } ``` Instead of creating a function object for the parameter and generating a call, the compiler could emit the following code: ```KOTLIN l.lock() try { foo() } finally { l.unlock() } ``` To make the compiler do this, mark the `lock()` function with the `inline` modifier: ```KOTLIN inline fun lock(lock: Lock, body: () -> T): T { ... } ``` The `inline` modifier affects both the function itself and the lambdas passed to it: all of those will be inlined into the call site. Inlining may cause the generated code to grow. However, if you do it in a reasonable way (avoiding inlining large functions), it will pay off in performance, especially at "megamorphic" call-sites inside loops. ## noinline If you don't want all of the lambdas passed to an inline function to be inlined, mark some of your function parameters with the `noinline` modifier: ```KOTLIN inline fun foo(inlined: () -> Unit, noinline notInlined: () -> Unit) { ... } ``` Inlinable lambdas can only be called inside inline functions or passed as inlinable arguments. `noinline` lambdas, however, can be manipulated in any way you like, including being stored in fields or passed around. Note: If an inline function has no inlinable function parameters and no [reified type parameters](#reified-type-parameters), the compiler will issue a warning, since inlining such functions is very unlikely to be beneficial (you can use the `@Suppress("NOTHING_TO_INLINE")` annotation to suppress the warning if you are sure the inlining is needed). ## Non-local jump expressions ### Returns In Kotlin, you can only use a normal, unqualified `return` to exit a named function or an anonymous function. To exit a lambda, use a [label](returns.html#return-to-labels). A bare `return` is forbidden inside a lambda because a lambda cannot make the enclosing function `return`: ```KOTLIN fun ordinaryFunction(block: () -> Unit) { println("hi!") } //sampleStart fun foo() { ordinaryFunction { return // ERROR: cannot make `foo` return here } } //sampleEnd fun main() { foo() } ``` But if the function the lambda is passed to is inlined, the return can be inlined, as well. So it is allowed: ```KOTLIN inline fun inlined(block: () -> Unit) { println("hi!") } //sampleStart fun foo() { inlined { return // OK: the lambda is inlined } } //sampleEnd fun main() { foo() } ``` Such returns (located in a lambda, but exiting the enclosing function) are called non-local returns. This sort of construct usually occurs in loops, which inline functions often enclose: ```KOTLIN fun hasZeros(ints: List): Boolean { ints.forEach { if (it == 0) return true // returns from hasZeros } return false } ``` Note that some inline functions may call the lambdas passed to them as parameters not directly from the function body, but from another execution context, such as a local object or a nested function. In such cases, non-local control flow is also not allowed in the lambdas. To indicate that the lambda parameter of the inline function cannot use non-local returns, mark the lambda parameter with the `crossinline` modifier: ```KOTLIN inline fun f(crossinline body: () -> Unit) { val f = object: Runnable { override fun run() = body() } // ... } ``` ### Break and continue Similar to non-local `return`, you can apply `break` and `continue` [jump expressions](returns.html) in lambdas passed as arguments to an inline function that encloses a loop: ```KOTLIN fun processList(elements: List): Boolean { for (element in elements) { val variable = element.nullableMethod() ?: run { log.warning("Element is null or invalid, continuing...") continue } if (variable == 0) return true } return false } ``` ## Reified type parameters Sometimes you need to access a type passed as a parameter: ```KOTLIN fun TreeNode.findParentOfType(clazz: Class): T? { var p = parent while (p != null && !clazz.isInstance(p)) { p = p.parent } @Suppress("UNCHECKED_CAST") return p as T? } ``` Here, you walk up a tree and use reflection to check whether a node has a certain type. It's all fine, but the call site is not very pretty: ```KOTLIN treeNode.findParentOfType(MyTreeNode::class.java) ``` A better solution would be to simply pass a type to this function. You can call it as follows: ```KOTLIN treeNode.findParentOfType() ``` To enable this, inline functions support reified type parameters, so you can write something like this: ```KOTLIN inline fun TreeNode.findParentOfType(): T? { var p = parent while (p != null && p !is T) { p = p.parent } return p as T? } ``` The code above qualifies the type parameter with the `reified` modifier to make it accessible inside the function, almost as if it were a normal class. Since the function is inlined, no reflection is needed and normal operators like `!is` and `as` are now available for you to use. Also, you can call the function as shown above: `myTree.findParentOfType()`. Though reflection may not be needed in many cases, you can still use it with a reified type parameter: ```KOTLIN inline fun membersOf() = T::class.members fun main(s: Array) { println(membersOf().joinToString("\n")) } ``` Normal functions (not marked as inline) cannot have reified parameters. A type that does not have a run-time representation (for example, a non-reified type parameter or a fictitious type like `Nothing`) cannot be used as an argument for a reified type parameter. ## Inline properties The `inline` modifier can be used on accessors of properties that don't have [backing fields](properties.html#backing-fields). You can annotate individual property accessors: ```KOTLIN val foo: Foo inline get() = Foo() var bar: Bar get() = ... inline set(v) { ... } ``` You can also annotate an entire property, which marks both of its accessors as `inline`: ```KOTLIN inline var bar: Bar get() = ... set(v) { ... } ``` At the call site, inline accessors are inlined as regular inline functions. ## Restrictions for public API inline functions When an inline function is `public` or `protected` but is not a part of a `private` or `internal` declaration, it is considered a [module](visibility-modifiers.html#modules)'s public API. It can be called in other modules and is inlined at such call sites as well. This imposes certain risks of binary incompatibility caused by changes in the module that declares an inline function in case the calling module is not re-compiled after the change. To eliminate the risk of such incompatibility being introduced by a change in a non-public API of a module, public API inline functions are not allowed to use non-public-API declarations, i.e. `private` and `internal` declarations and their parts, in their bodies. An `internal` declaration can be annotated with `@PublishedApi`, which allows its use in public API inline functions. When an `internal` inline function is marked as `@PublishedApi`, its body is checked too, as if it were public. # Operator overloading Kotlin allows you to provide custom implementations for the predefined set of operators on types. These operators have predefined symbolic representation (like `+` or `*`) and precedence. To implement an operator, provide a [member function](functions.html#member-functions) or an [extension function](extensions.html) with a specific name for the corresponding type. This type becomes the left-hand side type for binary operations and the argument type for the unary ones. To overload an operator, mark the corresponding function with the `operator` modifier: ```KOTLIN interface IndexedContainer { operator fun get(index: Int) } ``` When [overriding](inheritance.html#overriding-methods) your operator overloads, you can omit `operator`: ```KOTLIN class OrdersList: IndexedContainer { override fun get(index: Int) { /*...*/ } } ``` ## Unary operations ### Unary prefix operators | Expression |Translated to | ----------------------------- | `+a` |`a.unaryPlus()` | | `-a` |`a.unaryMinus()` | | `!a` |`a.not()` | This table says that when the compiler processes, for example, an expression `+a`, it performs the following steps: * Determines the type of `a`, let it be `T`. * Looks up a function `unaryPlus()` with the `operator` modifier and no parameters for the receiver `T`, that means a member function or an extension function. * If the function is absent or ambiguous, it is a compilation error. * If the function is present and its return type is `R`, the expression `+a` has type `R`. Note: These operations, as well as all the others, are optimized for [basic types](types-overview.html) and do not introduce overhead of function calls for them. As an example, here's how you can overload the unary minus operator: ```KOTLIN data class Point(val x: Int, val y: Int) operator fun Point.unaryMinus() = Point(-x, -y) val point = Point(10, 20) fun main() { println(-point) // prints "Point(x=-10, y=-20)" } ``` ### Increments and decrements | Expression |Translated to | ----------------------------- | `a++` |`a.inc()` + see below | | `a--` |`a.dec()` + see below | The `inc()` and `dec()` functions must return a value, which will be assigned to the variable on which the `++` or `--` operation was used. They shouldn't mutate the object on which the `inc` or `dec` was invoked. The compiler performs the following steps for resolution of an operator in the postfix form, for example `a++`: * Determines the type of `a`, let it be `T`. * Looks up a function `inc()` with the `operator` modifier and no parameters, applicable to the receiver of type `T`. * Checks that the return type of the function is a subtype of `T`. The effect of computing the expression is: * Store the initial value of `a` to a temporary storage `a0`. * Assign the result of `a0.inc()` to `a`. * Return `a0` as the result of the expression. For `a--` the steps are completely analogous. For the prefix forms `++a` and `--a` resolution works the same way, and the effect is: * Assign the result of `a.inc()` to `a`. * Return the new value of `a` as a result of the expression. ## Binary operations ### Arithmetic operators | Expression |Translated to | ----------------------------- | `a + b` |`a.plus(b)` | | `a - b` |`a.minus(b)` | | `a * b` |`a.times(b)` | | `a / b` |`a.div(b)` | | `a % b` |`a.rem(b)` | | `a..b` |`a.rangeTo(b)` | | `a.. b` |`a.compareTo(b) > 0` | | `a < b` |`a.compareTo(b) < 0` | | `a >= b` |`a.compareTo(b) >= 0` | | `a <= b` |`a.compareTo(b) <= 0` | All comparisons are translated into calls to `compareTo`, that is required to return `Int`. ### Property delegation operators `provideDelegate`, `getValue` and `setValue` operator functions are described in [Delegated properties](delegated-properties.html). ## Infix calls for named functions You can simulate custom infix operations by using [infix function calls](functions.html#infix-notation). # Unused return value checker Note: This feature is planned to be stabilized and improved in future Kotlin releases. We would appreciate your feedback in our issue tracker [YouTrack](https://youtrack.jetbrains.com/issue/KT-12719). For more information, see the related [KEEP proposal](https://github.com/Kotlin/KEEP/blob/main/proposals/KEEP-0412-unused-return-value-checker.md). The unused return value checker allows you to detect ignored results. These are values returned from expressions that produce something other than `Unit`, `Nothing`, or `Nothing?` and aren't: * Stored in a variable or property. * Returned or thrown. * Passed as an argument to another function. * Used as a receiver in a call or safe call. * Checked in a condition such as `if`, `when`, or `while`. * Used as the last statement of a lambda. The checker doesn't report ignored results for increment operations like `++` and `--`, or for boolean shortcuts where the right-hand side exits the current function, for example, `condition || return`. You can use the unused return value checker to catch bugs where a function call produces a meaningful result, but the result is silently dropped. This helps prevent unexpected behavior and makes such issues easier to track down. Here's an example where a string is created but never used, so the checker reports it as an ignored result: ```KOTLIN fun formatGreeting(name: String): String { if (name.isBlank()) return "Hello, anonymous user!" if (!name.contains(' ')) { // The checker reports a warning that this result is ignored: // "Unused return value of 'plus'." "Hello, " + name.replaceFirstChar(Char::titlecase) + "!" } val (first, last) = name.split(' ') return "Hello, $first! Or should I call you Dr. $last?" } ``` ## Configure the unused return value checker You can control how the compiler reports ignored results with the `-Xreturn-value-checker` compiler option. It has the following modes: * `disable` disables the unused return value checker (default). * `check` enables the checker, and reports warnings for ignored results from [marked functions](#mark-functions-to-check-ignored-results). * `full` enables the checker, treats all functions in your project as [marked](#mark-functions-to-check-ignored-results), and reports warnings for ignored results. Note: All marked functions are propagated as such, and ignored results are reported if the checker is enabled in projects that use your code as a dependency. To use the unused return value checker in your project, add the compiler option to your build configuration file: Gradle: ```KOTLIN // build.gradle(.kts) kotlin { compilerOptions { freeCompilerArgs.add("-Xreturn-value-checker=check") } } ``` Maven: ```XML org.jetbrains.kotlin .. -Xreturn-value-checker=check ``` ## Mark functions to check ignored results When you set [the -Xreturn-value-checker compiler option](#configure-the-unused-return-value-checker) to `check`, the checker reports ignored results only from expressions that are marked, like most functions in the Kotlin standard library. To mark your own code, use the [@MustUseReturnValues](https://kotlinlang.org/api/core/kotlin-stdlib/kotlin/-must-use-return-values/) annotation. You can apply it to a file, class, or function depending on the scope you want the checker to cover. For example, you can mark an entire file: ```KOTLIN // Marks all functions and classes in this file so the checker reports unused return values @file:MustUseReturnValues package my.project fun someFunction(): String ``` Or a specific class: ```KOTLIN // Marks all functions in this class so the checker reports unused return values @MustUseReturnValues class Greeter { fun greet(name: String): String = "Hello, $name" } fun someFunction(): Int = ... ``` Note: You can apply the checker to your entire project by setting the `-Xreturn-value-checker` compiler option to `full`. With this option, you don't have to annotate your code with `@MustUseReturnValues`. ## Suppress reports for ignored results You can suppress reports on specific functions by annotating them with [@IgnorableReturnValue](https://kotlinlang.org/api/core/kotlin-stdlib/kotlin/-ignorable-return-value/). Annotate functions where ignoring the result is common and expected, such as `MutableList.add`: ```KOTLIN @IgnorableReturnValue fun MutableList.addAndIgnoreResult(element: T): Boolean { return add(element) } ``` You can suppress a warning without annotating the function itself. To do this, assign the result to a special unnamed variable with an underscore syntax (`_`): ```KOTLIN // Non-ignorable function fun computeValue(): Int = 42 fun main() { // Reports a warning: result is ignored computeValue() // Suppresses the warning only at this call site with a special unused variable val _ = computeValue() } ``` ### Ignored results in function overrides When you override a function, the override inherits the reporting rules defined by the annotations on the base declaration. This also applies when the base declaration is part of the Kotlin standard library or of other library dependencies, so the checker reports ignored results for overrides of functions like `Any.hashCode()`. Additionally, you can't override a function marked with `@IgnorableReturnValue` with another function that [requires its return value to be used](#mark-functions-to-check-ignored-results). However, you can mark an override with `@IgnorableReturnValue` in a class or interface annotated with `@MustUseReturnValues` when its result can be safely ignored: ```KOTLIN @MustUseReturnValues interface Greeter { fun greet(name: String): String } object SilentGreeter : Greeter { @IgnorableReturnValue override fun greet(name: String): String = "" } fun check(g: Greeter) { // Reports a warning: unused return value g.greet("John") // No warning SilentGreeter.greet("John") } ``` ## Check for unused results in higher-order functions Some higher-order functions, such as the `let` scope function, return the result of a lambda. To check for unused lambda results of higher-order functions, add the [Experimental](components-stability.html#stability-levels-explained) `returnsResultOf()` contract to the function's contract. Warning: Kotlin contracts are Experimental. To opt in, add the `@OptIn(ExperimentalContracts::class)` annotation when declaring a function with a contract. Here's an example: ```KOTLIN import kotlin.contracts.ExperimentalContracts import kotlin.contracts.contract @OptIn(ExperimentalContracts::class) inline fun T.customLet(block: (T) -> R): R { contract { returnsResultOf(block) } return block(this) } ``` You can then use a function with this contract, such as `.customLet()`, to check if the lambda result is used: ```KOTLIN fun handleNullablePackageName(packageName: String?, builder: StringBuilder) { // The checker doesn't report a warning because the return value of append() can be ignored packageName?.customLet { builder.append(it) } // The checker reports a warning because the returned string is unused packageName?.customLet { "kotlin.$it" } } ``` Warning: The `returnsResultOf()` contract requires a separate compiler option to opt in. Be aware that using it produces pre-release binaries that Kotlin compiler versions earlier than 2.4.0 can't read. To opt in for your project, add the following compiler option to your build file: Gradle: ```KOTLIN // build.gradle(.kts) kotlin { compilerOptions { freeCompilerArgs.add("-Xallow-returns-result-of") } } ``` Maven: ```XML org.jetbrains.kotlin kotlin-maven-plugin -Xallow-returns-result-of ``` ## Interoperability with Java annotations Some Java libraries use similar mechanisms with different annotations. The unused return value checker treats the following annotations as equivalent to using `@MustUseReturnValues`: * [com.google.errorprone.annotations.CheckReturnValue](https://errorprone.info/api/latest/com/google/errorprone/annotations/CheckReturnValue.html) * [edu.umd.cs.findbugs.annotations.CheckReturnValue](https://findbugs.sourceforge.net/api/edu/umd/cs/findbugs/annotations/CheckReturnValue.html) * [org.jetbrains.annotations.CheckReturnValue](https://javadoc.io/doc/org.jetbrains/annotations/latest/org/jetbrains/annotations/CheckReturnValue.html) * [org.springframework.lang.CheckReturnValue](https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/lang/CheckReturnValue.html) * [org.jooq.CheckReturnValue](https://www.jooq.org/javadoc/latest/org.jooq/org/jooq/CheckReturnValue.html) It also treats [com.google.errorprone.annotations.CanIgnoreReturnValue](https://errorprone.info/api/latest/com/google/errorprone/annotations/CanIgnoreReturnValue.html) as equivalent to using `@IgnorableReturnValue`. # Classes Tip: Before creating classes, consider using a [data class](data-classes.html) if the purpose is to store data. Alternatively, think about extending an existing class with an [extension](extensions.html), rather than creating a new one from scratch. Like other object-oriented languages, Kotlin uses classes to encapsulate data (properties) and behavior (functions) for reusable, structured code. Classes are blueprints or templates for objects, which you create via [constructors](#constructors-and-initializer-blocks). When you [create an instance of a class](#creating-instances), you are creating a concrete object based on that blueprint. Kotlin offers concise syntax for declaring classes. To declare a class, use the `class` keyword followed by the class name: ```KOTLIN class Person { /*...*/ } ``` The class declaration consists of: * Class header, including but not limited to: * `class` keyword * Class name * Type parameters (if any) * [Primary constructor](#primary-constructor) (optional) * Class body (optional), surrounded by curly braces `{}`, and including class members such as: * [Secondary constructors](#secondary-constructors) * [Initializer blocks](#initializer-blocks) * [Functions](functions.html) * [Properties](properties.html) * [Nested and inner classes](nested-classes.html) * [Object declarations](object-declarations.html) You can keep both the class header and body to a bare minimum. If the class doesn't have a body, you can omit the curly braces `{}`: ```KOTLIN // Class with primary constructor, but without a body class Person(val name: String, var age: Int) ``` Here's an example that declares a class with a header and body, then [creates an instance](#creating-instances) from it: ```KOTLIN // Person class with a primary constructor // that initializes the name property class Person(val name: String) { // Class body with age property var age: Int = 0 } fun main() { // Creates an instance of the Person class by calling the constructor val person = Person("Alice") // Accesses the instance's properties println(person.name) // Alice println(person.age) // 0 } ``` ## Creating instances An instance is created when you use the class as a blueprint to build a real object to work with in your program. To create an instance of a class, use the class name followed by parentheses `()`, similar to calling a [function](functions.html): ```KOTLIN // Creates an instance of the Person class val anonymousUser = Person() ``` In Kotlin, you can create instances: * Without arguments (`Person()`): creates an instance using the default values, if they are declared in the class. * With arguments (`Person(value)`): creates an instance by passing specific values. You can assign the created instance to a mutable (`var`) or read-only (`val`) [variable](basic-syntax.html#variables): ```KOTLIN // Creates an instance using the default value // and assigns it to a mutable variable var anonymousUser = Person() // Creates an instance by passing a specific value // and assigns it to a read-only variable val namedUser = Person("Joe") ``` It's possible to create instances wherever you need them, inside the [main() function](basic-syntax.html#program-entry-point), within other functions, or inside another class. Additionally, you can create instances inside another function and call that function from `main()`. The following code declares a `Person` class with a property for storing a name. It also demonstrates how to create an instance with both the default constructor's value and a specific value: ```KOTLIN // Class header with a primary constructor // that initializes name with a default value class Person(val name: String = "Sebastian") fun main() { // Creates an instance using the default constructor's value val anonymousUser = Person() // Creates an instance by passing a specific value val namedUser = Person("Joe") // Accesses the instances' name property println(anonymousUser.name) // Sebastian println(namedUser.name) // Joe } ``` Note: In Kotlin, unlike other object-oriented programming languages, there is no need for the `new` keyword when creating class instances. For information about creating instances of nested, inner, and anonymous inner classes, see the [Nested classes](nested-classes.html) section. ## Constructors and initializer blocks When you create a class instance, you call one of its constructors. A class in Kotlin can have a [primary constructor](#primary-constructor) and one or more [secondary constructors](#secondary-constructors). The primary constructor is the main way to initialize a class. You declare it in the class header. A secondary constructor provides additional initialization logic. You declare it in the class body. Both primary and secondary constructors are optional, but a class must have at least one constructor. ### Primary constructor The primary constructor sets up the initial state of an instance when [it's created](#creating-instances). To declare a primary constructor, place it in the class header after the class name: ```KOTLIN class Person constructor(name: String) { /*...*/ } ``` If the primary constructor doesn't have any [annotations](annotations.html) or [visibility modifiers](visibility-modifiers.html#constructors), you can omit the `constructor` keyword: ```KOTLIN class Person(name: String) { /*...*/ } ``` The primary constructor can declare parameters as properties. Use the `val` keyword before the argument name to declare a read-only property and the `var` keyword for a mutable property: ```KOTLIN class Person(val name: String, var age: Int) { /*...*/ } ``` These constructor parameter properties are stored as part of the instance and are accessible from outside the class. It's also possible to declare primary constructor parameters that are not properties. These parameters don't have `val` or `var` in front of them, so they are not stored in the instance and are available only within the class body: ```KOTLIN // Primary constructor parameter that is also a property class PersonWithProperty(val name: String) { fun greet() { println("Hello, $name") } } // Primary constructor parameter only (not stored as a property) class PersonWithAssignment(name: String) { // Must be assigned to a property to be usable later val displayName: String = name fun greet() { println("Hello, $displayName") } } ``` Properties declared in the primary constructor are accessible by [member functions](functions.html) of the class: ```KOTLIN // Class with a primary constructor declaring properties class Person(val name: String, var age: Int) { // Member function accessing class properties fun introduce(): String { return "Hi, I'm $name and I'm $age years old." } } ``` You can also assign default values to properties in the primary constructor: ```KOTLIN class Person(val name: String = "John", var age: Int = 30) { /*...*/ } ``` If no value is passed to the constructor during [instance creation](#creating-instances), properties use their default value: ```KOTLIN // Class with a primary constructor // including default values for name and age class Person(val name: String = "John", var age: Int = 30) fun main() { // Creates an instance using default values val person = Person() println("Name: ${person.name}, Age: ${person.age}") // Name: John, Age: 30 } ``` You can use the primary constructor parameters to initialize additional class properties directly in the class body: ```KOTLIN // Class with a primary constructor // including default values for name and age class Person( val name: String = "John", var age: Int = 30 ) { // Initializes the description property // from the primary constructor parameters val description: String = "Name: $name, Age: $age" } fun main() { // Creates an instance of the Person class val person = Person() // Accesses the description property println(person.description) // Name: John, Age: 30 } ``` As with functions, you can use [trailing commas](coding-conventions.html#trailing-commas) in constructor declarations: ```KOTLIN class Person( val name: String, val lastName: String, var age: Int, ) { /*...*/ } ``` ### Initializer blocks The primary constructor initializes the class and sets its properties. In most cases, you can handle this with simple code. If you need to perform more complex operations during [instance creation](#creating-instances), place that logic in initializer blocks inside the class body. These blocks run when the primary constructor executes. Declare initializer blocks with the `init` keyword followed by curly braces `{}`. Write within the curly braces any code that you want to run during initialization: ```KOTLIN // Class with a primary constructor that initializes name and age class Person(val name: String, var age: Int) { init { // Initializer block runs when an instance is created println("Person created: $name, age $age.") } } fun main() { // Creates an instance of the Person class Person("John", 30) // Person created: John, age 30. } ``` Add as many initializer blocks (`init {}`) as you need. They run in the order in which they appear in the class body, along with property initializers: ```KOTLIN //sampleStart // Class with a primary constructor that initializes name and age class Person(val name: String, var age: Int) { // First initializer block init { // Runs first when an instance is created println("Person created: $name, age $age.") } // Second initializer block init { // Runs after the first initializer block if (age < 18) { println("$name is a minor.") } else { println("$name is an adult.") } } } fun main() { // Creates an instance of the Person class Person("John", 30) // Person created: John, age 30. // John is an adult. } //sampleEnd ``` You can use primary constructor parameters in initializer blocks. For example, in the code above, the first and second initializers use the `name` and `age` parameters from the primary constructor. A common use case for `init` blocks is data validation. For example, by calling the [require function](https://kotlinlang.org/api/core/kotlin-stdlib/kotlin/require.html): ```KOTLIN class Person(val age: Int) { init { require(age > 0) { "age must be positive" } } } ``` ### Secondary constructors In Kotlin, secondary constructors are additional constructors that a class can have beyond its primary constructor. Secondary constructors are useful when you need multiple ways to initialize a class or for [Java interoperability](java-to-kotlin-interop.html). To declare a secondary constructor, use the `constructor` keyword inside the class body with the constructor parameters within parentheses `()`. Add the constructor logic within curly braces `{}`: ```KOTLIN // Class header with a primary constructor that initializes name and age class Person(val name: String, var age: Int) { // Secondary constructor that takes age as a // String and converts it to an Int constructor(name: String, age: String) : this(name, age.toIntOrNull() ?: 0) { println("$name created with converted age: ${this.age}") } } fun main() { // Uses the secondary constructor with age as a String Person("Bob", "8") // Bob created with converted age: 8 } ``` Tip: The expression `age.toIntOrNull() ?: 0` uses the Elvis operator. For more information, see [Null safety](null-safety.html#elvis-operator). In the code above, the secondary constructor delegates to the primary constructor via the `this` keyword, passing `name` and the `age` value converted to an integer. In Kotlin, secondary constructors must delegate to the primary constructor. This delegation ensures that all primary constructor initialization logic is executed before any secondary constructor logic runs. Constructor delegation can be: * Direct, where the secondary constructor calls the primary constructor immediately. * Indirect, where one secondary constructor calls another, which in turn delegates to the primary constructor. Here's an example demonstrating how direct and indirect delegation works: ```KOTLIN // Class header with a primary constructor that initializes name and age class Person( val name: String, var age: Int ) { // Secondary constructor with direct delegation // to the primary constructor constructor(name: String) : this(name, 0) { println("Person created with default age: $age and name: $name.") } // Secondary constructor with indirect delegation: // this("Bob") -> constructor(name: String) -> primary constructor constructor() : this("Bob") { println("New person created with default age: $age and name: $name.") } } fun main() { // Creates an instance based on the direct delegation Person("Alice") // Person created with default age: 0 and name: Alice. // Creates an instance based on the indirect delegation Person() // Person created with default age: 0 and name: Bob. // New person created with default age: 0 and name: Bob. } ``` In classes with initializer blocks (`init {}`), the code within these blocks becomes part of the primary constructor. Given that secondary constructors delegate to the primary constructor first, all initializer blocks and property initializers run before the body of the secondary constructor. Even if the class has no primary constructor, the delegation still happens implicitly: ```KOTLIN // Class header with no primary constructor class Person { // Initializer block runs when an instance is created init { // Runs before the secondary constructor println("1. First initializer block runs") } // Secondary constructor that takes an integer parameter constructor(i: Int) { // Runs after the initializer block println("2. Person $i is created") } } fun main() { // Creates an instance of the Person class Person(1) // 1. First initializer block runs // 2. Person 1 created } ``` ### Classes without constructors Classes that don't declare any constructors (primary or secondary) have an implicit primary constructor with no parameters: ```KOTLIN // Class with no explicit constructors class Person { // No primary or secondary constructors declared } fun main() { // Creates an instance of the Person class // using the implicit primary constructor val person = Person() } ``` The visibility of this implicit primary constructor is public, meaning it can be accessed from anywhere. If you don't want your class to have a public constructor, declare an empty primary constructor with non-default visibility: ```KOTLIN class Person private constructor() { /*...*/ } ``` Note: On the JVM, if all primary constructor parameters have default values, the compiler implicitly provides a parameterless constructor that uses those default values. This makes it easier to use Kotlin with libraries such as [Jackson](https://github.com/FasterXML/jackson) or [Spring Data JPA](https://spring.io/projects/spring-data-jpa), which create class instances through parameterless constructors. In the following example, Kotlin implicitly provides a parameterless constructor `Person()` that uses the default value `""`: ```KOTLIN class Person(val personName: String = "") ``` ## Inheritance Class inheritance in Kotlin allows you to create a new class (derived class) from an existing class (base class), inheriting its properties and functions while adding or modifying behavior. For detailed information about inheritance hierarchies and how to use the `open` keyword, see the [Inheritance](inheritance.html) section. ## Abstract classes In Kotlin, abstract classes are classes that can't be instantiated directly. They are designed to be inherited by other classes which define their actual behavior. This behavior is called an implementation. An abstract class can declare abstract properties and functions, which must be implemented by subclasses. Abstract classes can also have constructors. These constructors initialize class properties and enforce required parameters for subclasses. Declare an abstract class using the `abstract` keyword: ```KOTLIN abstract class Person(val name: String, val age: Int) ``` An abstract class can have both abstract and non-abstract members (properties and functions). To declare a member as abstract, you must use the `abstract` keyword explicitly. You don't need to annotate abstract classes or functions with the `open` keyword because they are implicitly inheritable by default. For more details about the `open` keyword, see [Inheritance](inheritance.html#open-keyword). Abstract members don't have an implementation in the abstract class. You define the implementation in a subclass or inheriting class with an `override` function or property: ```KOTLIN // Abstract class with a primary constructor that declares name and age abstract class Person( val name: String, val age: Int ) { // Abstract member // Doesn't provide implementation, // and it must be implemented by subclasses abstract fun introduce() // Non-abstract member (has an implementation) fun greet() { println("Hello, my name is $name.") } } // Subclass that provides an implementation for the abstract member class Student( name: String, age: Int, val school: String ) : Person(name, age) { override fun introduce() { println("I am $name, $age years old, and I study at $school.") } } fun main() { // Creates an instance of the Student class val student = Student("Alice", 20, "Engineering University") // Calls the non-abstract member student.greet() // Hello, my name is Alice. // Calls the overridden abstract member student.introduce() // I am Alice, 20 years old, and I study at Engineering University. } ``` ## Companion objects In Kotlin, each class can have a [companion object](object-declarations.html#companion-objects). Companion objects are a type of object declaration that allows you to access its members using the class name without creating a class instance. Suppose you need to write a function that can be called without creating an instance of a class, but it is still logically connected to the class (such as a factory function). In that case, you can declare it inside a companion [object declaration](object-declarations.html) within the class: ```KOTLIN // Class with a primary constructor that declares the name property class Person( val name: String ) { // Class body with a companion object companion object { fun createAnonymous() = Person("Anonymous") } } fun main() { // Calls the function without creating an instance of the class val anonymous = Person.createAnonymous() println(anonymous.name) // Anonymous } ``` If you declare a companion object inside your class, you can access its members using only the class name as a qualifier. For more information, see [Companion objects](object-declarations.html#companion-objects). # Data classes Data classes in Kotlin are primarily used to hold data. For each data class, the compiler automatically generates additional member functions that allow you to print an instance to readable output, compare instances, copy instances, and more. Data classes are marked with `data`: ```KOTLIN data class User(val name: String, val age: Int) ``` The compiler automatically derives the following members from all properties declared in the primary constructor: * `equals()`/`hashCode()` pair. * `toString()` of the form `"User(name=John, age=42)"`. * [componentN() functions](destructuring-declarations.html) corresponding to the properties in their order of declaration. * [copy() function](#copying). To ensure consistency and meaningful behavior of the generated code, data classes have to fulfill the following requirements: * The primary constructor must have at least one parameter. * All primary constructor parameters must be marked as `val` or `var`. * Data classes can't be abstract, open, sealed, or inner. Additionally, the generation of data class members follows these rules with regard to the members' inheritance: * If there are explicit implementations of `equals()`, `hashCode()`, or `toString()` in the data class body or `final` implementations in a superclass, then these functions are not generated, and the existing implementations are used. * If a supertype has `componentN()` functions that are `open` and return compatible types, the corresponding functions are generated for the data class and override those of the supertype. If the functions of the supertype cannot be overridden due to incompatible signatures or due to their being final, an error is reported. * Providing explicit implementations for the `componentN()` and `copy()` functions is not allowed. Data classes may extend other classes (see [Sealed classes](sealed-classes.html) for examples). Note: On the JVM, if the generated class needs to have a parameterless constructor, default values for the properties have to be specified (see [Constructors](classes.html#constructors-and-initializer-blocks)): ```KOTLIN data class User(val name: String = "", val age: Int = 0) ``` ## Properties declared in the class body The compiler only uses the properties defined inside the primary constructor for the automatically generated functions. To exclude a property from the generated implementations, declare it inside the class body: ```KOTLIN data class Person(val name: String) { var age: Int = 0 } ``` In the example below, only the `name` property is used by default inside the `toString()`, `equals()`, `hashCode()`, and `copy()` implementations, and there is only one component function, `component1()`. The `age` property is declared inside the class body and is excluded. Therefore, two `Person` objects with the same `name` but different `age` values are considered equal since `equals()` only evaluates properties from the primary constructor: ```KOTLIN data class Person(val name: String) { var age: Int = 0 } fun main() { //sampleStart val person1 = Person("John") val person2 = Person("John") person1.age = 10 person2.age = 20 println("person1 == person2: ${person1 == person2}") // person1 == person2: true println("person1 with age ${person1.age}: ${person1}") // person1 with age 10: Person(name=John) println("person2 with age ${person2.age}: ${person2}") // person2 with age 20: Person(name=John) //sampleEnd } ``` ## Copying Use the `copy()` function to copy an object, allowing you to alter some of its properties while keeping the rest unchanged. The implementation of this function for the `User` class above would be as follows: ```KOTLIN fun copy(name: String = this.name, age: Int = this.age) = User(name, age) ``` You can then write the following: ```KOTLIN val jack = User(name = "Jack", age = 1) val olderJack = jack.copy(age = 2) ``` The `copy()` function creates a shallow copy of the instance. In other words, it doesn't copy components recursively. As a result, references to other objects are shared. For example, if a property holds a mutable list, changes made through the "original" value are also visible through the copy, and changes made through the copy are visible through the original: ```KOTLIN data class Employee(val name: String, val roles: MutableList) fun main() { val original = Employee("Jamie", mutableListOf("developer")) val duplicate = original.copy() duplicate.roles.add("team lead") println(original) // Employee(name=Jamie, roles=[developer, team lead]) println(duplicate) // Employee(name=Jamie, roles=[developer, team lead]) } ``` As you can see, modifying the `duplicate.roles` property also changes the `original.roles` property because both properties share the same list reference. ## Data classes and destructuring declarations Component functions generated for data classes make it possible to use them in [destructuring declarations](destructuring-declarations.html): ```KOTLIN val jane = User("Jane", 35) val (name, age) = jane println("$name, $age years of age") // Jane, 35 years of age ``` ## Standard data classes The standard library provides the `Pair` and `Triple` classes. In most cases, though, named data classes are a better design choice because they make the code easier to read by providing meaningful names for the properties. # Extensions Kotlin extensions let you extend a class or an interface with new functionality without using inheritance or design patterns like Decorator. They are useful when working with third-party libraries you can't modify directly. Once created, you call these extensions as if they were members of the original class or interface. The most common forms of extensions are [extension functions](#extension-functions) and [extension properties](#extension-properties). Importantly, extensions don't modify the classes or interfaces they extend. When you define an extension, you don't add new members. You make new functions callable or new properties accessible using the same syntax. ## Receivers Extensions are always called on a receiver. The receiver has to have the same type as the class or interface being extended. To use an extension, prefix it with the receiver followed by a `.` and the function or property name. For example, the [.appendLine()](https://kotlinlang.org/api/core/kotlin-stdlib/kotlin.text/append-line.html) extension function from the standard library extends the `StringBuilder` class. So in this case, the receiver is a `StringBuilder` instance, and the receiver type is `StringBuilder`: ```KOTLIN fun main() { //sampleStart // builder is an instance of StringBuilder val builder = StringBuilder() // Calls .appendLine() extension function on builder .appendLine("Hello") .appendLine() .appendLine("World") println(builder.toString()) // Hello // // World } //sampleEnd ``` ## Extension functions Before creating your own extension functions, see if what you are looking for is already available in the Kotlin [standard library](https://kotlinlang.org/api/core/kotlin-stdlib/). The standard library provides many useful extension functions for: * Operating on collections: [.map()](https://kotlinlang.org/api/core/kotlin-stdlib/kotlin.collections/map.html), [.filter()](https://kotlinlang.org/api/core/kotlin-stdlib/kotlin.collections/filter.html), [.reduce()](https://kotlinlang.org/api/core/kotlin-stdlib/kotlin.collections/reduce.html), [.fold()](https://kotlinlang.org/api/core/kotlin-stdlib/kotlin.collections/fold.html), [.groupBy()](https://kotlinlang.org/api/core/kotlin-stdlib/kotlin.collections/group-by.html). * Converting to strings: [.joinToString()](https://kotlinlang.org/api/core/kotlin-stdlib/kotlin.collections/join-to-string.html). * Working with null values: [.filterNotNull()](https://kotlinlang.org/api/core/kotlin-stdlib/kotlin.collections/filter-not-null.html). To create your own extension function, prefix its name with a receiver type followed by a `.`. In this example, the `.truncate()` function extends the `String` class, so the receiver type is `String`: ```KOTLIN fun String.truncate(maxLength: Int): String { return if (this.length <= maxLength) this else take(maxLength - 3) + "..." } fun main() { val shortUsername = "KotlinFan42" val longUsername = "JetBrainsLoverForever" println("Short username: ${shortUsername.truncate(15)}") // KotlinFan42 println("Long username: ${longUsername.truncate(15)}") // JetBrainsLov... } ``` The `.truncate()` function truncates any string that it's called on by the number in the `maxLength` argument and adds an ellipsis `...`. If the string is shorter than `maxLength`, the function returns the original string. In this example, the `.displayInfo()` function extends the `User` interface: ```KOTLIN interface User { val name: String val email: String } fun User.displayInfo(): String = "User(name=$name, email=$email)" // Inherits from and implements the properties of the User interface class RegularUser(override val name: String, override val email: String) : User fun main() { val user = RegularUser("Alice", "alice@example.com") println(user.displayInfo()) // User(name=Alice, email=alice@example.com) } ``` The `.displayInfo()` function returns a string containing the `name` and `email` of a `RegularUser` instance. Defining an extension on an interface like this is useful when you want to add functionality to all types that implement an interface only once. In this example, the `.mostVoted()` function extends the `Map` class: ```KOTLIN fun Map.mostVoted(): String? { return maxByOrNull { (key, value) -> value }?.key } fun main() { val poll = mapOf( "Cats" to 37, "Dogs" to 58, "Birds" to 22 ) println("Top choice: ${poll.mostVoted()}") // Dogs } ``` The `.mostVoted()` function iterates through the key-value pairs of the map it's called on and uses the [maxByOrNull()](https://kotlinlang.org/api/core/kotlin-stdlib/kotlin.collections/max-by-or-null.html) function to return the key of the pair containing the highest value. If the map is empty, the `maxByOrNull()` function returns `null`. The `mostVoted()` function uses a safe call `?.` to only access the `key` property when the `maxByOrNull()` function returns a non-null value. ### Generic extension functions To create generic extension functions, declare the generic type parameter before the function name to make it available in the receiver type expression. In this example, the `.endpoints()` function extends `List` where `T` can be any type: ```KOTLIN fun List.endpoints(): Pair { return first() to last() } fun main() { val cities = listOf("Paris", "London", "Berlin", "Prague") val temperatures = listOf(21.0, 19.5, 22.3) val cityEndpoints = cities.endpoints() val tempEndpoints = temperatures.endpoints() println("First and last cities: $cityEndpoints") // (Paris, Prague) println("First and last temperatures: $tempEndpoints") // (21.0, 22.3) } ``` The `.endpoints()` function returns a pair containing the first and last elements of the list that it's called on. Inside the function body, it calls the `first()` and `last()` functions and combines their returned values into a `Pair` using the `to` infix function. For more information about generics, see [generic functions](generics.html). ### Nullable receivers You can define extension functions with a nullable receiver type, which allows you to call them on a variable even if its value is null. When the receiver is `null`, `this` is also `null`. Make sure to handle nullability correctly within your functions. For example, use `this == null` checks inside function bodies, [safe calls ?.](null-safety.html#safe-call-operator), or the [Elvis operator ?:](null-safety.html#elvis-operator). In this example, you can call the `.toString()` function without checking for `null` because the check already happens inside the extension function: ```KOTLIN fun main() { //sampleStart // Extension function on nullable Any fun Any?.toString(): String { if (this == null) return "null" // After null check, `this` is smart-cast to non-nullable Any // So this call resolves to the regular toString() function return toString() } val number: Int? = 42 val nothing: Any? = null println(number.toString()) // 42 println(nothing.toString()) // null //sampleEnd } ``` ### Extension or member functions? Since extension and member function calls have the same notation, how does the compiler know which one to use? Extension functions are dispatched statically, meaning the compiler determines which function to call based on the receiver type at compile time. For example: ```KOTLIN fun main() { //sampleStart open class Shape class Rectangle: Shape() fun Shape.getName() = "Shape" fun Rectangle.getName() = "Rectangle" fun printClassName(shape: Shape) { println(shape.getName()) } printClassName(Rectangle()) // Shape //sampleEnd } ``` In this example, the compiler calls the `Shape.getName()` extension function because the parameter `shape` is declared as type `Shape`. Because extension functions are resolved statically, the compiler chooses the function based on the declared type, not the actual instance. So even though the example passes a `Rectangle` instance, the `.getName()` function resolves to `Shape.getName()` since the variable is declared as type `Shape`. If a class has a member function and there's an extension function with the same receiver type, the same name, and compatible arguments, the member function takes precedence. For example: ```KOTLIN fun main() { //sampleStart class Example { fun printFunctionType() { println("Member function") } } fun Example.printFunctionType() { println("Extension function") } Example().printFunctionType() // Member function //sampleEnd } ``` However, extension functions can overload member functions that have the same name but a different signature: ```KOTLIN fun main() { //sampleStart class Example { fun printFunctionType() { println("Member function") } } // Same name but different signature fun Example.printFunctionType(index: Int) { println("Extension function #$index") } Example().printFunctionType(1) // Extension function #1 //sampleEnd } ``` In this example, since an `Int` is passed to the `.printFunctionType()` function, the compiler chooses the extension function because it matches the signature. The compiler ignores the member function, which takes no arguments. ### Anonymous extension functions You can define extension functions without giving them a name. This is useful when you want to avoid cluttering the global namespace or when you need to pass some extension behavior as a parameter. For example, suppose you want to extend a data class with a one-time function to calculate shipping, without giving it a name: ```KOTLIN fun main() { //sampleStart data class Order(val weight: Double) val calculateShipping = fun Order.(rate: Double): Double = this.weight * rate val order = Order(2.5) val cost = order.calculateShipping(3.0) println("Shipping cost: $cost") // Shipping cost: 7.5 } ``` To pass extension behavior as a parameter, use a [lambda expression](lambdas.html#lambda-expression-syntax) with a type annotation. For example, let's say you want to check if a number is within a range without defining a named function: ```KOTLIN fun main() { val isInRange: Int.(min: Int, max: Int) -> Boolean = { min, max -> this in min..max } println(5.isInRange(1, 10)) // true println(20.isInRange(1, 10)) // false } ``` In this example, the `isInRange` variable holds a function of type `Int.(min: Int, max: Int) -> Boolean`. The type is an extension function on the `Int` class that takes `min` and `max` parameters and returns a `Boolean`. The lambda body `{ min, max -> this in min..max }` checks whether the `Int` value the function is called on falls within the range between `min` and `max` parameters. If the check is successful, the lambda returns `true`. For more information, see [Lambda expressions and anonymous functions](lambdas.html). ## Extension properties Kotlin supports extension properties, which are useful for performing data transformations or creating UI display helpers without cluttering the class you're working with. To create an extension property, write the name of the class that you want to extend, followed by a `.` and the name of your property. For example, suppose you have a data class that represents a user with a first and last name, and you want to create a property that returns an email-style username when accessed. Your code might look like this: ```KOTLIN data class User(val firstName: String, val lastName: String) // An extension property to get a username-style email handle val User.emailUsername: String get() = "${firstName.lowercase()}.${lastName.lowercase()}" fun main() { val user = User("Mickey", "Mouse") // Calls extension property println("Generated email username: ${user.emailUsername}") // Generated email username: mickey.mouse } ``` Since extensions don't actually add members to classes, there's no efficient way for an extension property to have a [backing field](properties.html#backing-fields). That's why initializers are not allowed for extension properties. You can define their behavior only by explicitly providing getters and setters. For example: ```KOTLIN data class House(val streetName: String) // Doesn't compile because there is no getter and setter // var House.number = 1 // Error: Initializers are not allowed for extension properties // Compiles successfully val houseNumbers = mutableMapOf() var House.number: Int get() = houseNumbers[this] ?: 1 set(value) { println("Setting house number for ${this.streetName} to $value") houseNumbers[this] = value } fun main() { val house = House("Maple Street") // Shows the default println("Default number: ${house.number} ${house.streetName}") // Default number: 1 Maple Street house.number = 99 // Setting house number for Maple Street to 99 // Shows the updated number println("Updated number: ${house.number} ${house.streetName}") // Updated number: 99 Maple Street } ``` In this example, the getter uses the [Elvis operator](null-safety.html#elvis-operator) to return the house number if it exists in the `houseNumbers` map or `1`. To learn more about how to write getters and setters, see [Custom getters and setters](properties.html#custom-getters-and-setters). ## Companion object extensions If a class defines a [companion object](object-declarations.html#companion-objects), you can also define extension functions and properties for the companion object. Just like regular members of the companion object, you can call them using only the class name as the qualifier. The compiler names the companion object `Companion` by default: ```KOTLIN class Logger { companion object { } } fun Logger.Companion.logStartupMessage() { println("Application started.") } fun main() { Logger.logStartupMessage() // Application started. } ``` ## Declaring extensions as members You can declare extensions for one class inside another. Extensions like this have multiple implicit receivers. An implicit receiver is an object whose members you can access without qualifying them with [this](this-expressions.html#qualified-this): * The class where you declare the extension is the dispatch receiver. * The extension function's receiver type is the extension receiver. Consider this example where the `Connection` class has an extension function for the `Host` class called `printConnectionString()`: ```KOTLIN class Host(val hostname: String) { fun printHostname() { print(hostname) } } class Connection(val host: Host, val port: Int) { fun printPort() { print(port) } // Host is the extension receiver fun Host.printConnectionString() { // Calls Host.printHostname() printHostname() print(":") // Calls Connection.printPort() // Connection is the dispatch receiver printPort() } fun connect() { /*...*/ // Calls the extension function host.printConnectionString() } } fun main() { Connection(Host("kotl.in"), 443).connect() // kotl.in:443 // Triggers an error because the extension function isn't available outside Connection // Host("kotl.in").printConnectionString() // Unresolved reference 'printConnectionString'. } ``` This example declares the `printConnectionString()` function inside the `Connection` class, so the `Connection` class is the dispatch receiver. The extension function's receiver type is the `Host` class, so the `Host` class is the extension receiver. If the dispatch receiver and the extension receiver have members with the same name, the extension receiver's member takes precedence. To access the dispatch receiver explicitly, use the [qualified this syntax](this-expressions.html#qualified-this): ```KOTLIN class Connection { fun Host.getConnectionString() { // Calls Host.toString() toString() // Calls Connection.toString() this@Connection.toString() } } ``` ### Overriding member extensions You can declare member extensions as `open` and override them in subclasses, which is useful when you want to customize the extension's behavior for each subclass. The compiler handles each receiver type differently: | Receiver type |Resolution time |Dispatch type | ------------------------------------------------- | Dispatch receiver |Runtime |Virtual | | Extension receiver |Compile time |Static | Consider this example, where the `User` class is `open` and the `Admin` class inherits from it. The `NotificationSender` class defines `sendNotification()` extension functions for both `User` and `Admin` classes, and the `SpecialNotificationSender` class overrides them: ```KOTLIN open class User class Admin : User() open class NotificationSender { open fun User.sendNotification() { println("Sending user notification from normal sender") } open fun Admin.sendNotification() { println("Sending admin notification from normal sender") } fun notify(user: User) { user.sendNotification() } } class SpecialNotificationSender : NotificationSender() { override fun User.sendNotification() { println("Sending user notification from special sender") } override fun Admin.sendNotification() { println("Sending admin notification from special sender") } } fun main() { // Dispatch receiver is NotificationSender // Extension receiver is User // Resolves to User.sendNotification() in NotificationSender NotificationSender().notify(User()) // Sending user notification from normal sender // Dispatch receiver is SpecialNotificationSender // Extension receiver is User // Resolves to User.sendNotification() in SpecialNotificationSender SpecialNotificationSender().notify(User()) // Sending user notification from special sender // Dispatch receiver is SpecialNotificationSender // Extension receiver is User NOT Admin // The notify() function declares user as type User // Statically resolves to User.sendNotification() in SpecialNotificationSender SpecialNotificationSender().notify(Admin()) // Sending user notification from special sender } ``` The dispatch receiver is resolved at runtime using virtual dispatch, which makes the behavior in the `main()` function easier to follow. What may surprise you is that when you call the `notify()` function on an `Admin` instance, the compiler chooses the extension based on the declared type: `user: User`, because it resolves the extension receiver statically. ## Extensions and visibility modifiers Extensions use the same [visibility modifiers](visibility-modifiers.html) as regular functions declared in the same scope, including extensions declared as members of other classes. For example, an extension declared at the top level of a file can access other `private` top-level declarations in the same file: ```KOTLIN // File: StringUtils.kt private fun removeWhitespace(input: String): String { return input.replace("\\s".toRegex(), "") } fun String.cleaned(): String { return removeWhitespace(this) } fun main() { val rawEmail = " user @example. com " val cleaned = rawEmail.cleaned() println("Raw: '$rawEmail'") // Raw: ' user @example. com ' println("Cleaned: '$cleaned'") // Cleaned: 'user@example.com' println("Looks like an email: ${cleaned.contains("@") && cleaned.contains(".")}") // Looks like an email: true } ``` And if an extension is declared outside its receiver type, it can't access the receiver's `private` or `protected` members: ```KOTLIN class User(private val password: String) { fun isLoggedIn(): Boolean = true fun passwordLength(): Int = password.length } // Extension declared outside the class fun User.isSecure(): Boolean { // Can't access password because it's private: // return password.length >= 8 // Instead, we rely on public members: return passwordLength() >= 8 && isLoggedIn() } fun main() { val user = User("supersecret") println("Is user secure: ${user.isSecure()}") // Is user secure: true } ``` If an extension is marked as `internal`, it's only accessible within its [module](visibility-modifiers.html#modules): ```KOTLIN // Networking module // JsonParser.kt internal fun String.parseJson(): Map { return mapOf("fakeKey" to "fakeValue") } ``` ## Scope of extensions In most cases, you define extensions on the top level, directly under packages: ```KOTLIN package org.example.declarations fun List.getLongestString() { /*...*/} ``` To use an extension outside its declaring package, import it at the call site: ```KOTLIN package org.example.usage import org.example.declarations.getLongestString fun main() { val list = listOf("red", "green", "blue") list.getLongestString() } ``` For more information, see [Imports](packages.html#imports). # Interfaces Interfaces in Kotlin can contain declarations of abstract methods, as well as method implementations. What makes them different from abstract classes is that interfaces cannot store state. They can have properties, but these need to be abstract or provide accessor implementations. An interface is defined using the keyword `interface`: ```KOTLIN interface MyInterface { fun bar() fun foo() { // optional body } } ``` ## Implementing interfaces A class or object can implement one or more interfaces: ```KOTLIN class Child : MyInterface { override fun bar() { // body } } ``` ## Properties in interfaces You can declare properties in interfaces. A property declared in an interface can either be abstract or provide implementations for accessors. Properties declared in interfaces can't have backing fields, and therefore accessors declared in interfaces can't reference them: ```KOTLIN interface MyInterface { val prop: Int // abstract val propertyWithImplementation: String get() = "foo" fun foo() { print(prop) } } class Child : MyInterface { override val prop: Int = 29 } ``` ## Interfaces Inheritance An interface can derive from other interfaces, meaning it can both provide implementations for their members and declare new functions and properties. Quite naturally, classes implementing such an interface are only required to define the missing implementations: ```KOTLIN interface Named { val name: String } interface Person : Named { val firstName: String val lastName: String override val name: String get() = "$firstName $lastName" } data class Employee( // implementing 'name' is not required override val firstName: String, override val lastName: String, val position: Position ) : Person ``` ## Resolving overriding conflicts When you declare many types in your supertype list, you may inherit more than one implementation of the same method: ```KOTLIN interface A { fun foo() { print("A") } fun bar() } interface B { fun foo() { print("B") } fun bar() { print("bar") } } class C : A { override fun bar() { print("bar") } } class D : A, B { override fun foo() { super.foo() super.foo() } override fun bar() { super.bar() } } ``` Interfaces A and B both declare functions foo() and bar(). Both of them implement foo(), but only B implements bar() (bar() is not marked as abstract in A, because this is the default for interfaces if the function has no body). Now, if you derive a concrete class C from A, you have to override bar() and provide an implementation. However, if you derive D from A and B, you need to implement all the methods that you have inherited from multiple interfaces, and you need to specify how exactly D should implement them. This rule applies both to methods for which you've inherited a single implementation (bar()) and to those for which you've inherited multiple implementations (foo()). ## JVM default method generation for interface functions On the JVM, functions declared in interfaces are compiled to default methods. You can control this behavior using the `-jvm-default` compiler option with the following values: * `enable` (default): generates default implementations in interfaces and includes bridge functions in subclasses and `DefaultImpls` classes. Use this mode to maintain binary compatibility with older Kotlin versions. * `no-compatibility`: generates only default implementations in interfaces. This mode skips compatibility bridges and `DefaultImpls` classes, making it suitable for new Kotlin code. * `disable`: skips default methods and generates only compatibility bridges and `DefaultImpls` classes. To configure the `-jvm-default` compiler option, set the `jvmDefault` property in your Gradle Kotlin DSL: ```KOTLIN kotlin { compilerOptions { jvmDefault = JvmDefaultMode.NO_COMPATIBILITY } } ``` # Delegation The [Delegation pattern](https://en.wikipedia.org/wiki/Delegation_pattern) has proven to be a good alternative to implementation inheritance, and Kotlin supports it natively requiring zero boilerplate code. A class `Derived` can implement an interface `Base` by delegating all of its public members to a specified object: ```KOTLIN interface Base { fun print() } class BaseImpl(val x: Int) : Base { override fun print() { print(x) } } class Derived(b: Base) : Base by b fun main() { val base = BaseImpl(10) val derived = Derived(base) derived.print() // 10 } ``` The `by`-clause in the supertype list for `Derived` indicates that `b` will be stored internally in objects of `Derived` and the compiler will generate all the methods of `Base` that forward to `b`. ## Overriding a member of an interface implemented by delegation [Overrides](inheritance.html#overriding-methods) work as you expect: the compiler will use your `override` implementations instead of those in the delegate object. If you want to add `override fun printMessage() { print("abc") }` to `Derived`, the program would print abc instead of 10 when `printMessage` is called: ```KOTLIN interface Base { fun printMessage() fun printMessageLine() } class BaseImpl(val x: Int) : Base { override fun printMessage() { print(x) } override fun printMessageLine() { println(x) } } class Derived(b: Base) : Base by b { override fun printMessage() { println("abc") } } fun main() { val base = BaseImpl(10) val derived = Derived(base) derived.printMessage() // abc derived.printMessageLine() // 10 } ``` Note, however, that members overridden in this way do not get called from the members of the delegate object, which can only access its own implementations of the interface members: ```KOTLIN interface Base { val message: String fun print() } class BaseImpl(x: Int) : Base { override val message = "BaseImpl: x = $x" override fun print() { println(message) } } class Derived(b: Base) : Base by b { // This property is not accessible // from b's implementation of `print()` override val message = "Message of Derived" } fun main() { val base = BaseImpl(10) val derived = Derived(base) derived.print() // BaseImpl: x = 10 println(derived.message) // Message of Derived } ``` Learn more about [delegated properties](delegated-properties.html). # Inheritance Tip: Before creating an inheritance hierarchy with classes, consider using [abstract classes](classes.html#abstract-classes) or [interfaces](interfaces.html). You can inherit from abstract classes and interfaces by default. They are designed so that other classes can inherit their members and implement them. All classes in Kotlin have a common superclass, `Any`, which is the default superclass for a class with no supertypes declared: ```KOTLIN class Example // Implicitly inherits from Any ``` `Any` has three methods: `equals()`, `hashCode()`, and `toString()`. Thus, these methods are defined for all Kotlin classes. By default, Kotlin classes are final – they can't be inherited. To make a class inheritable, mark it with the `open` keyword: ```KOTLIN open class Base // Class is open for inheritance ``` [For more information, see Open keyword](#open-keyword). To declare an explicit supertype, place the type after a colon in the class header: ```KOTLIN open class Base(p: Int) class Derived(p: Int) : Base(p) ``` If the derived class has a primary constructor, the base class can (and must) be initialized in that primary constructor according to its parameters. If the derived class has no primary constructor, then each secondary constructor has to initialize the base type using the `super` keyword or it has to delegate to another constructor which does. Note that in this case, different secondary constructors can call different constructors of the base type: ```KOTLIN class MyView : View { constructor(ctx: Context) : super(ctx) constructor(ctx: Context, attrs: AttributeSet) : super(ctx, attrs) } ``` ## Open keyword In Kotlin, the `open` keyword indicates that a class or a member (function or property) can be overridden in subclasses. By default, Kotlin classes and their members are final, meaning they cannot be inherited from (for classes) or overridden (for members) unless you explicitly mark them as `open`: ```KOTLIN // Base class with the open keyword to allow inheritance open class Person( val name: String ) { // Open function that can be overridden in a subclass open fun introduce() { println("Hello, my name is $name.") } } // Subclass inheriting from Person and overriding the introduce() function class Student( name: String, val school: String ) : Person(name) { override fun introduce() { println("Hi, I'm $name, and I study at $school.") } } ``` If you override a member of a base class, the overriding member is also open by default. If you want to change this and forbid the subclasses of your class from overriding your implementation, you can explicitly mark the overriding member as `final`: ```KOTLIN // Base class with the open keyword to allow inheritance open class Person(val name: String) { // Open function that can be overridden in a subclass open fun introduce() { println("Hello, my name is $name.") } } // A subclass that inherits from Person and overrides the introduce() function class Student(name: String, val school: String) : Person(name) { // The final keyword prevents further overrides in subclasses final override fun introduce() { println("Hi, I'm $name, and I study at $school.") } } ``` ## Overriding methods Kotlin requires explicit modifiers for overridable members and overrides: ```KOTLIN open class Shape { open fun draw() { /*...*/ } fun fill() { /*...*/ } } class Circle() : Shape() { override fun draw() { /*...*/ } } ``` The `override` modifier is required for `Circle.draw()`. If it's missing, the compiler will complain. If there is no `open` modifier on a function, like `Shape.fill()`, declaring a method with the same signature in a subclass is not allowed, either with `override` or without it. The `open` modifier has no effect when added to members of a final class – a class without an `open` modifier. A member marked `override` is itself open, so it may be overridden in subclasses. If you want to prohibit re-overriding, use `final`: ```KOTLIN open class Rectangle() : Shape() { final override fun draw() { /*...*/ } } ``` ## Overriding properties The overriding mechanism works on properties in the same way that it does on methods. Properties declared on a superclass that are then redeclared on a derived class must be prefaced with `override`, and they must have a compatible type. Each declared property can be overridden by a property with an initializer or by a property with a `get` method: ```KOTLIN open class Shape { open val vertexCount: Int = 0 } class Rectangle : Shape() { override val vertexCount = 4 } ``` You can also override a `val` property with a `var` property, but not vice versa. This is allowed because a `val` property essentially declares a `get` method, and overriding it as a `var` additionally declares a `set` method in the derived class. Note that you can use the `override` keyword as part of the property declaration in a primary constructor: ```KOTLIN interface Shape { val vertexCount: Int } class Rectangle(override val vertexCount: Int = 4) : Shape // Always has 4 vertices class Polygon : Shape { override var vertexCount: Int = 0 // Can be set to any number later } ``` ## Derived class initialization order During the construction of a new instance of a derived class, the base class initialization is done as the first step (preceded only by evaluation of the arguments for the base class constructor), which means that it happens before the initialization logic of the derived class is run. ```KOTLIN //sampleStart open class Base(val name: String) { init { println("Initializing a base class") } open val size: Int = name.length.also { println("Initializing size in the base class: $it") } } class Derived( name: String, val lastName: String, ) : Base(name.replaceFirstChar { it.uppercase() }.also { println("Argument for the base class: $it") }) { init { println("Initializing a derived class") } override val size: Int = (super.size + lastName.length).also { println("Initializing size in the derived class: $it") } } //sampleEnd fun main() { println("Constructing the derived class(\"hello\", \"world\")") Derived("hello", "world") } ``` This means that when the base class constructor is executed, the properties declared or overridden in the derived class have not yet been initialized. Using any of those properties in the base class initialization logic (either directly or indirectly through another overridden `open` member implementation) may lead to incorrect behavior or a runtime failure. When designing a base class, you should therefore avoid using `open` members in the constructors, property initializers, or `init` blocks. ## Calling the superclass implementation Code in a derived class can call its superclass functions and property accessor implementations using the `super` keyword: ```KOTLIN open class Rectangle { open fun draw() { println("Drawing a rectangle") } val borderColor: String get() = "black" } class FilledRectangle : Rectangle() { override fun draw() { super.draw() println("Filling the rectangle") } val fillColor: String get() = super.borderColor } ``` Inside an inner class, accessing the superclass of the outer class is done using the `super` keyword qualified with the outer class name: `super@Outer`: ```KOTLIN open class Rectangle { open fun draw() { println("Drawing a rectangle") } val borderColor: String get() = "black" } //sampleStart class FilledRectangle: Rectangle() { override fun draw() { val filler = Filler() filler.drawAndFill() } inner class Filler { fun fill() { println("Filling") } fun drawAndFill() { super@FilledRectangle.draw() // Calls Rectangle's implementation of draw() fill() println("Drawn a filled rectangle with color ${super@FilledRectangle.borderColor}") // Uses Rectangle's implementation of borderColor's get() } } } //sampleEnd fun main() { val fr = FilledRectangle() fr.draw() } ``` ## Overriding rules In Kotlin, implementation inheritance is regulated by the following rule: if a class inherits multiple implementations of the same member from its immediate superclasses, it must override this member and provide its own implementation (perhaps, using one of the inherited ones). To denote the supertype from which the inherited implementation is taken, use `super` qualified by the supertype name in angle brackets, such as `super`: ```KOTLIN open class Rectangle { open fun draw() { /* ... */ } } interface Polygon { fun draw() { /* ... */ } // interface members are 'open' by default } class Square() : Rectangle(), Polygon { // The compiler requires draw() to be overridden: override fun draw() { super.draw() // call to Rectangle.draw() super.draw() // call to Polygon.draw() } } ``` It's fine to inherit from both `Rectangle` and `Polygon`, but both of them have their implementations of `draw()`, so you need to override `draw()` in `Square` and provide a separate implementation for it to eliminate the ambiguity. # Object declarations and expressions In Kotlin, objects allow you to define a class and create an instance of it in a single step. This is useful when you need either a reusable singleton instance or a one-time object. To handle these scenarios, Kotlin provides two key approaches: object declarations for creating singletons and object expressions for creating anonymous, one-time objects. Tip: A singleton ensures that a class has only one instance and provides a global point of access to it. Object declarations and object expressions are best used for scenarios when: * Using singletons for shared resources: You need to ensure that only one instance of a class exists throughout the application. For example, managing a database connection pool. * Creating factory methods: You need a convenient way to create instances efficiently. [Companion objects](#companion-objects) allow you to define class-level functions and properties tied to a class, simplifying the creation and management of these instances. * Modifying existing class behavior temporarily: You want to modify the behavior of an existing class without the need to create a new subclass. For example, adding temporary functionality to an object for a specific operation. * Type-safe design is required: You require one-time implementations of interfaces or [abstract classes](classes.html#abstract-classes) using object expressions. This can be useful for scenarios like a button click handler. ## Object declarations You can create single instances of objects in Kotlin using object declarations, which always have a name following the `object` keyword. This allows you to define a class and create an instance of it in a single step, which is useful for implementing singletons: ```KOTLIN //sampleStart // Declares a Singleton object to manage data providers object DataProviderManager { private val providers = mutableListOf() // Registers a new data provider fun registerDataProvider(provider: DataProvider) { providers.add(provider) } // Retrieves all registered data providers val allDataProviders: Collection get() = providers } //sampleEnd // Example data provider interface interface DataProvider { fun provideData(): String } // Example data provider implementation class ExampleDataProvider : DataProvider { override fun provideData(): String { return "Example data" } } fun main() { // Creates an instance of ExampleDataProvider val exampleProvider = ExampleDataProvider() // To refer to the object, use its name directly DataProviderManager.registerDataProvider(exampleProvider) // Retrieves and prints all data providers println(DataProviderManager.allDataProviders.map { it.provideData() }) // [Example data] } ``` Tip: The initialization of an object declaration is thread-safe and done on first access. To refer to the `object`, use its name directly: ```KOTLIN DataProviderManager.registerDataProvider(exampleProvider) ``` Object declarations can also have supertypes, similar to how [anonymous objects can inherit from existing classes or implement interfaces](#inherit-anonymous-objects-from-supertypes): ```KOTLIN object DefaultListener : MouseAdapter() { override fun mouseClicked(e: MouseEvent) { ... } override fun mouseEntered(e: MouseEvent) { ... } } ``` Like variable declarations, object declarations are not expressions, so they cannot be used on the right-hand side of an assignment statement: ```KOTLIN // Syntax error: An object expression cannot bind a name. val myObject = object MySingleton { val name = "Singleton" } ``` Object declarations cannot be local, which means they cannot be nested directly inside a function. However, they can be nested within other object declarations or non-inner classes. ### Data objects When printing a plain object declaration in Kotlin, the string representation contains both its name and the hash of the `object`: ```KOTLIN object MyObject fun main() { println(MyObject) // MyObject@hashcode } ``` However, by marking an object declaration with the `data` modifier, you can instruct the compiler to return the actual name of the object when calling `toString()`, the same way it works for [data classes](data-classes.html): ```KOTLIN data object MyDataObject { val number: Int = 3 } fun main() { println(MyDataObject) // MyDataObject } ``` Additionally, the compiler generates several functions for your `data object`: * `toString()` returns the name of the data object * `equals()`/`hashCode()` enables equality checks and hash-based collections Note: You can't provide a custom `equals` or `hashCode` implementation for a `data object`. The `equals()` function for a `data object` ensures that all objects that have the type of your `data object` are considered equal. In most cases, you will only have a single instance of your `data object` at runtime, since a `data object` declares a singleton. However, in the edge case where another object of the same type is generated at runtime (for example, by using platform reflection with `java.lang.reflect` or a JVM serialization library that uses this API under the hood), this ensures that the objects are treated as being equal. Warning: Make sure that you only compare `data objects` structurally (using the `==` operator) and never by reference (using the `===` operator). This helps you to avoid pitfalls when more than one instance of a data object exists at runtime. ```KOTLIN import java.lang.reflect.Constructor data object MySingleton fun main() { val evilTwin = createInstanceViaReflection() println(MySingleton) // MySingleton println(evilTwin) // MySingleton // Even when a library forcefully creates a second instance of MySingleton, // its equals() function returns true: println(MySingleton == evilTwin) // true // Don't compare data objects using === println(MySingleton === evilTwin) // false } fun createInstanceViaReflection(): MySingleton { // Kotlin reflection does not permit the instantiation of data objects. // This creates a new MySingleton instance "by force" (using Java platform reflection) // Don't do this yourself! return (MySingleton.javaClass.declaredConstructors[0].apply { isAccessible = true } as Constructor).newInstance() } ``` The generated `hashCode()` function has a behavior that is consistent with the `equals()` function, so that all runtime instances of a `data object` have the same hash code. #### Differences between data objects and data classes While `data object` and `data class` declarations are often used together and have some similarities, there are some functions that are not generated for a `data object`: * No `copy()` function. Because a `data object` declaration is intended to be used as singletons, no `copy()` function is generated. Singletons restrict the instantiation of a class to a single instance, which would be violated by allowing copies of the instance to be created. * No `componentN()` function. Unlike a `data class`, a `data object` does not have any data properties. Since attempting to destructure such an object without data properties wouldn't make sense, no `componentN()` functions are generated. #### Use data objects with sealed hierarchies Data object declarations are particularly useful for sealed hierarchies like [sealed classes or sealed interfaces](sealed-classes.html). They allow you to maintain symmetry with any data classes you may have defined alongside the object. In this example, declaring `EndOfFile` as a `data object` instead of a plain `object` means that it will get the `toString()` function without the need to override it manually: ```KOTLIN sealed interface ReadResult data class Number(val number: Int) : ReadResult data class Text(val text: String) : ReadResult data object EndOfFile : ReadResult fun main() { println(Number(7)) // Number(number=7) println(EndOfFile) // EndOfFile } ``` ### Companion objects Companion objects allow you to define class-level functions and properties. This makes it easy to create factory methods, hold constants, and access shared utilities. An object declaration inside a class can be marked with the `companion` keyword: ```KOTLIN class MyClass { companion object Factory { fun create(): MyClass = MyClass() } } ``` Members of the `companion object` can be called simply by using the class name as the qualifier: ```KOTLIN class User(val name: String) { // Defines a companion object that acts as a factory for creating User instances companion object Factory { fun create(name: String): User = User(name) } } fun main(){ // Calls the companion object's factory method using the class name as the qualifier. // Creates a new User instance val userInstance = User.create("John Doe") println(userInstance.name) // John Doe } ``` The name of the `companion object` can be omitted, in which case the name `Companion` is used: ```KOTLIN class User(val name: String) { // Defines a companion object without a name companion object { } } // Accesses the companion object val companionUser = User.Companion ``` Class members can access `private` members of their corresponding `companion object`: ```KOTLIN class User(val name: String) { companion object { private val defaultGreeting = "Hello" } fun sayHi() { println(defaultGreeting) } } User("Nick").sayHi() // Hello ``` When a class name is used by itself, it acts as a reference to the companion object of the class, regardless of whether the companion object is named or not: ```KOTLIN //sampleStart class User1 { // Defines a named companion object companion object Named { fun show(): String = "User1's Named Companion Object" } } // References the companion object of User1 using the class name val reference1 = User1 class User2 { // Defines an unnamed companion object companion object { fun show(): String = "User2's Companion Object" } } // References the companion object of User2 using the class name val reference2 = User2 //sampleEnd fun main() { // Calls the show() function from the companion object of User1 println(reference1.show()) // User1's Named Companion Object // Calls the show() function from the companion object of User2 println(reference2.show()) // User2's Companion Object } ``` Although members of companion objects in Kotlin look like static members from other languages, they are actually instance members of the companion object, meaning they belong to the object itself. This allows companion objects to implement interfaces: ```KOTLIN interface Factory { fun create(name: String): T } class User(val name: String) { // Defines a companion object that implements the Factory interface companion object : Factory { override fun create(name: String): User = User(name) } } fun main() { // Uses the companion object as a Factory val userFactory: Factory = User val newUser = userFactory.create("Example User") println(newUser.name) // Example User } ``` However, on the JVM, you can have members of companion objects generated as real static methods and fields if you use the `@JvmStatic` annotation. See the [Java interoperability](java-to-kotlin-interop.html#static-fields) section for more detail. ## Object expressions Object expressions declare a class and create an instance of that class, but without naming either of them. These classes are useful for one-time use. They can either be created from scratch, inherit from existing classes, or implement interfaces. Instances of these classes are also called anonymous objects because they are defined by an expression, not a name. ### Create anonymous objects from scratch Object expressions start with the `object` keyword. If the object doesn't extend any classes or implement interfaces, you can define an object's members directly inside curly braces after the `object` keyword: ```KOTLIN fun main() { //sampleStart val helloWorld = object { val hello = "Hello" val world = "World" // Object expressions extend the Any class, which already has a toString() function, // so it must be overridden override fun toString() = "$hello $world" } print(helloWorld) // Hello World //sampleEnd } ``` ### Inherit anonymous objects from supertypes To create an anonymous object that inherits from some type (or types), specify this type after `object` and a colon `:`. Then implement or override the members of this class as if you were [inheriting](inheritance.html) from it: ```KOTLIN window.addMouseListener(object : MouseAdapter() { override fun mouseClicked(e: MouseEvent) { /*...*/ } override fun mouseEntered(e: MouseEvent) { /*...*/ } }) ``` If a supertype has a constructor, pass the appropriate constructor parameters to it. Multiple supertypes can be specified, separated by commas, after the colon: ```KOTLIN //sampleStart // Creates an open class BankAccount with a balance property open class BankAccount(initialBalance: Int) { open val balance: Int = initialBalance } // Defines an interface Transaction with an execute() function interface Transaction { fun execute() } // A function to perform a special transaction on a BankAccount fun specialTransaction(account: BankAccount) { // Creates an anonymous object that inherits from the BankAccount class and implements the Transaction interface // The balance of the provided account is passed to the BankAccount superclass constructor val temporaryAccount = object : BankAccount(account.balance), Transaction { override val balance = account.balance + 500 // Temporary bonus // Implements the execute() function from the Transaction interface override fun execute() { println("Executing special transaction. New balance is $balance.") } } // Executes the transaction temporaryAccount.execute() } //sampleEnd fun main() { // Creates a BankAccount with an initial balance of 1000 val myAccount = BankAccount(1000) // Performs a special transaction on the created account specialTransaction(myAccount) // Executing special transaction. New balance is 1500. } ``` ### Use anonymous objects as return and value types When you return an anonymous object from a local or [private](visibility-modifiers.html#packages) function or property, all the members of that anonymous object are accessible through that function or property: ```KOTLIN //sampleStart class UserPreferences { private fun getPreferences() = object { val theme: String = "Dark" val fontSize: Int = 14 } fun printPreferences() { val preferences = getPreferences() println("Theme: ${preferences.theme}, Font Size: ${preferences.fontSize}") } } //sampleEnd fun main() { val userPreferences = UserPreferences() userPreferences.printPreferences() // Theme: Dark, Font Size: 14 } ``` This allows you to return an anonymous object with specific properties, offering a simple way to encapsulate data or behavior without creating a separate class. If a function or property that returns an anonymous object has `public`, `protected`, or `internal` visibility, its actual type is: * `Any` if the anonymous object doesn't have a declared supertype. * The declared supertype of the anonymous object, if there is exactly one such type. * The explicitly declared type if there is more than one declared supertype. In all these cases, members added in the anonymous object are not accessible. Overridden members are accessible if they are declared in the actual type of the function or property. For example: ```KOTLIN //sampleStart interface Notification { // Declares notifyUser() in the Notification interface fun notifyUser() } interface DetailedNotification class NotificationManager { // The return type is Any. The message property is not accessible. // When the return type is Any, only members of the Any class are accessible. fun getNotification() = object { val message: String = "General notification" } // The return type is Notification because the anonymous object implements only one interface // The notifyUser() function is accessible because it is part of the Notification interface // The message property is not accessible because it is not declared in the Notification interface fun getEmailNotification() = object : Notification { override fun notifyUser() { println("Sending email notification") } val message: String = "You've got mail!" } // The return type is DetailedNotification. The notifyUser() function and the message property are not accessible // Only members declared in the DetailedNotification interface are accessible fun getDetailedNotification(): DetailedNotification = object : Notification, DetailedNotification { override fun notifyUser() { println("Sending detailed notification") } val message: String = "Detailed message content" } } //sampleEnd fun main() { // This produces no output val notificationManager = NotificationManager() // The message property is not accessible here because the return type is Any // This produces no output val notification = notificationManager.getNotification() // The notifyUser() function is accessible // The message property is not accessible here because the return type is Notification val emailNotification = notificationManager.getEmailNotification() emailNotification.notifyUser() // Sending email notification // The notifyUser() function and message property are not accessible here because the return type is DetailedNotification // This produces no output val detailedNotification = notificationManager.getDetailedNotification() } ``` ### Access variables from anonymous objects Code within the body of object expressions can access variables from the enclosing scope: ```KOTLIN import java.awt.event.MouseAdapter import java.awt.event.MouseEvent fun countClicks(window: JComponent) { var clickCount = 0 var enterCount = 0 // MouseAdapter provides default implementations for mouse event functions // Simulates MouseAdapter handling mouse events window.addMouseListener(object : MouseAdapter() { override fun mouseClicked(e: MouseEvent) { clickCount++ } override fun mouseEntered(e: MouseEvent) { enterCount++ } }) // The clickCount and enterCount variables are accessible within the object expression } ``` ## Behavior difference between object declarations and expressions There are differences in the initialization behavior between object declarations and object expressions: * Object expressions are executed (and initialized) immediately, where they are used. * Object declarations are initialized lazily, when accessed for the first time. * A companion object is initialized when the corresponding class is loaded (resolved) that matches the semantics of a Java static initializer. # This expressions The `this` expression refers to the current receiver (the object with which the function works). How you use `this` depends on the context: * In a member of a [class](classes.html), `this` refers to the current object of that class. For example, in the following code, `this.name` means the `name` property of the current `Language` object: ```KOTLIN class Language(val name: String) { fun printName() { println(this.name) } } fun main() { val language = Language("Kotlin") language.printName() // Kotlin } ``` * In an [extension function](extensions.html) or a [function literal with receiver](lambdas.html#function-literals-with-receiver), `this` refers to the receiver. In the following example, `lastCharacter()` is called on the string `"Kotlin"`. Therefore, `"Kotlin"` is the receiver. Inside the extension function, `this` refers to `"Kotlin"`. This means that `this.length` is the length of `"Kotlin"`: ```KOTLIN fun String.lastCharacter(): Char { println(this.length) // 6 return this[this.length - 1] } fun main() { println("Kotlin".lastCharacter()) // n } ``` Tip: In simple cases, you don't need to write `this` explicitly. Kotlin resolves it from the current scope. Learn more about [Implicit this](#implicit-this). ## Qualified `this` Your code can have several receivers available at the same time when receiver scopes are nested. Kotlin can use any available receiver to access its members implicitly, but receivers from inner scopes have higher priority. To explicitly refer to a particular receiver, use a qualified `this`. It is especially useful when multiple receivers have members with the same name, and you need to access a member of an outer receiver. To use a qualified `this`, add a [label](returns.html) qualifier: ```KOTLIN this@label ``` The label tells the compiler which receiver to access. You can use the name of an enclosing class or extension function. For example, `this@foo` refers to the receiver of an enclosing extension function named `foo`. ### Access an outer class from an inner class In an [inner class](nested-classes.html#inner-classes), unqualified `this` refers to the inner class instance. To access the outer class object, use qualified `this`: ```KOTLIN class User(val name: String) { inner class Age(val value: Int) { fun printInfo() { // Refers to the value property of the current Age object println(this.value) // 22 // Refers to the name property of the outer User object println(this@User.name) // Jane Doe } } } fun main() { val user = User("Jane Doe") val age = user.Age(22) age.printInfo() } ``` Note: Only inner classes hold a reference to an outer class instance. Regular [nested classes](nested-classes.html) don't have access to `this` from the outer class. ### Access a class from an extension function If you declare an extension function inside a class, two receivers are available: * The extension receiver: the value on which you call the extension function. * The dispatch receiver: the current object of the class where you declare the extension function. Use qualified `this` to specify which receiver you need: ```KOTLIN class User(val name: String) { val prefix = "Name" fun String.formatName(): String { return "${this@User.prefix}: ${this.uppercase()}" } fun printName() { println(name.formatName()) } } fun main() { val user = User("Jane Doe") user.printName() // Name: JANE DOE } ``` Here: * `this` refers to the extension receiver (`String`), so `this.uppercase()` converts the string to uppercase. * `this@User` refers to the current `User` object. * `this@User.prefix` accesses the `prefix` property of the current `User` object. ### Access from a lambda Unlike a regular lambda, a [lambda with receiver](lambdas.html#function-literals-with-receiver) introduces a receiver into its scope. As a result, `this` inside the lambda refers to the lambda's receiver, not to one from an enclosing scope. If a lambda with receiver is nested inside another receiver scope, add a label to the lambda and use a qualified `this` to refer explicitly to the lambda's receiver or to a receiver from an enclosing scope: ```KOTLIN class User(val name: String) { fun printWithPrefix() { val printString: String.() -> Unit = stringLabel@ { println("${this@stringLabel}: ${this@User.name}") } printString("User") } } fun main() { val user = User("Jane Doe") user.printWithPrefix() // User: Jane Doe } ``` Here: * `stringLabel@` labels the lambda. * `this@stringLabel` refers to the string receiver of the lambda. * `this@User` refers to the current `User` object. The label doesn't call anything or change how the lambda works. It only helps you refer to the lambda's receiver. ### Access an anonymous object or its outer class An [anonymous object](object-declarations.html#object-expressions) has its own receiver scope. Inside the object body, unqualified `this` refers to the anonymous object itself. However, since anonymous objects don't have class names, you can't use them as `this` qualifiers. Therefore, you can refer to the anonymous object only with unqualified `this`: ```KOTLIN interface UserPrinter { fun print() } fun main() { val printer = object : UserPrinter { val prefix = "User" override fun print() { // `this` refers to the anonymous object // `this.prefix` accesses its `prefix` property println(this.prefix) } } printer.print() // User } ``` If you declare an anonymous object inside another class, you can use qualified `this` to access the enclosing object: ```KOTLIN interface UserPrinter { fun print() } class User(val name: String) { fun createPrinter(): UserPrinter { return object : UserPrinter { override fun print() { // `this@User` refers to the enclosing `User` object // `this@User.name` accesses its `name` property println(this@User.name) } } } } fun main() { val printer = User("Jane Doe").createPrinter() printer.print() // Jane Doe } ``` ## Implicit `this` When you call a member function on `this`, you can omit the `this.` qualifier. However, if another callable with the same name is available in a closer lexical scope, Kotlin resolves the unqualified call to that callable instead of the member function. To explicitly call the member function, use the `this.` qualifier: ```KOTLIN fun main() { class A { fun printLine() { println("Member function") } fun invokePrintLine() { fun printLine() { println("Local function") } printLine() // Local function this.printLine() // Member function } } A().invokePrintLine() } ``` # Sealed classes and interfaces Sealed classes and interfaces provide controlled inheritance of your class hierarchies. All direct subclasses of a sealed class are known at compile time. No other subclasses may appear outside the module and package within which the sealed class is defined. The same logic applies to sealed interfaces and their implementations: once a module with a sealed interface is compiled, no new implementations can be created. Note: Direct subclasses are classes that immediately inherit from their superclass. Indirect subclasses are classes that inherit from more than one level down from their superclass. When you combine sealed classes and interfaces with the `when` expression, you can cover the behavior of all possible subclasses and ensure that no new subclasses are created to affect your code adversely. Sealed classes are best used for scenarios when: * Limited class inheritance is desired: You have a predefined, finite set of subclasses that extend a class, all of which are known at compile time. * Type-safe design is required: Safety and pattern matching are crucial in your project. Particularly for state management or handling complex conditional logic. For an example, check out [Use sealed classes with when expressions](#use-sealed-classes-with-when-expression). * Working with closed APIs: You want robust and maintainable public APIs for libraries that ensure that third-party clients use the APIs as intended. For more detailed practical applications, see [Use case scenarios](#use-case-scenarios). Tip: Java 15 introduced [a similar concept](https://docs.oracle.com/en/java/javase/15/language/sealed-classes-and-interfaces.html#GUID-0C709461-CC33-419A-82BF-61461336E65F), where sealed classes use the `sealed` keyword along with the `permits` clause to define restricted hierarchies. ## Declare a sealed class or interface To declare a sealed class or interface, use the `sealed` modifier: ```KOTLIN // Create a sealed interface sealed interface Error // Create a sealed class that implements sealed interface Error sealed class IOError(): Error // Define subclasses that extend sealed class 'IOError' class FileReadError(val file: File): IOError() class DatabaseError(val source: DataSource): IOError() // Create a singleton object implementing the 'Error' sealed interface object RuntimeError : Error ``` This example could represent a library's API that contains error classes to let library users handle errors that it can throw. If the hierarchy of such error classes includes interfaces or abstract classes visible in the public API, then nothing prevents other developers from implementing or extending them in the client code. Since the library doesn't know about errors declared outside of it, it can't treat them consistently with its own classes. However, with a sealed hierarchy of error classes, library authors can be sure that they know all the possible error types and that other error types can't appear later. The hierarchy of the example looks like this: ![Hierarchy illustration of sealed classes and interfaces](images/sealed-classes-interfaces.svg) ### Constructors A sealed class itself is always an [abstract class](classes.html#abstract-classes), and as a result, can't be instantiated directly. However, it may contain or inherit constructors. These constructors aren't for creating instances of the sealed class itself but for its subclasses. Consider the following example with a sealed class called `Error` and its several subclasses, which we instantiate: ```KOTLIN sealed class Error(val message: String) { class NetworkError : Error("Network failure") class DatabaseError : Error("Database cannot be reached") class UnknownError : Error("An unknown error has occurred") } fun main() { val errors = listOf(Error.NetworkError(), Error.DatabaseError(), Error.UnknownError()) errors.forEach { println(it.message) } } // Network failure // Database cannot be reached // An unknown error has occurred ``` You can use [enum](enum-classes.html) classes within your sealed classes to use enum constants to represent states and provide additional detail. Each enum constant exists only as a single instance, while subclasses of a sealed class may have multiple instances. In the example, the `sealed class Error` along with its several subclasses, employs an `enum` to denote error severity. Each subclass constructor initializes the `severity` and can alter its state: ```KOTLIN enum class ErrorSeverity { MINOR, MAJOR, CRITICAL } sealed class Error(val severity: ErrorSeverity) { class FileReadError(val file: File): Error(ErrorSeverity.MAJOR) class DatabaseError(val source: DataSource): Error(ErrorSeverity.CRITICAL) object RuntimeError : Error(ErrorSeverity.CRITICAL) // Additional error types can be added here } ``` Constructors of sealed classes can have one of two [visibilities](visibility-modifiers.html): `protected` (by default) or `private`: ```KOTLIN sealed class IOError { // A sealed class constructor has protected visibility by default. It's visible inside this class and its subclasses constructor() { /*...*/ } // Private constructor, visible inside this class only. // Using a private constructor in a sealed class allows for even stricter control over instantiation, enabling specific initialization procedures within the class. private constructor(description: String): this() { /*...*/ } // This will raise an error because public and internal constructors are not allowed in sealed classes // public constructor(code: Int): this() {} } ``` ## Inheritance Direct subclasses of sealed classes and interfaces must be declared in the same package. They may be top-level or nested inside any number of other named classes, named interfaces, or named objects. Subclasses can have any [visibility](visibility-modifiers.html) as long as they are compatible with normal inheritance rules in Kotlin, including those for [overriding properties](inheritance.html#overriding-properties). Subclasses of sealed classes must have a properly qualified name. They can't be local or anonymous objects. Note: `enum` classes can't extend a sealed class, or any other class. However, they can implement sealed interfaces: ```KOTLIN sealed interface Error // enum class extending the sealed interface Error enum class ErrorType : Error { FILE_ERROR, DATABASE_ERROR } ``` These restrictions don't apply to indirect subclasses. If a direct subclass of a sealed class is not marked as sealed, it can be extended in any way that its modifiers allow: ```KOTLIN // Sealed interface 'Error' has implementations only in the same package and module sealed interface Error // Sealed class 'IOError' extends 'Error' and is extendable only within the same package sealed class IOError(): Error // Open class 'CustomError' extends 'Error' and can be extended anywhere it's visible open class CustomError(): Error ``` ### Inheritance in multiplatform projects There is one more inheritance restriction in [multiplatform projects](https://kotlinlang.org/docs/multiplatform/get-started.html): direct subclasses of sealed classes must reside in the same [source set](https://kotlinlang.org/docs/multiplatform/multiplatform-discover-project.html#source-sets). It applies to sealed classes without the [expected and actual modifiers](https://kotlinlang.org/docs/multiplatform/multiplatform-expect-actual.html). If a sealed class is declared as `expect` in a common source set and have `actual` implementations in platform source sets, both `expect` and `actual` versions can have subclasses in their source sets. Moreover, if you use a hierarchical structure, you can create subclasses in any source set between the `expect` and `actual` declarations. [Learn more about the hierarchical structure of multiplatform projects](https://kotlinlang.org/docs/multiplatform/multiplatform-hierarchy.html). ## Use sealed classes with when expression The key benefit of using sealed classes comes into play when you use them in a [when](control-flow.html#when-expressions-and-statements) expression. The `when` expression, used with a sealed class, allows the Kotlin compiler to check exhaustively that all possible cases are covered. In such cases, you don't need to add an `else` clause: ```KOTLIN // Sealed class and its subclasses sealed class Error { class FileReadError(val file: String): Error() class DatabaseError(val source: String): Error() object RuntimeError : Error() } //sampleStart // Function to log errors fun log(e: Error) = when(e) { is Error.FileReadError -> println("Error while reading file ${e.file}") is Error.DatabaseError -> println("Error while reading from database ${e.source}") Error.RuntimeError -> println("Runtime error") // No `else` clause is required because all the cases are covered } //sampleEnd // List all errors fun main() { val errors = listOf( Error.FileReadError("example.txt"), Error.DatabaseError("usersDatabase"), Error.RuntimeError ) errors.forEach { log(it) } } ``` Tip: To reduce repetition in `when` expressions, try out context-sensitive resolution (currently in preview). This feature allows you to omit the type name when matching sealed class members if the expected type is known. For more information, see [Preview of context-sensitive resolution](whatsnew22.html#preview-of-context-sensitive-resolution) or the related [KEEP proposal](https://github.com/Kotlin/KEEP/blob/improved-resolution-expected-type/proposals/context-sensitive-resolution.md). When using sealed classes with `when` expressions, you can also add guard conditions to include additional checks in a single branch. For more information, see [Guard conditions in when expressions](control-flow.html#guard-conditions-in-when-expressions). Note: In multiplatform projects, if you have a sealed class with a `when` expression as an [expected declaration](https://kotlinlang.org/docs/multiplatform/multiplatform-expect-actual.html) in your common code, you still need an `else` branch. This is because subclasses of `actual` platform implementations may extend sealed classes that aren't known in the common code. ## Use case scenarios Let's explore some practical scenarios where sealed classes and interfaces can be particularly useful. ### State management in UI applications You can use sealed classes to represent different UI states in an application. This approach allows for structured and safe handling of UI changes. This example demonstrates how to manage various UI states: ```KOTLIN sealed class UIState { data object Loading : UIState() data class Success(val data: String) : UIState() data class Error(val exception: Exception) : UIState() } fun updateUI(state: UIState) { when (state) { is UIState.Loading -> showLoadingIndicator() is UIState.Success -> showData(state.data) is UIState.Error -> showError(state.exception) } } ``` ### Payment method handling In practical business applications, handling various payment methods efficiently is a common requirement. You can use sealed classes with `when` expressions to implement such business logic. By representing different payment methods as subclasses of a sealed class, it establishes a clear and manageable structure for processing transactions: ```KOTLIN sealed class Payment { data class CreditCard(val number: String, val expiryDate: String) : Payment() data class PayPal(val email: String) : Payment() data object Cash : Payment() } fun processPayment(payment: Payment) { when (payment) { is Payment.CreditCard -> processCreditCardPayment(payment.number, payment.expiryDate) is Payment.PayPal -> processPayPalPayment(payment.email) is Payment.Cash -> processCashPayment() } } ``` `Payment` is a sealed class that represents different payment methods in an e-commerce system: `CreditCard`, `PayPal`, and `Cash`. Each subclass can have its specific properties, like `number` and `expiryDate` for `CreditCard`, and `email` for `PayPal`. The `processPayment()` function demonstrates how to handle different payment methods. This approach ensures that all possible payment types are considered, and the system remains flexible for new payment methods to be added in the future. ### API request-response handling You can use sealed classes and sealed interfaces to implement a user authentication system that handles API requests and responses. The user authentication system has login and logout functionalities. The `ApiRequest` sealed interface defines specific request types: `LoginRequest` for login, and `LogoutRequest` for logout operations. The sealed class, `ApiResponse`, encapsulates different response scenarios: `UserSuccess` with user data, `UserNotFound` for absent users, and `Error` for any failures. The `handleRequest` function processes these requests in a type-safe manner using a `when` expression, while `getUserById` simulates user retrieval: ```KOTLIN // Import necessary modules import io.ktor.server.application.* import io.ktor.server.resources.* import kotlinx.serialization.* // Define the sealed interface for API requests using Ktor resources @Resource("api") sealed interface ApiRequest @Serializable @Resource("login") data class LoginRequest(val username: String, val password: String) : ApiRequest @Serializable @Resource("logout") object LogoutRequest : ApiRequest // Define the ApiResponse sealed class with detailed response types sealed class ApiResponse { data class UserSuccess(val user: UserData) : ApiResponse() data object UserNotFound : ApiResponse() data class Error(val message: String) : ApiResponse() } // User data class to be used in the success response data class UserData(val userId: String, val name: String, val email: String) // Function to validate user credentials (for demonstration purposes) fun isValidUser(username: String, password: String): Boolean { // Some validation logic (this is just a placeholder) return username == "validUser" && password == "validPass" } // Function to handle API requests with detailed responses fun handleRequest(request: ApiRequest): ApiResponse { return when (request) { is LoginRequest -> { if (isValidUser(request.username, request.password)) { ApiResponse.UserSuccess(UserData("userId", "userName", "userEmail")) } else { ApiResponse.Error("Invalid username or password") } } is LogoutRequest -> { // Assuming logout operation always succeeds for this example ApiResponse.UserSuccess(UserData("userId", "userName", "userEmail")) // For demonstration } } } // Function to simulate a getUserById call fun getUserById(userId: String): ApiResponse { return if (userId == "validUserId") { ApiResponse.UserSuccess(UserData("validUserId", "John Doe", "john@example.com")) } else { ApiResponse.UserNotFound } // Error handling would also result in an Error response. } // Main function to demonstrate the usage fun main() { val loginResponse = handleRequest(LoginRequest("user", "pass")) println(loginResponse) val logoutResponse = handleRequest(LogoutRequest) println(logoutResponse) val userResponse = getUserById("validUserId") println(userResponse) val userNotFoundResponse = getUserById("invalidId") println(userNotFoundResponse) } ``` ## What's next Learn more about [inheritance in Kotlin](inheritance.html). # Enum classes Enum classes represent a fixed set of possible values. Use an enum class when a value can only be one of several predefined options, such as available states or modes. Each value in an enum class is called an enum constant. Enum constants behave like [singleton objects](object-declarations.html) of the enum class type, so they can have properties, functions, and custom behavior. Enum classes are the best fit when all possible values are known in advance and have the same structure. If you need to hold different data or have a different structure for each case, use [sealed classes or interfaces](sealed-classes.html). ## Declare enum classes To create an enum class, use the `enum` keyword and follow the usual class syntax with a body enclosed in curly braces. Inside the class body, list the enum constants separated by commas: ```KOTLIN enum class Direction { NORTH, SOUTH, WEST, EAST } ``` In this example, `Direction` is the enum class, and `NORTH`, `SOUTH`, `WEST`, and `EAST` are enum constants. By convention, enum constants are usually written in uppercase because they represent constant values. You can access an enum constant by using the enum class name followed by the constant name: ```KOTLIN enum class Direction { NORTH, SOUTH, WEST, EAST } fun main() { // `Direction.NORTH` is an enum constant of type `Direction`. val direction: Direction = Direction.NORTH println(direction) // NORTH } ``` Every enum class in Kotlin inherits from the [Enum<T>](https://kotlinlang.org/api/core/kotlin-stdlib/kotlin/-enum/) base class, where `T` is the enum class itself. For example, the `Direction` enum class inherits from `Enum`. This is why enum constants have built-in properties, such as [name and ordinal](#access-enum-constants-and-their-properties). ## Working with enum constants Since enum constants are values, you can assign them to variables, print them, pass them to functions, compare them, and use them in `when` expressions. ### Declare enum constants To declare enum constants, first define properties in the enum class constructor and then pass values to each enum constant in parentheses. Unlike some other languages, Kotlin doesn't use assignment syntax, for example `RED = "#FF0000"`. Enum constants can have associated values of any type. Strings and numbers are common examples, but you can also use other types, such as `Boolean`, another enum class, or a custom class. Consider the `Color` enum class that stores a hexadecimal color code for each color: ```KOTLIN enum class Color(val hex: String) { RED("#FF0000"), GREEN("#00FF00"), BLUE("#0000FF") } ``` The value passed to each enum constant must match the constructor parameter type. Here, `hex` is a string property of the `Color` enum class. Each enum constant passes its own string value for this property. You can also associate numeric values with enum constants. For example, declare the `Int` type in the constructor and provide an `Int` value for each enum constant: ```KOTLIN enum class Priority(val level: Int) { LOW(0), MEDIUM(1), HIGH(2) } ``` ### Access enum constants and their properties You can access an enum constant through the enum class name. To access a property associated with an enum constant, use the dot notation, such as `color.hex` or `Color.GREEN.hex`: ```KOTLIN enum class Color(val hex: String) { RED("#FF0000"), GREEN("#00FF00"), BLUE("#0000FF") } fun main() { val color: Color = Color.RED println(color) // RED println(color.hex) // #FF0000 println(Color.GREEN.hex) // #00FF00 } ``` Here, `Color.RED` is an enum constant of the `Color` type. The color variable stores this enum constant. Besides any properties you define, every enum constant also has the built-in `name` and `ordinal` properties for getting its name and position (starting from `0`) in the enum class declaration: ```KOTLIN enum class RGB { RED, GREEN, BLUE } fun main() { println(RGB.RED.name) // RED println(RGB.RED.ordinal) // 0 } ``` ### Pass enum constants to functions Because enum constants are values, you can pass them to functions. This way, a function accepts only the fixed set of options defined in the enum class, ensuring type-safe code: ```KOTLIN enum class Color(val hex: String) { RED("#FF0000"), GREEN("#00FF00"), BLUE("#0000FF") } //sampleStart fun printColor(color: Color) { println("Color: $color") println("Hex code: ${color.hex}") } fun main() { printColor(Color.BLUE) // Color: BLUE // Hex code: #0000FF } //sampleEnd ``` Here, the `printColor()` function accepts a value of type `Color`, so you can pass any `Color` enum constant to it. Although enum constants behave like singleton objects, the compiler treats them as values of the enum class type. You can use the enum class name itself as a type, but you can't use enum constants as enum types: ```KOTLIN enum class Color { RED, GREEN, BLUE } fun printColor(color: Color) { println(color) } fun printRed(color: Color.RED) { println(color) // Error: enum entry cannot be used as a type } ``` ### Use enum constants in `when` expressions Enum classes work best with `when` expressions when you want to handle each constant separately: ```KOTLIN enum class Color(val hex: String) { RED("#FF0000"), GREEN("#00FF00"), BLUE("#0000FF") } //sampleStart fun describeColor(color: Color): String { return when (color) { Color.RED -> "Red is a warm color" Color.GREEN -> "Green is a natural color" Color.BLUE -> "Blue is a cool color" } } fun main() { println(describeColor(Color.RED)) // Red is a warm color } //sampleEnd ``` When you use all enum constants in a when expression, you don't need an `else` branch. Tip: To reduce repetition when working with enum entries, try context-sensitive resolution (currently in preview). This feature allows you to omit the enum class name when the expected type is known, such as in `when` expressions or when assigning to a typed variable. For more information, see [Preview of context-sensitive resolution](whatsnew22.html#preview-of-context-sensitive-resolution) or the related [KEEP proposal](https://github.com/Kotlin/KEEP/blob/improved-resolution-expected-type/proposals/context-sensitive-resolution.md). ### Find enum constants Sometimes you need to get an enum constant from a string, an index, or one of its associated values. Kotlin provides built-in APIs to look up constants by name, position, or custom values. For example, consider an enum class where each color has an associated RGB value. To find an enum constant by its name, use the `valueOf()` function: ```KOTLIN enum class Color(val rgb: Int) { RED(0xFF0000), GREEN(0x00FF00), BLUE(0x0000FF) } fun main() { val color = Color.valueOf("RED") println(color) // RED } ``` The name passed to `valueOf()` must match the enum constant name exactly. If there is no enum constant with the specified name, `valueOf()` throws an `IllegalArgumentException`. To find an enum constant by its position in the enum declaration, use the [getOrNull()](https://kotlinlang.org/api/core/kotlin-stdlib/kotlin.collections/get-or-null.html) function on the enum's `entries` property: ```KOTLIN enum class Color(val rgb: Int) { RED(0xFF0000), GREEN(0x00FF00), BLUE(0x0000FF) } //sampleStart fun main() { val color = Color.entries.getOrNull(0) println(color) // RED } //sampleEnd ``` Enum positions start from `0`. In this example, `RED` has the position `0`, `GREEN` is at `1`, and `BLUE` is at `2`. This is useful when you have an integer, for example from a file or user input, that represents an enum constant position. Unlike some other languages, Kotlin doesn't let you cast an `Int` directly to an enum constant. Instead, use the integer as an index and look up the constant with `entries.getOrNull(index)`. If the integer represents a value that should remain stable even if you reorder the enum constants, define an explicit numeric property, for example, `rgb` or `code` and search for the constant with the matching value. Since `entries` is a specialized `List`, you can use standard collection APIs with it. For example, to find an enum constant by an associated value, search through entries using [first()](https://kotlinlang.org/api/core/kotlin-stdlib/kotlin.collections/first.html): ```KOTLIN enum class Color(val rgb: Int) { RED(0xFF0000), GREEN(0x00FF00), BLUE(0x0000FF) } //sampleStart fun main() { val color = Color.entries.first { it.rgb == 0xFF0000 } println(color) // RED } //sampleEnd ``` The `first()` function throws a `NoSuchElementException` if no matching constant is found. To get `null` instead, use [firstOrNull()](https://kotlinlang.org/api/core/kotlin-stdlib/kotlin.collections/first-or-null.html). To get the number of enum constants, use the [size](https://kotlinlang.org/api/core/kotlin-stdlib/kotlin.collections/-list/size.html) property. For example: ```KOTLIN enum class RGB { RED, GREEN, BLUE } fun main() { println(RGB.entries) // [RED, GREEN, BLUE] println(RGB.entries.size) // 3 println("The first color is: ${RGB.valueOf("RED")}") // "The first color is: RED" } ``` If you often need to look up enum constants by name, position, or associated value, add helper functions in a [companion object](object-declarations.html#companion-objects): ```KOTLIN enum class Color(val rgb: Int) { RED(0xFF0000), GREEN(0x00FF00), BLUE(0x0000FF); companion object { fun fromName(name: String): Color? = entries.find { it.name == name } fun fromPosition(position: Int): Color? = entries.getOrNull(position) fun fromRgb(rgb: Int): Color? = entries.find { it.rgb == rgb } } } fun main() { println(Color.fromName("RED")) // RED println(Color.fromPosition(1)) // GREEN println(Color.fromRgb(0x0000FF)) // BLUE println(Color.fromRgb(0xABCDEF)) // null } ``` Companion object helper functions are useful when you want safe lookups that return `null` instead of throwing an exception. The lookup APIs used above, such as `entries` and `valueOf()`, are examples of synthetic members. In this context, synthetic means that Kotlin provides these members automatically, even though you don't declare them yourself. This is why every enum class can list its constants with the `entries` property and get a constant by name with the `valueOf()` function without the need to write extra code. You can access the constants in an enum class using generic helper functions such as [enumEntries<T>()](https://kotlinlang.org/api/core/kotlin-stdlib/kotlin.enums/enum-entries.html) and [enumValueOf<T>()](https://kotlinlang.org/api/core/kotlin-stdlib/kotlin/enum-value-of.html). These functions use [reified type parameters](inline-functions.html#reified-type-parameters). Such parameters keep the actual enum type available inside a generic inline function, so the helper functions can work with the enum type `T` directly: | Function |Description | ------------------------- | [enumEntries<T>()](https://kotlinlang.org/api/core/kotlin-stdlib/kotlin.enums/enum-entries.html) |(Recommended) Returns all enum entries of the enum type `T`. Every call returns the same list. | | [enumValues<T>()](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/enum-values.html) |Returns an array with all enum entries of the enum type `T`. Every call `enumValues()` creates a new array. | | [enumValueOf<T>()](https://kotlinlang.org/api/core/kotlin-stdlib/kotlin/enum-value-of.html) |Returns a single enum entry by its name, throwing an `IllegalArgumentException` if no enum entry matches. | For example: ```KOTLIN import kotlin.enums.enumEntries enum class RGB { RED, GREEN, BLUE } inline fun > printAllValues() { println(enumEntries().joinToString { it.name }) } inline fun > findByName(name: String): T = enumValueOf(name) fun main() { printAllValues() // RED, GREEN, BLUE println(findByName("GREEN")) // GREEN } ``` For more information about inline functions and reified type parameters, see [Inline functions](inline-functions.html). ### Compare and sort enum constants Use the `==` [structural equality](equality.html#structural-equality) operator to compare enum constants: ```KOTLIN enum class Color(val hex: String) { RED("#FF0000"), GREEN("#00FF00"), BLUE("#0000FF") } //sampleStart fun main() { val color = Color.RED println(color == Color.RED) // true println(color == Color.BLUE) // false } //sampleEnd ``` Since each enum constant behaves like a singleton object, comparing enum constants checks whether both values refer to the same constant. All enum classes implement the [Comparable](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-comparable/index.html) interface by default, so you can compare and sort enum constants. Constants are ordered by their position in the enum declaration (their `ordinal` value), which means the constant declared first is considered the smallest: ```KOTLIN enum class Priority { LOW, MEDIUM, HIGH } fun main() { println(Priority.LOW < Priority.HIGH) // true println(Priority.HIGH > Priority.MEDIUM) // true } ``` Sorting follows the same declaration order. For example, `entries.sorted()` returns the constants in the order in which they are declared, regardless of their names: ```KOTLIN enum class Priority { HIGH, LOW, MEDIUM } fun main() { println(Priority.entries.sorted()) // [HIGH, LOW, MEDIUM] } ``` The `Enum` class provides the `compareTo()`, `equals()`, and `hashCode()` functions, and you can't override them to customize their behavior like in normal classes. Comparison always follows the declaration order. If you need a different order, don't rely on the declaration order. Instead, define an explicit property and sort by it. For example, sort colors by their brightness: ```KOTLIN enum class Color(val brightness: Int) { RED(1), GREEN(3), BLUE(2) } fun main() { println(Color.entries.sortedBy { it.brightness }) // [RED, BLUE, GREEN] } ``` For more information, see [Ordering](collection-ordering.html). ## Add functions to enum classes Just like properties, enum classes can have functions. You can add functions that are shared by all enum constants, combine them with properties, or define operator functions. ### Add functions shared by all constants To add behavior that every enum constant shares, define a function in the enum class body. If the enum class defines any members, separate the constant definitions from the member definitions with a semicolon: ```KOTLIN enum class Direction { NORTH, SOUTH, WEST, EAST; fun isVertical(): Boolean = this == NORTH || this == SOUTH } fun main() { println(Direction.NORTH.isVertical()) // true println(Direction.EAST.isVertical()) // false } ``` Every enum constant can call the shared function. Inside the function, `this` refers to the enum constant it's called on. You can combine constructor properties with functions to associate data with each constant and add behavior that uses that data: ```KOTLIN enum class Color(val hex: String) { RED("#FF0000"), GREEN("#00FF00"), BLUE("#0000FF"); fun describe(): String = "$name has hex code $hex" } fun main() { println(Color.RED.describe()) // RED has hex code #FF0000 } ``` Here, each constant stores its own `hex` value, and the shared `describe()` function uses both the built-in `name` property and the `hex` property. ### Add operator functions Enum classes can also define [operator functions](operator-overloading.html), so you can use enum constants with operators. For example, define the `not()` operator function to return the opposite direction with the `!` operator: ```KOTLIN enum class Direction { NORTH, SOUTH, WEST, EAST; operator fun not(): Direction = when (this) { NORTH -> SOUTH SOUTH -> NORTH WEST -> EAST EAST -> WEST } } fun main() { println(!Direction.NORTH) // SOUTH } ``` ## Use anonymous classes Enum constants can declare their own anonymous classes with their corresponding functions, as well as with overriding base functions. With anonymous classes, you write the class body directly after the enum constant name and Kotlin infers the enum class as the supertype. This is useful when you declare an abstract function in the enum class and require each constant to provide its own implementation. Each constant overrides the abstract function inside its own anonymous class: ```KOTLIN enum class ProtocolState { WAITING { override fun signal() = TALKING }, TALKING { override fun signal() = WAITING }; abstract fun signal(): ProtocolState } fun main() { var state = ProtocolState.WAITING println(state) // WAITING state = state.signal() println(state) // TALKING } ``` Here, each constant implements the abstract `signal()` function differently, so calling `signal()` returns a different next state depending on the constant. Although enum constants behave like singleton objects, the type of an enum constant is the enum class itself, not its own anonymous class. That's why you can't access members declared inside the body of an anonymous class: ```KOTLIN enum class ProtocolState { WAITING { val waitingMessage = "Waiting for a signal" override fun signal() = TALKING }, TALKING { override fun signal() = WAITING }; abstract fun signal(): ProtocolState } fun main() { println(ProtocolState.WAITING.waitingMessage) // Error: unresolved reference 'waitingMessage' } ``` To expose data or behavior for every constant, declare it in the enum class body, using an abstract member when each constant needs its own implementation. ## Implement interfaces in enum classes An enum class can implement an interface, but it cannot inherit from a class. You can provide a common implementation of the interface members for all enum constants or let each constant provide its own implementation in an anonymous class. To implement an interface, add it to the enum class declaration: ```KOTLIN import java.util.function.BinaryOperator import java.util.function.IntBinaryOperator //sampleStart enum class IntArithmetics : BinaryOperator, IntBinaryOperator { PLUS { override fun apply(t: Int, u: Int): Int = t + u }, TIMES { override fun apply(t: Int, u: Int): Int = t * u }; override fun applyAsInt(t: Int, u: Int) = apply(t, u) } //sampleEnd fun main() { val a = 13 val b = 31 for (f in IntArithmetics.entries) { println("$f($a, $b) = ${f.apply(a, b)}") } } ``` In this example, the `IntArithmetics` enum class implements two interfaces in the enum class declaration: `BinaryOperator` and `IntBinaryOperator`. Each constant can override interface members inside its own anonymous class body, as `PLUS` and `TIMES` do for `apply()`, while `applyAsInt()` provides a shared implementation for all constants. # Inline value classes Sometimes it is useful to wrap a value in a class to create a more domain-specific type. However, it introduces runtime overhead due to additional heap allocations. Moreover, if the wrapped type is primitive, the performance hit is significant, because primitive types are usually heavily optimized by the runtime, while their wrappers don't get any special treatment. To solve such issues, Kotlin introduces a special kind of class called an inline class. Inline classes are a subset of [value-based classes](https://github.com/Kotlin/KEEP/blob/master/notes/value-classes.md). They don't have an identity and can only hold values. To declare an inline class, use the `value` modifier before the name of the class: ```KOTLIN value class Password(private val s: String) ``` To declare an inline class for the JVM backend, use the `value` modifier along with the `@JvmInline` annotation before the class declaration: ```KOTLIN // For JVM backends @JvmInline value class Password(private val s: String) ``` An inline class must have a single property initialized in the primary constructor. At runtime, instances of the inline class will be represented using this single property (see details about runtime representation [below](#representation)): ```KOTLIN // No actual instantiation of class 'Password' happens // At runtime 'securePassword' contains just 'String' val securePassword = Password("Don't try this in production") ``` This is the main feature of inline classes, which inspired the name inline: data of the class is inlined into its usages (similar to how the content of [inline functions](inline-functions.html) is inlined to call sites). ## Members Inline classes support some functionality of regular classes. In particular, they are allowed to declare properties and functions, have an `init` block and [secondary constructors](classes.html#secondary-constructors): ```KOTLIN @JvmInline value class Person(private val fullName: String) { init { require(fullName.isNotEmpty()) { "Full name shouldn't be empty" } } constructor(firstName: String, lastName: String) : this("$firstName $lastName") { require(lastName.isNotBlank()) { "Last name shouldn't be empty" } } val length: Int get() = fullName.length fun greet() { println("Hello, $fullName") } } fun main() { val name1 = Person("Kotlin", "Mascot") val name2 = Person("Kodee") name1.greet() // the `greet()` function is called as a static method println(name2.length) // property getter is called as a static method } ``` Inline class properties cannot have [backing fields](properties.html#backing-fields). They can only have simple computable properties (no `lateinit`/delegated properties). ## Inheritance Inline classes are allowed to inherit from interfaces: ```KOTLIN interface Printable { fun prettyPrint(): String } @JvmInline value class Name(val s: String) : Printable { override fun prettyPrint(): String = "Let's $s!" } fun main() { val name = Name("Kotlin") println(name.prettyPrint()) // Still called as a static method } ``` It is forbidden for inline classes to participate in a class hierarchy. This means that inline classes cannot extend other classes and are always `final`. ## Representation In generated code, the Kotlin compiler keeps a wrapper for each inline class. Inline class instances can be represented at runtime either as wrappers or as the underlying type. This is similar to how `Int` can be [represented](numbers.html#boxing-and-caching-numbers-on-the-jvm) either as a primitive `int` or as the wrapper `Integer`. The Kotlin compiler will prefer using underlying types instead of wrappers to produce the most performant and optimized code. However, sometimes it is necessary to keep wrappers around. As a rule of thumb, inline classes are boxed whenever they are used as another type. ```KOTLIN interface I @JvmInline value class Foo(val i: Int) : I fun asInline(f: Foo) {} fun asGeneric(x: T) {} fun asInterface(i: I) {} fun asNullable(i: Foo?) {} fun id(x: T): T = x fun main() { val f = Foo(42) asInline(f) // unboxed: used as Foo itself asGeneric(f) // boxed: used as generic type T asInterface(f) // boxed: used as type I asNullable(f) // boxed: used as Foo?, which is different from Foo // below, 'f' first is boxed (while being passed to 'id') and then unboxed (when returned from 'id') // In the end, 'c' contains unboxed representation (just '42'), as 'f' val c = id(f) } ``` Because inline classes may be represented both as the underlying value and as a wrapper, [referential equality](equality.html#referential-equality) is pointless for them and is therefore prohibited. Inline classes can also have a generic type parameter as the underlying type. In this case, the compiler maps it to `Any?` or, generally, to the upper bound of the type parameter. ```KOTLIN @JvmInline value class UserId(val value: T) fun compute(s: UserId) {} // compiler generates fun compute-(s: Any?) ``` ### Mangling Since inline classes are compiled to their underlying type, it may lead to various obscure errors, for example, unexpected platform signature clashes: ```KOTLIN @JvmInline value class UInt(val x: Int) // Represented as 'public final void compute(int x)' on the JVM fun compute(x: Int) { } // Also represented as 'public final void compute(int x)' on the JVM! fun compute(x: UInt) { } ``` To mitigate such issues, functions using inline classes are mangled by adding some stable hashcode to the function name. Therefore, `fun compute(x: UInt)` will be represented as `public final void compute-(int x)`, which solves the clash problem. ### Calling from Java code You can call functions that accept inline classes from Java code. To do so, you should manually disable mangling: add the `@JvmName` annotation before the function declaration: ```KOTLIN @JvmInline value class UInt(val x: Int) fun compute(x: Int) { } @JvmName("computeUInt") fun compute(x: UInt) { } ``` By default, Kotlin compiles inline classes using unboxed representations, which makes them difficult to access from Java. To learn how to compile inline classes into boxed representations that are accessible from Java, see the guide to [Calling Kotlin from Java](java-to-kotlin-interop.html#inline-value-classes). ## Inline classes vs type aliases At first sight, inline classes seem very similar to [type aliases](type-aliases.html). Indeed, both seem to introduce a new type and both will be represented as the underlying type at runtime. However, the crucial difference is that type aliases are assignment-compatible with their underlying type (and with other type aliases with the same underlying type), while inline classes are not. In other words, inline classes introduce a truly new type, contrary to type aliases which only introduce an alternative name (alias) for an existing type: ```KOTLIN typealias NameTypeAlias = String @JvmInline value class NameInlineClass(val s: String) fun acceptString(s: String) {} fun acceptNameTypeAlias(n: NameTypeAlias) {} fun acceptNameInlineClass(p: NameInlineClass) {} fun main() { val nameAlias: NameTypeAlias = "" val nameInlineClass: NameInlineClass = NameInlineClass("") val string: String = "" acceptString(nameAlias) // OK: pass alias instead of underlying type acceptString(nameInlineClass) // Not OK: can't pass inline class instead of underlying type // And vice versa: acceptNameTypeAlias(string) // OK: pass underlying type instead of alias acceptNameInlineClass(string) // Not OK: can't pass underlying type instead of inline class } ``` ## Inline classes and delegation Implementation by delegation to inlined value of inlined class is allowed with interfaces: ```KOTLIN interface MyInterface { fun bar() fun foo() = "foo" } @JvmInline value class MyInterfaceWrapper(val myInterface: MyInterface) : MyInterface by myInterface fun main() { val my = MyInterfaceWrapper(object : MyInterface { override fun bar() { // body } }) println(my.foo()) // prints "foo" } ``` # Nested and inner classes Classes can be nested in other classes: ```KOTLIN class Outer { private val bar: Int = 1 class Nested { fun foo() = 2 } } val demo = Outer.Nested().foo() // == 2 ``` You can also use interfaces with nesting. All combinations of classes and interfaces are possible: You can nest interfaces in classes, classes in interfaces, and interfaces in interfaces. ```KOTLIN interface OuterInterface { class InnerClass interface InnerInterface } class OuterClass { class InnerClass interface InnerInterface } ``` ## Inner classes A nested class marked as `inner` can access the members of its outer class. Inner classes carry a reference to an object of an outer class: ```KOTLIN class Outer { private val bar: Int = 1 inner class Inner { fun foo() = bar } } val demo = Outer().Inner().foo() // == 1 ``` See [Qualified this expressions](this-expressions.html) to learn about disambiguation of `this` in inner classes. ## Anonymous inner classes Anonymous inner class instances are created using an [object expression](object-declarations.html#object-expressions): ```KOTLIN window.addMouseListener(object : MouseAdapter() { override fun mouseClicked(e: MouseEvent) { ... } override fun mouseEntered(e: MouseEvent) { ... } }) ``` Note: On the JVM, if the object is an instance of a functional Java interface (that means a Java interface with a single abstract method), you can create it using a lambda expression prefixed with the type of the interface: ```KOTLIN val listener = ActionListener { println("clicked") } ``` # Functional (SAM) interfaces An interface with only one abstract member function is called a functional interface, or a Single Abstract Method (SAM) interface. The functional interface can have several non-abstract member functions but only one abstract member function. To declare a functional interface in Kotlin, use the `fun` modifier. ```KOTLIN fun interface KRunnable { fun invoke() } ``` ## SAM conversions For functional interfaces, you can use SAM conversions that help make your code more concise and readable by using [lambda expressions](lambdas.html#lambda-expressions-and-anonymous-functions). Instead of creating a class that implements a functional interface manually, you can use a lambda expression. With a SAM conversion, Kotlin can convert any lambda expression whose signature matches the signature of the interface's single method into the code, which dynamically instantiates the interface implementation. For example, consider the following Kotlin functional interface: ```KOTLIN fun interface IntPredicate { fun accept(i: Int): Boolean } ``` If you don't use a SAM conversion, you will need to write code like this: ```KOTLIN // Creating an instance of a class val isEven = object : IntPredicate { override fun accept(i: Int): Boolean { return i % 2 == 0 } } ``` By leveraging Kotlin's SAM conversion, you can write the following equivalent code instead: ```KOTLIN // Creating an instance using lambda val isEven = IntPredicate { it % 2 == 0 } ``` A short lambda expression replaces all the unnecessary code. ```KOTLIN fun interface IntPredicate { fun accept(i: Int): Boolean } val isEven = IntPredicate { it % 2 == 0 } fun main() { println("Is 7 even? - ${isEven.accept(7)}") } ``` You can also use [SAM conversions for Java interfaces](java-interop.html#sam-conversions). ## Migration from an interface with constructor function to a functional interface Starting from 1.6.20, Kotlin supports [callable references](reflection.html#callable-references) to functional interface constructors, which adds a source-compatible way to migrate from an interface with a constructor function to a functional interface. Consider the following code: ```KOTLIN interface Printer { fun print() } fun Printer(block: () -> Unit): Printer = object : Printer { override fun print() = block() } ``` With callable references to functional interface constructors enabled, this code can be replaced with just a functional interface declaration: ```KOTLIN fun interface Printer { fun print() } ``` Its constructor will be created implicitly, and any code using the `::Printer` function reference will compile. For example: ```KOTLIN documentsStorage.addPrinter(::Printer) ``` Preserve the binary compatibility by marking the legacy function `Printer` with the [@Deprecated](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-deprecated/) annotation with `DeprecationLevel.HIDDEN`: ```KOTLIN @Deprecated(message = "Your message about the deprecation", level = DeprecationLevel.HIDDEN) fun Printer(...) {...} ``` ## Functional interfaces vs. type aliases You can also simply rewrite the above using a [type alias](type-aliases.html) for a functional type: ```KOTLIN typealias IntPredicate = (i: Int) -> Boolean val isEven: IntPredicate = { it % 2 == 0 } fun main() { println("Is 7 even? - ${isEven(7)}") } ``` However, functional interfaces and [type aliases](type-aliases.html) serve different purposes. Type aliases are just names for existing types – they don't create a new type, while functional interfaces do. You can provide extensions that are specific to a particular functional interface to be inapplicable for plain functions or their type aliases. Type aliases can have only one member, while functional interfaces can have multiple non-abstract member functions and one abstract member function. Functional interfaces can also implement and extend other interfaces. Functional interfaces are more flexible and provide more capabilities than type aliases, but they can be more costly both syntactically and at runtime because they can require conversions to a specific interface. When you choose which one to use in your code, consider your needs: * If your API needs to accept a function (any function) with some specific parameter and return types – use a simple functional type or define a type alias to give a shorter name to the corresponding functional type. * If your API accepts a more complex entity than a function – for example, it has non-trivial contracts and/or operations on it that can't be expressed in a functional type's signature – declare a separate functional interface for it. # Properties In Kotlin, properties let you store and manage data without writing functions to access or change the data. You can use properties in [classes](classes.html), [interfaces](interfaces.html), [objects](object-declarations.html), [companion objects](object-declarations.html#companion-objects), and even outside these structures as top-level properties. Every property has a name, a type, and an automatically generated `get()` function called a getter. You can use the getter to read the property's value. If the property is mutable, it also has a `set()` function called a setter, which allows you to change the property's value. Tip: Getters and setters are called accessors. ## Declaring properties Properties can be mutable (`var`) or read-only (`val`). You can declare them as a top-level property in a `.kt` file. Think of a top-level property as a global variable that belongs to a package: ```KOTLIN // File: Constants.kt package my.app val pi = 3.14159 var counter = 0 ``` You can also declare properties inside a class, interface, or object: ```KOTLIN // Class with properties class Address { var name: String = "Holmes, Sherlock" var street: String = "Baker" var city: String = "London" } // Interface with a property interface ContactInfo { val email: String } // Object with properties object Company { var name: String = "Detective Inc." val country: String = "UK" } // Class implementing the interface class PersonContact : ContactInfo { override val email: String = "sherlock@example.com" } ``` To use a property, refer to it by its name: ```KOTLIN class Address { var name: String = "Holmes, Sherlock" var street: String = "Baker" var city: String = "London" } interface ContactInfo { val email: String } object Company { var name: String = "Detective Inc." val country: String = "UK" } class PersonContact : ContactInfo { override val email: String = "sherlock@example.com" } //sampleStart fun copyAddress(address: Address): Address { val result = Address() // Accesses properties in the result instance result.name = address.name result.street = address.street result.city = address.city return result } fun main() { val sherlockAddress = Address() val copy = copyAddress(sherlockAddress) // Accesses properties in the copy instance println("Copied address: ${copy.name}, ${copy.street}, ${copy.city}") // Copied address: Holmes, Sherlock, Baker, London // Accesses properties in the Company object println("Company: ${Company.name} in ${Company.country}") // Company: Detective Inc. in UK val contact = PersonContact() // Access properties in the contact instance println("Email: ${contact.email}") // Email: sherlock@email.com } //sampleEnd ``` In Kotlin, we recommend initializing properties when you declare them to keep your code safe and easy to read. However, you can [initialize them later](#late-initialized-properties-and-variables) in special cases. Declaring the property type is optional if the compiler can infer it from the initializer or the getter's return type: ```KOTLIN var initialized = 1 // The inferred type is Int var allByDefault // ERROR: Property must be initialized. ``` ## Custom getters and setters By default, Kotlin automatically generates getters and setters. You can define your own custom accessors when you need extra logic, such as validation, formatting, or calculations based on other properties. A custom getter runs every time the property is accessed: ```KOTLIN //sampleStart class Rectangle(val width: Int, val height: Int) { val area: Int get() = this.width * this.height } //sampleEnd fun main() { val rectangle = Rectangle(3, 4) println("Width=${rectangle.width}, height=${rectangle.height}, area=${rectangle.area}") } ``` You can omit the type if the compiler can infer it from the getter: ```KOTLIN val area get() = this.width * this.height ``` A custom setter runs every time you assign a value to the property, except during initialization. By convention, the name of the setter parameter is `value`, but you can choose a different name: ```KOTLIN class Point(var x: Int, var y: Int) { var coordinates: String get() = "$x,$y" set(value) { val parts = value.split(",") x = parts[0].toInt() y = parts[1].toInt() } } fun main() { val location = Point(1, 2) println(location.coordinates) // 1,2 location.coordinates = "10,20" println("${location.x}, ${location.y}") // 10, 20 } ``` ### Changing visibility or adding annotations In Kotlin, you can change accessor visibility or add [annotations](annotations.html) without replacing the default implementation. You don't have to make these changes within a body `{}`. To change the visibility of an accessor, use the modifier before the `get` or `set` keyword: ```KOTLIN class BankAccount(initialBalance: Int) { var balance: Int = initialBalance // Only the class can modify the balance private set fun deposit(amount: Int) { if (amount > 0) balance += amount } fun withdraw(amount: Int) { if (amount > 0 && amount <= balance) balance -= amount } } fun main() { val account = BankAccount(100) println("Initial balance: ${account.balance}") // 100 account.deposit(50) println("After deposit: ${account.balance}") // 150 account.withdraw(70) println("After withdrawal: ${account.balance}") // 80 // account.balance = 1000 // Error: cannot assign because setter is private } ``` To annotate an accessor, use the annotation before the `get` or `set` keyword: ```KOTLIN // Defines an annotation that can be applied to a getter @Target(AnnotationTarget.PROPERTY_GETTER) annotation class Inject class Service { var dependency: String = "Default Service" // Annotates the getter @Inject get } fun main() { val service = Service() println(service.dependency) // Default service println(service::dependency.getter.annotations) // [@Inject()] println(service::dependency.setter.annotations) // [] } ``` This example uses [reflection](reflection.html) to show which annotations are present on the getter and setter. ## Backing fields The compiler automatically generates backing fields for properties when a value needs to be stored in memory. For example, the compiler creates a backing field when you use the default `get()` and `set()` functions because they read and write the stored value: ```KOTLIN var count = 0 ``` You can access backing fields by using the `field` keyword in a [custom get() or set() function](#custom-getters-and-setters). For example, you can add extra logic to a getter or setter, or trigger an additional action when a property changes. In this example, the `score` property uses the backing field inside the `set()` function so that updating the value also triggers a log event: ```KOTLIN class Scoreboard { var score: Int = 0 set(value) { field = value // Adds logging when updating the value println("Score updated to $field") } } fun main() { val board = Scoreboard() board.score = 10 // Score updated to 10 board.score = 20 // Score updated to 20 } ``` Backing fields aren't created by default for all properties because they might not need them. For example, the `isEmpty` property doesn't have a backing field because the value is calculated from the `size` property each time you access it: ```KOTLIN val isEmpty: Boolean get() = this.size == 0 ``` ### Explicit backing fields Sometimes you might need more flexibility. For example, if you have an API where you want to be able to modify the property internally but not externally. In such cases, you can use an explicit backing field. In the following example, the `ShoppingCart` class has an `items` property that represents everything in the shopping cart. The class exposes the `items` property as a read-only list of strings, but internally it stores the data in a mutable list with an explicit backing field: ```KOTLIN class ShoppingCart { // Public read-only view with explicit backing field val items: List field = mutableListOf() fun addItem(item: String) { items.add(item) } fun removeItem(item: String) { items.remove(item) } } fun main() { val cart = ShoppingCart() cart.addItem("Apple") cart.addItem("Banana") println(cart.items) // [Apple, Banana] cart.removeItem("Apple") println(cart.items) // [Banana] } ``` In this example, the compiler infers the type of the backing field from the `mutableListOf()` call: `MutableList`. You can also declare the type of the backing field explicitly: ```KOTLIN val items: List // Explicit backing field with explicit type field: MutableList = mutableListOf() ``` In the example of the `ShoppingCart` class, the compiler smart casts the `items` property to the `MutableList` type, so the class can add and remove items from the cart through the `add()` and `remove()` functions. Outside the class, the compiler uses the public property type `List`, so API users can only read what's in the `items` list. #### Limitations To use explicit backing fields, their properties and the backing fields themselves must follow certain rules. Properties can have explicit backing fields only if they: * Don't have a custom getter. * Are read-only (`val`). * Aren't `open`. * Aren't a [delegated property](delegated-properties.html). * Aren't [compile-time constants](#compile-time-constants). In addition, the backing field type must be a subtype of the property's type and have [private visibility](visibility-modifiers.html). You can work around these restrictions by using backing properties instead. ### Backing properties If explicit backing fields don't fit your use case, you can try using a coding pattern called a backing property. For example, if your property needs a custom getter: ```KOTLIN class UserDirectory { private val _users = mutableListOf( "sarah", "mike", "emma" ) val users: List get() = _users.sorted() fun addUser(username: String) { _users.add(username) } } fun main() { val directory = UserDirectory() directory.addUser("alex") println(directory.users) // [alex, emma, mike, sarah] } ``` Tip: Use a leading underscore when naming backing properties to follow Kotlin [coding conventions](coding-conventions.html#names-for-backing-properties). In this example, the `UserDirectory` class has a read-only `users` property that lists every user in the directory. The `_users` variable is the private backing property containing the real list. The getter for the public `users` property sorts the entries before returning them. ## Compile-time constants If the value of a read-only property is known at compile time, mark it as a compile-time constant using the `const` modifier. Compile-time constants are inlined at compile time, so each reference is replaced with its actual value. They are accessed more efficiently because no getter is called: ```KOTLIN // File: AppConfig.kt package com.example // Compile-time constant const val MAX_LOGIN_ATTEMPTS = 3 ``` Compile-time constants must meet the following requirements: * They must be either a top-level property, or a member of an [object declaration](object-declarations.html#object-declarations-overview) or a [companion object](object-declarations.html#companion-objects). * They must be initialized with a value of type `String` or a [primitive type](types-overview.html). * They can't have a custom getter. Compile-time constants still have a backing field, so you can interact with them using [reflection](reflection.html). You can also use these properties in annotations: ```KOTLIN const val SUBSYSTEM_DEPRECATED: String = "This subsystem is deprecated" @Deprecated(SUBSYSTEM_DEPRECATED) fun processLegacyOrders() { ... } ``` ## Late-initialized properties and variables Normally, you must initialize properties in the constructor. However, this isn't always convenient. For example, you might initialize properties through dependency injection or inside the setup method of a unit test. To handle these situations, mark the property with the `lateinit` modifier: ```KOTLIN public class OrderServiceTest { lateinit var orderService: OrderService @SetUp fun setup() { orderService = OrderService() } @Test fun processesOrderSuccessfully() { // Calls orderService directly without checking for null // or initialization orderService.processOrder() } } ``` You can use the `lateinit` modifier on `var` properties declared as: * Top-level properties. * Local variables. * Properties inside the body of a class. For class properties: * You can't declare them in the primary constructor. * They must not have a custom getter or setter. In all cases, the property or variable must be non-nullable and must not be a [primitive type](types-overview.html). If you access a `lateinit` property before initializing it, Kotlin throws a specific exception that identifies the uninitialized property being accessed: ```KOTLIN class ReportGenerator { lateinit var report: String fun printReport() { // Throws an exception as it's accessed before // initialization println(report) } } fun main() { val generator = ReportGenerator() generator.printReport() // Exception in thread "main" kotlin.UninitializedPropertyAccessException: lateinit property report has not been initialized } ``` To check whether a `lateinit var` has already been initialized, use the [isInitialized](https://kotlinlang.org/api/core/kotlin-stdlib/kotlin/is-initialized.html) property on the [reference to that property](reflection.html#property-references): ```KOTLIN class WeatherStation { lateinit var latestReading: String fun printReading() { // Checks whether the property is initialized if (this::latestReading.isInitialized) { println("Latest reading: $latestReading") } else { println("No reading available") } } } fun main() { val station = WeatherStation() station.printReading() // No reading available station.latestReading = "22°C, sunny" station.printReading() // Latest reading: 22°C, sunny } ``` You can only use `isInitialized` on a property if you can already access that property in your code. The property must be declared in the same class, in an outer class, or as a top-level property in the same file. ## Overriding properties See [Overriding properties](inheritance.html#overriding-properties). ## Delegated properties To reuse logic and reduce code duplication, you can delegate the responsibility of getting and setting a property to a separate object. Delegating accessor behavior keeps the property's accessor logic centralized, making it easier to reuse. This approach is useful when implementing behaviors like: * Computing a value lazily. * Reading from a map by a given key. * Accessing a database. * Notifying a listener when a property is accessed. You can implement these common behaviors in libraries yourself or use existing delegates provided by external libraries. For more information, see [delegated properties](delegated-properties.html). # Delegated properties With some common kinds of properties, even though you can implement them manually every time you need them, it is more helpful to implement them once, add them to a library, and reuse them later. For example: * Lazy properties: the value is computed only on first access. * Observable properties: listeners are notified about changes to this property. * Storing properties in a map instead of a separate field for each property. To cover these (and other) cases, Kotlin supports delegated properties: ```KOTLIN class Example { var p: String by Delegate() } ``` The syntax is: `val/var : by `. The expression after `by` is a delegate, because the `get()` (and `set()`) that correspond to the property will be delegated to its `getValue()` and `setValue()` methods. Property delegates don't have to implement an interface, but they have to provide a `getValue()` function (and `setValue()` for `var`s). For example: ```KOTLIN import kotlin.reflect.KProperty class Delegate { operator fun getValue(thisRef: Any?, property: KProperty<*>): String { return "$thisRef, thank you for delegating '${property.name}' to me!" } operator fun setValue(thisRef: Any?, property: KProperty<*>, value: String) { println("$value has been assigned to '${property.name}' in $thisRef.") } } ``` When you read from `p`, which delegates to an instance of `Delegate`, the `getValue()` function from `Delegate` is called. Its first parameter is the object you read `p` from, and the second parameter holds a description of `p` itself (for example, you can take its name). ```KOTLIN val e = Example() println(e.p) ``` This prints: ``` Example@33a17727, thank you for delegating 'p' to me! ``` Similarly, when you assign to `p`, the `setValue()` function is called. The first two parameters are the same, and the third holds the value being assigned: ```KOTLIN e.p = "NEW" ``` This prints: ``` NEW has been assigned to 'p' in Example@33a17727. ``` The specification of the requirements for the delegated object can be found [below](#property-delegate-requirements). You can declare a delegated property inside a function or code block; it doesn't have to be a member of a class. Below you can find [an example](#local-delegated-properties). ## Standard delegates The Kotlin standard library provides factory methods for several useful kinds of delegates. ### Lazy properties [lazy()](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/lazy.html) is a function that takes a lambda and returns an instance of `Lazy`, which can serve as a delegate for implementing a lazy property. The first call to `get()` executes the lambda passed to `lazy()` and remembers the result. Subsequent calls to `get()` simply return the remembered result. ```KOTLIN val lazyValue: String by lazy { println("computed!") "Hello" } fun main() { println(lazyValue) println(lazyValue) } ``` By default, the evaluation of lazy properties is synchronized: the value is computed only in one thread, but all threads will see the same value. If the synchronization of the initialization delegate is not required to allow multiple threads to execute it simultaneously, pass `LazyThreadSafetyMode.PUBLICATION` as a parameter to `lazy()`. If you're sure that the initialization will always happen in the same thread as the one where you use the property, you can use `LazyThreadSafetyMode.NONE`. It doesn't incur any thread-safety guarantees and related overhead. ### Observable properties [Delegates.observable()](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.properties/-delegates/observable.html) takes two arguments: the initial value and a handler for modifications. The handler is called every time you assign to the property (after the assignment has been performed). It has three parameters: the property being assigned to, the old value, and the new value: ```KOTLIN import kotlin.properties.Delegates class User { var name: String by Delegates.observable("") { prop, old, new -> println("$old -> $new") } } fun main() { val user = User() user.name = "first" user.name = "second" } ``` If you want to intercept assignments and veto them, use [vetoable()](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.properties/-delegates/vetoable.html) instead of `observable()`. The handler passed to `vetoable` will be called before the assignment of a new property value. ## Delegating to another property A property can delegate its getter and setter to another property. Such delegation is available for both top-level and class properties (member and extension). The delegate property can be: * A top-level property * A member or an extension property of the same class * A member or an extension property of another class To delegate a property to another property, use the `::` qualifier in the delegate name, for example, `this::delegate` or `MyClass::delegate`. ```KOTLIN var topLevelInt: Int = 0 class ClassWithDelegate(val anotherClassInt: Int) class MyClass(var memberInt: Int, val anotherClassInstance: ClassWithDelegate) { var delegatedToMember: Int by this::memberInt var delegatedToTopLevel: Int by ::topLevelInt val delegatedToAnotherClass: Int by anotherClassInstance::anotherClassInt } var MyClass.extDelegated: Int by ::topLevelInt ``` This may be useful, for example, when you want to rename a property in a backward-compatible way: introduce a new property, annotate the old one with the `@Deprecated` annotation, and delegate its implementation. ```KOTLIN class MyClass { var newName: Int = 0 @Deprecated("Use 'newName' instead", ReplaceWith("newName")) var oldName: Int by this::newName } fun main() { val myClass = MyClass() // Notification: 'oldName: Int' is deprecated. // Use 'newName' instead myClass.oldName = 42 println(myClass.newName) // 42 } ``` ## Storing properties in a map One common use case is storing the values of properties in a map. This comes up often in applications for things like parsing JSON or performing other dynamic tasks. In this case, you can use the map instance itself as the delegate for a delegated property. ```KOTLIN class User(val map: Map) { val name: String by map val age: Int by map } ``` In this example, the constructor takes a map: ```KOTLIN val user = User(mapOf( "name" to "John Doe", "age" to 25 )) ``` Delegated properties take values from this map through string keys, which are associated with the names of properties: ```KOTLIN class User(val map: Map) { val name: String by map val age: Int by map } fun main() { val user = User(mapOf( "name" to "John Doe", "age" to 25 )) //sampleStart println(user.name) // Prints "John Doe" println(user.age) // Prints 25 //sampleEnd } ``` This also works for `var`'s properties if you use a `MutableMap` instead of a read-only `Map`: ```KOTLIN class MutableUser(val map: MutableMap) { var name: String by map var age: Int by map } ``` ## Local delegated properties You can declare local variables as delegated properties. For example, you can make a local variable lazy: ```KOTLIN fun example(computeFoo: () -> Foo) { val memoizedFoo by lazy(computeFoo) if (someCondition && memoizedFoo.isValid()) { memoizedFoo.doSomething() } } ``` The `memoizedFoo` variable will be computed on first access only. If `someCondition` fails, the variable won't be computed at all. ## Property delegate requirements For a read-only property (`val`), a delegate should provide an operator function `getValue()` with the following parameters: * `thisRef` must be the same type as, or a supertype of, the property owner (for extension properties, it should be the type being extended). * `property` must be of type `KProperty<*>` or its supertype. `getValue()` must return the same type as the property (or its subtype). ```KOTLIN class Resource class Owner { val valResource: Resource by ResourceDelegate() } class ResourceDelegate { operator fun getValue(thisRef: Owner, property: KProperty<*>): Resource { return Resource() } } ``` For a mutable property (`var`), a delegate has to additionally provide an operator function `setValue()` with the following parameters: * `thisRef` must be the same type as, or a supertype of, the property owner (for extension properties, it should be the type being extended). * `property` must be of type `KProperty<*>` or its supertype. * `value` must be of the same type as the property (or its supertype). ```KOTLIN class Resource class Owner { var varResource: Resource by ResourceDelegate() } class ResourceDelegate(private var resource: Resource = Resource()) { operator fun getValue(thisRef: Owner, property: KProperty<*>): Resource { return resource } operator fun setValue(thisRef: Owner, property: KProperty<*>, value: Any?) { if (value is Resource) { resource = value } } } ``` `getValue()` and/or `setValue()` functions can be provided either as member functions of the delegate class or as extension functions. The latter is handy when you need to delegate a property to an object that doesn't originally provide these functions. Both of the functions need to be marked with the `operator` keyword. You can create delegates as anonymous objects without creating new classes, by using the interfaces `ReadOnlyProperty` and `ReadWriteProperty` from the Kotlin standard library. They provide the required methods: `getValue()` is declared in `ReadOnlyProperty`; `ReadWriteProperty` extends it and adds `setValue()`. This means you can pass a `ReadWriteProperty` whenever a `ReadOnlyProperty` is expected. ```KOTLIN fun resourceDelegate(resource: Resource = Resource()): ReadWriteProperty = object : ReadWriteProperty { var curValue = resource override fun getValue(thisRef: Any?, property: KProperty<*>): Resource = curValue override fun setValue(thisRef: Any?, property: KProperty<*>, value: Resource) { curValue = value } } val readOnlyResource: Resource by resourceDelegate() // ReadWriteProperty as val var readWriteResource: Resource by resourceDelegate() ``` ## Translation rules for delegated properties Under the hood, the Kotlin compiler generates auxiliary properties for some kinds of delegated properties and then delegates to them. Note: For optimization purposes, the compiler [does not generate auxiliary properties in several cases](#optimized-cases-for-delegated-properties). Learn about the optimization on the example of [delegating to another property](#translation-rules-when-delegating-to-another-property). For example, for the property `prop` it generates the hidden property `prop$delegate`, and the code of the accessors simply delegates to this additional property: ```KOTLIN class C { var prop: Type by MyDelegate() } // this code is generated by the compiler instead: class C { private val prop$delegate = MyDelegate() var prop: Type get() = prop$delegate.getValue(this, this::prop) set(value: Type) = prop$delegate.setValue(this, this::prop, value) } ``` The Kotlin compiler provides all the necessary information about `prop` in the arguments: the first argument `this` refers to an instance of the outer class `C`, and `this::prop` is a reflection object of the `KProperty` type describing `prop` itself. ### Optimized cases for delegated properties The `$delegate` field will be omitted if a delegate is: * A referenced property: ```KOTLIN class C { private var impl: Type = ... var prop: Type by ::impl } ``` * A named object: ```KOTLIN object NamedObject { operator fun getValue(thisRef: Any?, property: KProperty<*>): String = ... } val s: String by NamedObject ``` * A final `val` property with a backing field and a default getter in the same module: ```KOTLIN val impl: ReadOnlyProperty = ... class A { val s: String by impl } ``` * A constant expression, enum entry, `this`, `null`. The example of `this`: ```KOTLIN class A { operator fun getValue(thisRef: Any?, property: KProperty<*>) ... val s by this } ``` ### Translation rules when delegating to another property When delegating to another property, the Kotlin compiler generates immediate access to the referenced property. This means that the compiler doesn't generate the field `prop$delegate`. This optimization helps save memory. Take the following code, for example: ```KOTLIN class C { private var impl: Type = ... var prop: Type by ::impl } ``` Property accessors of the `prop` variable invoke the `impl` variable directly, skipping the delegated property's `getValue`and `setValue` operators, and thus the `KProperty` reference object is not needed. For the code above, the compiler generates the following code: ```KOTLIN class C { private var impl: Type = ... var prop: Type get() = impl set(value) { impl = value } fun getProp$delegate(): Type = impl // This method is needed only for reflection } ``` ## Providing a delegate By defining the `provideDelegate` operator, you can extend the logic for creating the object to which the property implementation is delegated. If the object used on the right-hand side of `by` defines `provideDelegate` as a member or extension function, that function will be called to create the property delegate instance. One of the possible use cases of `provideDelegate` is to check the consistency of the property upon its initialization. For example, to check the property name before binding, you can write something like this: ```KOTLIN class ResourceDelegate : ReadOnlyProperty { override fun getValue(thisRef: MyUI, property: KProperty<*>): T { ... } } class ResourceLoader(id: ResourceID) { operator fun provideDelegate( thisRef: MyUI, prop: KProperty<*> ): ReadOnlyProperty { checkProperty(thisRef, prop.name) // create delegate return ResourceDelegate() } private fun checkProperty(thisRef: MyUI, name: String) { ... } } class MyUI { fun bindResource(id: ResourceID): ResourceLoader { ... } val image by bindResource(ResourceID.image_id) val text by bindResource(ResourceID.text_id) } ``` The parameters of `provideDelegate` are the same as those of `getValue`: * `thisRef` must be the same type as, or a supertype of, the property owner (for extension properties, it should be the type being extended); * `property` must be of type `KProperty<*>` or its supertype. The `provideDelegate` method is called for each property during the creation of the `MyUI` instance, and it performs the necessary validation right away. Without this ability to intercept the binding between the property and its delegate, to achieve the same functionality you'd have to pass the property name explicitly, which isn't very convenient: ```KOTLIN // Checking the property name without "provideDelegate" functionality class MyUI { val image by bindResource(ResourceID.image_id, "image") val text by bindResource(ResourceID.text_id, "text") } fun MyUI.bindResource( id: ResourceID, propertyName: String ): ReadOnlyProperty { checkProperty(this, propertyName) // create delegate } ``` In the generated code, the `provideDelegate` method is called to initialize the auxiliary `prop$delegate` property. Compare the generated code for the property declaration `val prop: Type by MyDelegate()` with the generated code [above](#translation-rules-for-delegated-properties) (when the `provideDelegate` method is not present): ```KOTLIN class C { var prop: Type by MyDelegate() } // this code is generated by the compiler // when the 'provideDelegate' function is available: class C { // calling "provideDelegate" to create the additional "delegate" property private val prop$delegate = MyDelegate().provideDelegate(this, this::prop) var prop: Type get() = prop$delegate.getValue(this, this::prop) set(value: Type) = prop$delegate.setValue(this, this::prop, value) } ``` Note that the `provideDelegate` method affects only the creation of the auxiliary property and doesn't affect the code generated for the getter or the setter. With the `PropertyDelegateProvider` interface from the standard library, you can create delegate providers without creating new classes. ```KOTLIN val provider = PropertyDelegateProvider { thisRef: Any?, property -> ReadOnlyProperty {_, property -> 42 } } val delegate: Int by provider ``` # Null safety Null safety is a Kotlin feature designed to significantly reduce the risk of null references, also known as [The Billion-Dollar Mistake](https://en.wikipedia.org/wiki/Null_pointer#History). One of the most common pitfalls in many programming languages, including Java, is that accessing a member of a null reference results in a null reference exception. In Java, this would be the equivalent of a `NullPointerException`, or an NPE for short. Kotlin explicitly supports nullability as part of its type system, meaning you can explicitly declare which variables or properties are allowed to be `null`. Also, when you declare non-null variables, the compiler enforces that these variables cannot hold a `null` value, preventing an NPE. Kotlin's null safety ensures safer code by catching potential null-related issues at compile time rather than runtime. This feature improves code robustness, readability, and maintainability by explicitly expressing `null` values, making the code easier to understand and manage. The only possible causes of an NPE in Kotlin are: * An explicit call to [throw NullPointerException()](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-null-pointer-exception/). * Usage of the [not-null assertion operator !!](#not-null-assertion-operator). * Data inconsistency during initialization, such as when: * An uninitialized `this` available in a constructor is used somewhere else ([a "leaking this"](https://youtrack.jetbrains.com/issue/KTIJ-9751)). * A [superclass constructor calling an open member](inheritance.html#derived-class-initialization-order) whose implementation in the derived class uses an uninitialized state. * Java interoperation: * Attempts to access a member of a `null` reference of a [platform type](java-interop.html#null-safety-and-platform-types). * Nullability issues with generic types. For example, a piece of Java code adding `null` into a Kotlin `MutableList`, which would require `MutableList` to handle it properly. * Other issues caused by external Java code. Tip: Besides NPE, another exception related to null safety is [UninitializedPropertyAccessException](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-uninitialized-property-access-exception/). Kotlin throws this exception when you try to access a property that has not been initialized, ensuring that non-nullable properties are not used until they are ready. This typically happens with [lateinit properties](properties.html#late-initialized-properties-and-variables). ## Nullable types and non-nullable types In Kotlin, the type system distinguishes between types that can hold `null` (nullable types) and those that cannot (non-nullable types). For example, a regular variable of type `String` cannot hold `null`: ```KOTLIN fun main() { //sampleStart // Assigns a non-null string to a variable var a: String = "abc" // Attempts to re-assign null to the non-nullable variable a = null print(a) // Null can not be a value of a non-null type String //sampleEnd } ``` You can safely call a method or access a property on `a`. It's guaranteed not to cause an NPE because `a` is a non-nullable variable. The compiler ensures that `a` always holds a valid `String` value, so there's no risk of accessing its properties or methods when it's `null`: ```KOTLIN fun main() { //sampleStart // Assigns a non-null string to a variable val a: String = "abc" // Returns the length of a non-nullable variable val l = a.length print(l) // 3 //sampleEnd } ``` To allow `null` values, declare a variable with a `?` sign right after the variable type. For example, you can declare a nullable string by writing `String?`. This expression makes `String` a type that can accept `null`: ```KOTLIN fun main() { //sampleStart // Assigns a nullable string to a variable var b: String? = "abc" // Successfully re-assigns null to the nullable variable b = null print(b) // null //sampleEnd } ``` If you try accessing `length` directly on `b`, the compiler reports an error. This is because `b` is declared as a nullable variable and can hold `null` values. Attempting to access properties on nullables directly leads to an NPE: ```KOTLIN fun main() { //sampleStart // Assigns a nullable string to a variable var b: String? = "abc" // Re-assigns null to the nullable variable b = null // Tries to directly return the length of a nullable variable val l = b.length print(l) // Only safe (?.) or non-null asserted (!!.) calls are allowed on a nullable receiver of type String? //sampleEnd } ``` In the example above, the compiler requires you to use safe calls to check for nullability before accessing properties or performing operations. There are several ways to handle nullables: * [Check for null with the if conditional](#check-for-null-with-the-if-conditional) * [Safe call operator ?.](#safe-call-operator) * [Elvis operator ?:](#elvis-operator) * [Not-null assertion operator !!](#not-null-assertion-operator) * [Nullable receiver](#nullable-receiver) * [let function](#let-function) * [Safe casts as?](#safe-casts) * [Collections of a nullable type](#collections-of-a-nullable-type) Read the next sections for details and examples of `null` handling tools and techniques. ## Check for null with the if conditional When working with nullable types, you need to handle nullability safely to avoid an NPE. One way to handle this is checking for nullability explicitly with the `if` conditional expression. For example, check whether `b` is `null` and then access `b.length`: ```KOTLIN fun main() { //sampleStart // Assigns null to a nullable variable val b: String? = null // Checks for nullability first and then accesses length val l = if (b != null) b.length else -1 print(l) // -1 //sampleEnd } ``` In the example above, the compiler performs a [smart cast](typecasts.html#smart-casts) to change the type from nullable `String?` to non-nullable `String`. It also tracks the information about the check you performed and allows the call to `length` inside the `if` conditional. More complex conditions are supported as well: ```KOTLIN fun main() { //sampleStart // Assigns a nullable string to a variable val b: String? = "Kotlin" // Checks for nullability first and then accesses length if (b != null && b.length > 0) { print("String of length ${b.length}") // String of length 6 } else { // Provides alternative if the condition is not met print("Empty string") } //sampleEnd } ``` Note that the example above only works when the compiler can guarantee that `b` doesn't change between the check and its usage, same as the [smart cast prerequisites](typecasts.html#smart-cast-prerequisites). ## Safe call operator The safe call operator `?.` allows you to handle nullability safely in a shorter form. Instead of throwing an NPE, if the object is `null`, the `?.` operator simply returns `null`: ```KOTLIN fun main() { //sampleStart // Assigns a nullable string to a variable val a: String? = "Kotlin" // Assigns null to a nullable variable val b: String? = null // Checks for nullability and returns length or null println(a?.length) // 6 println(b?.length) // null //sampleEnd } ``` The `b?.length` expression checks for nullability and returns `b.length` if `b` is non-null, or `null` otherwise. The type of this expression is `Int?`. You can use the `?.` operator with both [var and val variables](basic-syntax.html#variables) in Kotlin: * A nullable `var` can hold a `null` (for example, `var nullableValue: String? = null`) or a non-null value (for example, `var nullableValue: String? = "Kotlin"`). If it's a non-null value, you can change it to `null` at any point. * A nullable `val` can hold a `null` (for example, `val nullableValue: String? = null`) or a non-null value (for example, `val nullableValue: String? = "Kotlin"`). If it's a non-null value, you cannot change it to `null` subsequently. Safe calls are useful in chains. For example, Bob is an employee who may be assigned to a department (or not). That department may, in turn, have another employee as a department head. To obtain the name of Bob's department head (if there is one), you write the following: ```KOTLIN bob?.department?.head?.name ``` This chain returns `null` if any of its properties are `null`. You can also place a safe call on the left side of an assignment: ```KOTLIN person?.department?.head = managersPool.getManager() ``` In the example above, if one of the receivers in the safe call chain is `null`, the assignment is skipped, and the expression on the right is not evaluated at all. For example, if either `person` or `person.department` is `null`, the function is not called. Here's the equivalent of the same safe call but with the `if` conditional: ```KOTLIN if (person != null && person.department != null) { person.department.head = managersPool.getManager() } ``` ## Elvis operator When working with nullable types, you can check for `null` and provide an alternative value. For example, if `b` is not `null`, access `b.length`. Otherwise, return an alternative value: ```KOTLIN fun main() { //sampleStart // Assigns null to a nullable variable val b: String? = null // Checks for nullability. If not null, returns length. If null, returns 0 val l: Int = if (b != null) b.length else 0 println(l) // 0 //sampleEnd } ``` Instead of writing the complete `if` expression, you can handle this in a more concise way with the Elvis operator `?:`: ```KOTLIN fun main() { //sampleStart // Assigns null to a nullable variable val b: String? = null // Checks for nullability. If not null, returns length. If null, returns a non-null value val l = b?.length ?: 0 println(l) // 0 //sampleEnd } ``` If the expression to the left of `?:` is not `null`, the Elvis operator returns it. Otherwise, the Elvis operator returns the expression to the right. The expression on the right-hand side is evaluated only if the left-hand side is `null`. Since `throw` and `return` are expressions in Kotlin, you can also use them on the right-hand side of the Elvis operator. This can be handy, for example, when checking function arguments: ```KOTLIN fun foo(node: Node): String? { // Checks for getParent(). If not null, it's assigned to parent. If null, returns null val parent = node.getParent() ?: return null // Checks for getName(). If not null, it's assigned to name. If null, throws exception val name = node.getName() ?: throw IllegalArgumentException("name expected") // ... } ``` ## Not-null assertion operator The not-null assertion operator `!!` converts any value to a non-nullable type. When you apply the `!!` operator to a variable whose value is not `null`, it's safely handled as a non-nullable type, and the code executes normally. However, if the value is `null`, the `!!` operator forces it to be treated as non-nullable, which results in an NPE. When `b` is not `null` and the `!!` operator makes it return its non-null value (which is a `String` in this example), it accesses `length` correctly: ```KOTLIN fun main() { //sampleStart // Assigns a nullable string to a variable val b: String? = "Kotlin" // Treats b as non-null and accesses its length val l = b!!.length println(l) // 6 //sampleEnd } ``` When `b` is `null` and the `!!` operator makes it return its non-null value, and an NPE occurs: ```KOTLIN fun main() { //sampleStart // Assigns null to a nullable variable val b: String? = null // Treats b as non-null and tries to access its length val l = b!!.length println(l) // Exception in thread "main" java.lang.NullPointerException //sampleEnd } ``` The `!!` operator is particularly useful when you are confident that a value is not `null` and there's no chance of getting an NPE, but the compiler cannot guarantee this due to certain rules. In such cases, you can use the `!!` operator to explicitly tell the compiler that the value is not `null`. ## Nullable receiver You can use extension functions with a [nullable receiver type](extensions.html#nullable-receivers), allowing these functions to be called on variables that might be `null`. By defining an extension function on a nullable receiver type, you can handle `null` values within the function itself instead of checking for `null` at every place where you call the function. For example, the [.toString()](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/to-string.html) extension function can be called on a nullable receiver. When invoked on a `null` value, it safely returns the string `"null"` without throwing an exception: ```KOTLIN //sampleStart fun main() { // Assigns null to a nullable Person object stored in the person variable val person: Person? = null // Applies .toString to the nullable person variable and prints a string println(person.toString()) // null } // Defines a simple Person class data class Person(val name: String) //sampleEnd ``` In the example above, even though `person` is `null`, the `.toString()` function safely returns the string `"null"`. This can be helpful for debugging and logging. If you expect the `.toString()` function to return a nullable string (either a string representation or `null`), use the [safe-call operator ?.](#safe-call-operator). The `?.` operator calls `.toString()` only if the object is not `null`, otherwise it returns `null`: ```KOTLIN //sampleStart fun main() { // Assigns a nullable Person object to a variable val person1: Person? = null val person2: Person? = Person("Alice") // Prints "null" if person is null; otherwise prints the result of person.toString() println(person1?.toString()) // null println(person2?.toString()) // Person(name=Alice) } // Defines a Person class data class Person(val name: String) //sampleEnd ``` The `?.` operator allows you to safely handle potential `null` values while still accessing properties or functions of objects that might be `null`. ## Let function To handle `null` values and perform operations only on non-null types, you can use the safe call operator `?.` together with the [let function](scope-functions.html#let). This combination is useful for evaluating an expression, check the result for `null`, and execute code only if it's not `null`, avoiding manual null checks: ```KOTLIN fun main() { //sampleStart // Declares a list of nullable strings val listWithNulls: List = listOf("Kotlin", null) // Iterates over each item in the list for (item in listWithNulls) { // Checks if the item is null and only prints non-null values item?.let { println(it) } //Kotlin } //sampleEnd } ``` ## Safe casts The regular Kotlin operator for [type casts](typecasts.html#unsafe-cast-operator) is the `as` operator. However, regular casts can result in an exception if the object is not of the target type. You can use the `as?` operator for safe casts. It tries to cast a value to the specified type and returns `null` if the value is not of that type: ```KOTLIN fun main() { //sampleStart // Declares a variable of type Any, which can hold any type of value val a: Any = "Hello, Kotlin!" // Safe casts to Int using the 'as?' operator val aInt: Int? = a as? Int // Safe casts to String using the 'as?' operator val aString: String? = a as? String println(aInt) // null println(aString) // "Hello, Kotlin!" //sampleEnd } ``` The code above prints `null` because `a` is not an `Int`, so the cast fails safely. It also prints `"Hello, Kotlin!"` because it matches the `String?` type, so the safe cast succeeds. ## Collections of a nullable type If you have a collection of nullable elements and want to keep only the non-null ones, use the `filterNotNull()` function: ```KOTLIN fun main() { //sampleStart // Declares a list containing some null and non-null integer values val nullableList: List = listOf(1, 2, null, 4) // Filters out null values, resulting in a list of non-null integers val intList: List = nullableList.filterNotNull() println(intList) // [1, 2, 4] //sampleEnd } ``` ## What's next? * Learn how to [handle nullability in Java and Kotlin](java-to-kotlin-nullability-guide.html). * Learn about generic types that are [definitely non-nullable](generics.html#definitely-non-nullable-types). # Equality In Kotlin, there are two types of equality: * Structural equality (`==`) - a check for the `equals()` function * Referential equality (`===`) - a check for two references pointing to the same object ## Structural equality Structural equality verifies if two objects have the same content or structure. Structural equality is checked by the `==` operation and its negated counterpart `!=`. By convention, an expression like `a == b` is translated to: ```KOTLIN a?.equals(b) ?: (b === null) ``` If `a` is not `null`, it calls the `equals(Any?)` function. Otherwise (`a` is `null`), it checks that `b` is referentially equal to `null`: ```KOTLIN fun main() { var a = "hello" var b = "hello" var c = null var d = null var e = d println(a == b) // true println(a == c) // false println(c == e) // true } ``` Note that there's no point in optimizing your code when comparing to `null` explicitly: `a == null` will be automatically translated to `a === null`. In Kotlin, the `equals()` function is inherited by all classes from the `Any` class. By default, the `equals()` function implements [referential equality](#referential-equality). However, classes in Kotlin can override the `equals()` function to provide a custom equality logic and, in this way, implement structural equality. Value classes and data classes are two specific Kotlin types that automatically override the `equals()` function. That's why they implement structural equality by default. However, in the case of data classes, if the `equals()` function is marked as `final` in the parent class, its behavior remains unchanged. Distinctly, non-data classes (those not declared with the `data` modifier) do not override the `equals()` function by default. Instead, non-data classes implement referential equality behavior inherited from the `Any` class. To implement structural equality, non-data classes require a custom equality logic to override the `equals()` function. To provide a custom equals check implementation, override the [equals(other: Any?): Boolean](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-any/equals.html) function: ```KOTLIN class Point(val x: Int, val y: Int) { override fun equals(other: Any?): Boolean { if (this === other) return true if (other !is Point) return false // Compares properties for structural equality return this.x == other.x && this.y == other.y } } ``` Note: When overriding the equals() function, you should also override the [hashCode() function](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-any/hash-code.html) to keep consistency between equality and hashing and ensure the proper behavior of these functions. Functions with the same name and other signatures (like `equals(other: Foo)`) don't affect equality checks with the operators `==` and `!=`. Structural equality has nothing to do with comparison defined by the `Comparable<...>` interface, so only a custom `equals(Any?)` implementation may affect the behavior of the operator. ## Referential equality Referential equality verifies the memory addresses of two objects to determine if they are the same instance. Referential equality is checked by the `===` operation and its negated counterpart `!==`. `a === b` evaluates to true if and only if `a` and `b` point to the same object: ```KOTLIN fun main() { var a = "Hello" var b = a var c = "world" var d = "world" println(a === b) // true println(a === c) // false println(c === d) // true } ``` For values represented by primitive types at runtime (for example, `Int`), the `===` equality check is equivalent to the `==` check. Tip: The referential equality is implemented differently in Kotlin/JS. For more information about equality, see the [Kotlin/JS](js-interop.html#equality) documentation. ## Floating-point numbers equality When the operands of an equality check are statically known to be `Float` or `Double` (nullable or not), the check follows the [IEEE 754 Standard for Floating-Point Arithmetic](https://en.wikipedia.org/wiki/IEEE_754). The behavior is different for operands that are not statically typed as floating-point numbers. In these cases, structural equality is implemented. As a result, checks with operands not statically typed as floating-point numbers differ from the IEEE standard. In this scenario: * `NaN` is equal to itself * `NaN` is greater than any other element (including `POSITIVE_INFINITY`) * `-0.0` is not equal to `0.0` For more information, see [Floating-point numbers comparison](numbers.html#floating-point-number-comparison). ## Array equality To compare whether two arrays have the same elements in the same order, use [contentEquals()](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.collections/content-equals.html). For more information, see [Compare arrays](arrays.html#compare-arrays). # Generics: in, out, where Classes in Kotlin can have type parameters, just like in Java: ```KOTLIN class Box(t: T) { var value = t } ``` To create an instance of such a class, simply provide the type arguments: ```KOTLIN val box: Box = Box(1) ``` If the compiler can infer the type arguments, for example, from the constructor arguments, you don’t need to specify them explicitly: ```KOTLIN val box = Box(1) // 1 has type Int, so the compiler figures out that it is Box ``` ## Variance One of the trickiest aspects of Java's type system is the wildcard types (see [Java Generics FAQ](http://www.angelikalanger.com/GenericsFAQ/JavaGenericsFAQ.html)). Kotlin doesn't have these. Instead, Kotlin has declaration-site variance and type projections. ### Variance and wildcards in Java Let's think about why Java needs these mysterious wildcards. First, generic types in Java are invariant, meaning that `List` is not a subtype of `List`. If `List` were not invariant, it would have been no better than Java's arrays, as the following code would have compiled but caused an exception at runtime: ```JAVA // Java List strs = new ArrayList(); // Java reports a type mismatch here at compile-time. List objs = strs; // What if it didn't? // We would be able to put an Integer into a list of Strings. objs.add(1); // And then at runtime, Java would throw // a ClassCastException: Integer cannot be cast to String String s = strs.get(0); ``` Java prohibits such things to guarantee runtime safety. But this has implications. For example, consider the `addAll()` method from the `Collection` interface. What's the signature of this method? Intuitively, you'd write it this way: ```JAVA // Java interface Collection ... { void addAll(Collection items); } ``` But then, you would not be able to do the following (which is perfectly safe): ```JAVA // Java // The following would not compile with the naive declaration of addAll: // Collection is not a subtype of Collection void copyAll(Collection to, Collection from) { to.addAll(from); } ``` That's why the actual signature of `addAll()` is the following: ```JAVA // Java interface Collection ... { void addAll(Collection items); } ``` The wildcard type argument `? extends E` indicates that this method accepts a collection of objects of `E` or a subtype of `E`, not just `E` itself. This means that you can safely read `E`'s from items (elements of this collection are instances of a subclass of E), but cannot write to it as you don't know what objects comply with that unknown subtype of `E`. In return for this limitation, you get the desired behavior: `Collection` is a subtype of `Collection`. In other words, the wildcard with an extends-bound (upper bound) makes the type covariant. The key to understanding why this works is rather simple: if you can only take items from a collection, then using a collection of `String`s and reading `Object`s from it is fine. Conversely, if you can only put items into the collection, it's okay to take a collection of `Object`s and put `String`s into it: in Java there is `List`, which accepts `String`s or any of its supertypes. The latter is called contravariance, and you can only call methods that take `String` as an argument on `List` (for example, you can call `add(String)` or `set(int, String)`). If you call something that returns `T` in `List`, you don't get a `String`, but rather an `Object`. Joshua Bloch, in his book [Effective Java, 3rd Edition](http://www.oracle.com/technetwork/java/effectivejava-136174.html), explains the problem well (Item 31: "Use bounded wildcards to increase API flexibility"). He gives the name Producers to objects you only read from and Consumers to those you only write to. He recommends: Tip: "For maximum flexibility, use wildcard types on input parameters that represent producers or consumers." He then proposes the following mnemonic: PECS stands for Producer-Extends, Consumer-Super. Note: If you use a producer-object, say, `List`, you are not allowed to call `add()` or `set()` on this object, but this does not mean that it is immutable: for example, nothing prevents you from calling `clear()` to remove all the items from the list, since `clear()` does not take any parameters at all. The only thing guaranteed by wildcards (or other types of variance) is type safety. Immutability is a completely different story. ### Declaration-site variance Let's suppose that there is a generic interface `Source` that does not have any methods that take `T` as a parameter, only methods that return `T`: ```JAVA // Java interface Source { T nextT(); } ``` Then, it would be perfectly safe to store a reference to an instance of `Source` in a variable of type `Source` - there are no consumer-methods to call. But Java does not know this, and still prohibits it: ```JAVA // Java void demo(Source strs) { Source objects = strs; // !!! Not allowed in Java // ... } ``` To fix this, you should declare objects of type `Source`. Doing so is meaningless, because you can call all the same methods on such a variable as before, so there's no value added by the more complex type. But the compiler does not know that. In Kotlin, there is a way to explain this sort of thing to the compiler. This is called declaration-site variance: you can annotate the type parameter `T` of `Source` to make sure that it is only returned (produced) from members of `Source`, and never consumed. To do this, use the `out` modifier: ```KOTLIN interface Source { fun nextT(): T } fun demo(strs: Source) { val objects: Source = strs // This is OK, since T is an out-parameter // ... } ``` The general rule is this: when a type parameter `T` of a class `C` is declared `out`, it may occur only in the out-position in the members of `C`, but in return `C` can safely be a supertype of `C`. In other words, you can say that the class `C` is covariant in the parameter `T`, or that `T` is a covariant type parameter. You can think of `C` as being a producer of `T`'s, and NOT a consumer of `T`'s. The `out` modifier is called a variance annotation, and since it is provided at the type parameter declaration site, it provides declaration-site variance. This is in contrast with Java's use-site variance where wildcards in the type usages make the types covariant. In addition to `out`, Kotlin provides a complementary variance annotation: `in`. It makes a type parameter contravariant, meaning it can only be consumed and never produced. A good example of a contravariant type is `Comparable`: ```KOTLIN interface Comparable { operator fun compareTo(other: T): Int } fun demo(x: Comparable) { x.compareTo(1.0) // 1.0 has type Double, which is a subtype of Number // Thus, you can assign x to a variable of type Comparable val y: Comparable = x // OK! } ``` The words in and out seem to be self-explanatory (as they've already been used successfully in C# for quite some time), and so the mnemonic mentioned above is not really needed. It can in fact be rephrased at a higher level of abstraction: [The Existential](https://en.wikipedia.org/wiki/Existentialism) Transformation: Consumer in, Producer out! :-) ## Type projections ### Use-site variance: type projections It is very easy to declare a type parameter `T` as `out` and avoid trouble with subtyping on the use site, but some classes can't actually be restricted to only return `T`'s! A good example of this is `Array`: ```KOTLIN class Array(val size: Int) { operator fun get(index: Int): T { ... } operator fun set(index: Int, value: T) { ... } } ``` This class can be neither co- nor contravariant in `T`. And this imposes certain inflexibilities. Consider the following function: ```KOTLIN fun copy(from: Array, to: Array) { assert(from.size == to.size) for (i in from.indices) to[i] = from[i] } ``` This function is supposed to copy items from one array to another. Let's try to apply it in practice: ```KOTLIN val ints: Array = arrayOf(1, 2, 3) val any = Array(3) { "" } copy(ints, any) // ^ type is Array but Array was expected ``` Here you run into the same familiar problem: `Array` is invariant in `T`, and so neither `Array` nor `Array` is a subtype of the other. Why not? Again, this is because `copy` could have an unexpected behavior, for example, it may attempt to write a `String` to `from`, and if you actually pass an array of `Int` there, a `ClassCastException` will be thrown later. To prohibit the `copy` function from writing to `from`, you can do the following: ```KOTLIN fun copy(from: Array, to: Array) { ... } ``` This is type projection, which means that `from` is not a simple array, but is rather a restricted (projected) one. You can only call methods that return the type parameter `T`, which in this case means that you can only call `get()`. This is our approach to use-site variance, and it corresponds to Java's `Array` while being slightly simpler. You can project a type with `in` as well: ```KOTLIN fun fill(dest: Array, value: String) { ... } ``` `Array` corresponds to Java's `Array`. This means that you can pass an array of `String`, `CharSequence`, or `Object` to the `fill()` function. ### Star-projections Sometimes you want to say that you know nothing about the type argument, but you still want to use it in a safe way. The safe way here is to define such a projection of the generic type, that every concrete instantiation of that generic type will be a subtype of that projection. Kotlin provides so-called star-projection syntax for this: * For `Foo`, where `T` is a covariant type parameter with the upper bound `TUpper`, `Foo<*>` is equivalent to `Foo`. This means that when the `T` is unknown, you can safely read values of `TUpper` from `Foo<*>`. * For `Foo`, where `T` is a contravariant type parameter, `Foo<*>` is equivalent to `Foo`. This means there is nothing you can write to `Foo<*>` in a safe way when `T` is unknown. * For `Foo`, where `T` is an invariant type parameter with the upper bound `TUpper`, `Foo<*>` is equivalent to `Foo` for reading values and to `Foo` for writing values. If a generic type has several type parameters, each of them can be projected independently. For example, if the type is declared as `interface Function` you could use the following star-projections: * `Function<*, String>` means `Function`. * `Function` means `Function`. * `Function<*, *>` means `Function`. Note: Star-projections are very much like Java's raw types, but safe. ### Captured types When you use a type projection, such as `out T` or `in T`, the compiler internally represents the unknown concrete type as a [captured type](https://kotlinlang.org/spec/type-system.html#type-capturing). A captured type is an unknown type with known upper and lower bounds. Captured types are non-denotable, so you can't write them directly in Kotlin code. Instead, you can most frequently see captured types in compiler diagnostics, such as `CapturedType(out X)`. For example, the following type mismatch diagnostic contains a captured type: ```KOTLIN val array: Array = arrayOf("str") val item: Int = array.get(0) // Initializer type mismatch: expected 'Int', actual 'CapturedType(out CharSequence)' ``` The compiler uses the captured type's upper bound for read operations and its lower bound to determine which values are type-safe for write operations: ```KOTLIN // The projected type is Array val array: Array = arrayOf("Kotlin") // The get() read operation uses the captured type's upper bound, CharSequence val item = array.get(0) // The set() write operation uses the captured type's lower bound, Nothing, // which results in an error array.set(0, "New value") // Receiver type 'Array' contains out projection // which prohibits the use of 'fun set(index: Int, value: T): Unit' ``` In this example: * The variable `array` has the projected type `Array`. The compiler represents the projected type argument `out CharSequence` as a captured type with `CharSequence` as its upper bound and `Nothing` as its lower bound. * For the `get()` operation, the compiler approximates the captured type to its upper bound, `CharSequence`, and infers `CharSequence` as the type of `item`. * For the `set()` operation, the captured type has `Nothing` as its lower bound. Since `Nothing` has no instances, writing a value to the projected type isn't type-safe and results in an error. ## Generic functions Classes aren't the only declarations that can have type parameters. Functions can, too. Type parameters are placed before the name of the function: ```KOTLIN fun singletonList(item: T): List { // ... } fun T.basicToString(): String { // extension function // ... } ``` To call a generic function, specify the type arguments at the call site after the name of the function: ```KOTLIN val l = singletonList(1) ``` Type arguments can be omitted if they can be inferred from the context, so the following example works as well: ```KOTLIN val l = singletonList(1) ``` ## Generic constraints The set of all possible types that can be substituted for a given type parameter may be restricted by generic constraints. ### Upper bounds The most common type of constraint is an upper bound, which corresponds to Java's `extends` keyword: ```KOTLIN fun > sort(list: List) { ... } ``` The type specified after a colon is the upper bound, indicating that only a subtype of `Comparable` can be substituted for `T`. For example: ```KOTLIN sort(listOf(1, 2, 3)) // OK. Int is a subtype of Comparable sort(listOf(HashMap())) // Error: HashMap is not a subtype of Comparable> ``` The default upper bound (if there was none specified) is `Any?`. Only one upper bound can be specified inside the angle brackets. If the same type parameter needs more than one upper bound, you need a separate where-clause: ```KOTLIN fun copyWhenGreater(list: List, threshold: T): List where T : CharSequence, T : Comparable { return list.filter { it > threshold }.map { it.toString() } } ``` The passed type must satisfy all conditions of the `where` clause simultaneously. In the above example, the `T` type must implement both `CharSequence` and `Comparable`. ## Definitely non-nullable types To make interoperability with generic Java classes and interfaces easier, Kotlin supports declaring a generic type parameter as definitely non-nullable. To declare a generic type `T` as definitely non-nullable, declare the type with `& Any`. For example: `T & Any`. A definitely non-nullable type must have a nullable [upper bound](#upper-bounds). The most common use case for declaring definitely non-nullable types is when you want to override a Java method that contains `@NotNull` as an argument. For example, consider the `load()` method: ```JAVA import org.jetbrains.annotations.*; public interface Game { public T save(T x) {} @NotNull public T load(@NotNull T x) {} } ``` To override the `load()` method in Kotlin successfully, you need `T1` to be declared as definitely non-nullable: ```KOTLIN interface ArcadeGame : Game { override fun save(x: T1): T1 // T1 is definitely non-nullable override fun load(x: T1 & Any): T1 & Any } ``` When working only with Kotlin, it's unlikely that you will need to declare definitely non-nullable types explicitly because Kotlin's type inference takes care of this for you. ## Type erasure The type safety checks that Kotlin performs for generic declaration usages are done at compile time. At runtime, the instances of generic types do not hold any information about their actual type arguments. The type information is said to be erased. For example, the instances of `Foo` and `Foo` are erased to just `Foo<*>`. ### Generics type checks and casts Due to the type erasure, there is no general way to check whether an instance of a generic type was created with certain type arguments at runtime, and the compiler prohibits such `is`-checks such as `ints is List` or `list is T` (type parameter). However, you can check an instance against a star-projected type: ```KOTLIN if (something is List<*>) { something.forEach { println(it) } // The items are typed as `Any?` } ``` Similarly, when you already have the type arguments of an instance checked statically (at compile time), you can make an `is`-check or a cast that involves the non-generic part of the type. Note that angle brackets are omitted in this case: ```KOTLIN fun handleStrings(list: MutableList) { if (list is ArrayList) { // `list` is smart-cast to `ArrayList` } } ``` The same syntax but with the type arguments omitted can be used for casts that do not take type arguments into account: `list as ArrayList`. The type arguments of generic function calls are also only checked at compile time. Inside the function bodies, the type parameters cannot be used for type checks, and type casts to type parameters (`foo as T`) are unchecked. The only exclusion is inline functions with [reified type parameters](inline-functions.html#reified-type-parameters), which have their actual type arguments inlined at each call site. This enables type checks and casts for the type parameters. However, the restrictions described above still apply for instances of generic types used inside checks or casts. For example, in the type check `arg is T`, if `arg` is an instance of a generic type itself, its type arguments are still erased. ```KOTLIN //sampleStart inline fun Pair<*, *>.asPairOf(): Pair? { if (first !is A || second !is B) return null return first as A to second as B } val somePair: Pair = "items" to listOf(1, 2, 3) val stringToSomething = somePair.asPairOf() val stringToInt = somePair.asPairOf() val stringToList = somePair.asPairOf>() val stringToStringList = somePair.asPairOf>() // Compiles but breaks type safety! // Expand the sample for more details //sampleEnd fun main() { println("stringToSomething = " + stringToSomething) println("stringToInt = " + stringToInt) println("stringToList = " + stringToList) println("stringToStringList = " + stringToStringList) //println(stringToStringList?.second?.forEach() {it.length}) // This will throw ClassCastException as list items are not String } ``` ### Unchecked casts Type casts to generic types with concrete type arguments such as `foo as List` cannot be checked at runtime. These unchecked casts can be used when type safety is implied by the high-level program logic but cannot be inferred directly by the compiler. See the example below. ```KOTLIN fun readDictionary(file: File): Map = file.inputStream().use { TODO("Read a mapping of strings to arbitrary elements.") } // We saved a map with `Int`s into this file val intsFile = File("ints.dictionary") // Warning: Unchecked cast: `Map` to `Map` val intsDictionary: Map = readDictionary(intsFile) as Map ``` A warning appears for the cast in the last line. The compiler can't fully check it at runtime and provides no guarantee that the values in the map are `Int`. To avoid unchecked casts, you can redesign the program structure. In the example above, you could use the `DictionaryReader` and `DictionaryWriter` interfaces with type-safe implementations for different types. You can introduce reasonable abstractions to move unchecked casts from the call site to the implementation details. Proper use of [generic variance](#variance) can also help. For generic functions, using [reified type parameters](inline-functions.html#reified-type-parameters) makes casts like `arg as T` checked, unless `arg`'s type has its own type arguments that are erased. An unchecked cast warning can be suppressed by [annotating](annotations.html) the statement or the declaration where it occurs with `@Suppress("UNCHECKED_CAST")`: ```KOTLIN inline fun List<*>.asListOfType(): List? = if (all { it is T }) @Suppress("UNCHECKED_CAST") this as List else null ``` Note: On the JVM: [array types](arrays.html) (`Array`) retain information about the erased type of their elements, and type casts to an array type are partially checked: the nullability and actual type arguments of the element type are still erased. For example, the cast `foo as Array?>` will succeed if `foo` is an array holding any `List<*>`, whether it is nullable or not. ## Underscore operator for type arguments The underscore operator `_` can be used for type arguments. Use it to automatically infer a type of the argument when other types are explicitly specified: ```KOTLIN abstract class SomeClass { abstract fun execute() : T } class SomeImplementation : SomeClass() { override fun execute(): String = "Test" } class OtherImplementation : SomeClass() { override fun execute(): Int = 42 } object Runner { inline fun , T> run() : T { return S::class.java.getDeclaredConstructor().newInstance().execute() } } fun main() { // T is inferred as String because SomeImplementation derives from SomeClass val s = Runner.run() assert(s == "Test") // T is inferred as Int because OtherImplementation derives from SomeClass val n = Runner.run() assert(n == 42) } ``` # Asynchronous programming techniques For decades, as developers we are confronted with a problem to solve - how to prevent our applications from blocking. Whether we're developing desktop, mobile, or even backend applications, we want to avoid making the user wait or, even worse, create bottlenecks that prevent the application from scaling. There have been many approaches to solving this problem, including: * [Threading](#threading) * [Callbacks](#callbacks) * [Futures, promises, and others](#futures-promises-and-others) * [Reactive Extensions](#reactive-extensions) * [Coroutines](#coroutines) Before explaining what coroutines are, let's briefly review some of the other solutions. ## Threading Threads are by far probably the most well-known approach to avoid applications from blocking. ```KOTLIN fun postItem(item: Item) { val token = preparePost() val post = submitPost(token, item) processPost(post) } fun preparePost(): Token { // makes a request and consequently blocks the main thread return token } ``` Let's assume in the code above that `preparePost` is a long-running process and consequently would block the user interface. What we can do is launch it in a separate thread. This would then allow us to avoid the UI from blocking. This is a very common technique, but has a series of drawbacks: * Threads aren't cheap. Threads require context switches which are costly. * Threads aren't infinite. The number of threads that can be launched is limited by the underlying operating system. In backend applications, this could cause a major bottleneck. * Threads aren't always available. Some platforms, such as JavaScript, do not even support threads. * Threads aren't easy. Debugging threads and avoiding race conditions are common problems we suffer in multithreaded programming. ## Callbacks With callbacks, the idea is to pass one function as a parameter to another function, and have this one invoked once the process has completed. ```KOTLIN fun postItem(item: Item) { preparePostAsync { token -> submitPostAsync(token, item) { post -> processPost(post) } } } fun preparePostAsync(callback: (Token) -> Unit) { // make request and return immediately // arrange callback to be invoked later } ``` This in principle feels like a much more elegant solution, but once again has several issues: * Difficulty of nested callbacks. Usually a function that is used as a callback, often ends up needing its own callback. This leads to a series of nested callbacks which lead to incomprehensible code. The pattern is often referred to as callback hell, or the [pyramid of doom](https://en.wikipedia.org/wiki/Pyramid_of_doom_(programming)) due to the triangular shape that indentations from these deeply nested callbacks create. * Error handling is complicated. The nesting model makes error handling and propagation of these somewhat more complicated. Callbacks are quite common in event-loop architectures such as JavaScript, but even there, generally people have moved away to using other approaches such as promises or reactive extensions. ## Futures, promises, and others The idea behind futures or promises (other terms may be used depending on the language or platform), is that when we make a call, we're promised that at some point the call will return a `Promise` object, which we can then operate on. ```KOTLIN fun postItem(item: Item) { preparePostAsync() .thenCompose { token -> submitPostAsync(token, item) } .thenAccept { post -> processPost(post) } } fun preparePostAsync(): Promise { // makes request and returns a promise that is completed later return promise } ``` This approach requires a series of changes in how we program, in particular: * Different programming model. Similar to callbacks, the programming model moves away from a top-down imperative approach to a compositional model with chained calls. Traditional program structures such as loops, exception handling, etc. usually are no longer valid in this model. * Different APIs. Usually there's a need to learn a completely new API such as `thenCompose` or `thenAccept`, which can also vary across platforms. * Specific return type. The return type moves away from the actual data that we need and instead returns a new type `Promise` which has to be introspected. * Error handling can be complicated. The propagation and chaining of errors aren't always straightforward. ## Reactive extensions Reactive Extensions (Rx) were introduced to C# by [Erik Meijer](https://en.wikipedia.org/wiki/Erik_Meijer_(computer_scientist)). While it was definitely used on the .NET platform, it really didn't reach mainstream adoption until Netflix ported it over to Java, naming it RxJava. From then on, numerous ports have been provided for a variety of platforms including JavaScript (RxJS). The idea behind Rx is to move towards what's called `observable streams` whereby we now think of data as streams (infinite amounts of data) and these streams can be observed. In practical terms, Rx is simply the [Observer Pattern](https://en.wikipedia.org/wiki/Observer_pattern) with a series of extensions which allow us to operate on the data. In approach it's quite similar to Futures, but one can think of a Future as returning a discrete element, whereas Rx returns a stream. However, similar to the previous, it also introduces a complete new way of thinking about our programming model, famously phrased as ``` "everything is a stream, and it's observable" ``` This implies a different way to approach problems and quite a significant shift from what we're used to when writing synchronous code. One benefit as opposed to Futures is that given it's ported to so many platforms, generally we can find a consistent API experience no matter what we use, be it C#, Java, JavaScript, or any other language where Rx is available. In addition, Rx does introduce a somewhat nicer approach to error handling. ## Coroutines Kotlin's approach to working with asynchronous code is using coroutines, which is the idea of suspendable computations, i.e. the idea that a function can suspend its execution at some point and resume later on. However, one of the benefits of coroutines is that when it comes to the developer, writing non-blocking code is essentially the same as writing blocking code. The programming model itself doesn't really change. Take for instance the following code: ```KOTLIN fun postItem(item: Item) { launch { val token = preparePost() val post = submitPost(token, item) processPost(post) } } suspend fun preparePost(): Token { // makes a request and suspends the coroutine return suspendCoroutine { /* ... */ } } ``` This code will launch a long-running operation without blocking the main thread. The `preparePost` is what's called a `suspendable function`, thus the keyword `suspend` prefixing it. What this means as stated above, is that the function will execute, pause execution and resume at some point in time. * The function signature remains exactly the same. The only difference is `suspend` being added to it. The return type, however, is the type we want to be returned. * The code is still written as if we were writing synchronous code, top-down, without the need of any special syntax, beyond the use of a function called `launch` which essentially kicks off the coroutine (covered in other tutorials). * The programming model and APIs remain the same. We can continue to use loops, exception handling, etc. and there's no need to learn a complete set of new APIs. * It is platform independent. Whether we're targeting JVM, JavaScript or any other platform, the code we write is the same. Under the covers, the compiler takes care of adapting it to each platform. Coroutines are not a new concept, let alone invented by Kotlin. They've been around for decades and are popular in some other programming languages such as Go. What is important to note though is that the way they're implemented in Kotlin, most of the functionality is delegated to libraries. In fact, beyond the `suspend` keyword, no other keywords are added to the language. This is somewhat different from languages such as C# that have `async` and `await` as part of the syntax. With Kotlin, these are just library functions. For more information, see the [Coroutines reference](coroutines-overview.html). # Coroutines Applications often need to perform multiple tasks at the same time, such as responding to user input, loading data, or updating the screen. To support this, they rely on concurrency, which allows operations to run independently without blocking each other. The most common way to run tasks concurrently is by using threads, which are independent paths of execution managed by the operating system. However, threads are relatively heavy, and creating many of them can lead to performance issues. To support efficient concurrency, Kotlin uses asynchronous programming built around coroutines, which let you write asynchronous code in a natural, sequential style using suspending functions. Coroutines are lightweight alternatives to threads. They can suspend without blocking system resources and are resource-friendly, making them better suited for fine-grained concurrency. Most coroutine features are provided by the [kotlinx.coroutines](https://github.com/Kotlin/kotlinx.coroutines) library, which includes tools for launching coroutines, handling concurrency, working with asynchronous streams, and more. If you're new to coroutines in Kotlin, start with the [Coroutine basics](coroutines-basics.html) guide before diving into more complex topics. This guide introduces the key concepts of suspending functions, coroutine builders, and structured concurrency through simple examples: [Get started with coroutines](coroutines-basics.html) Tip: Check out the [KotlinConf app](https://github.com/JetBrains/kotlinconf-app) for a sample project to see how coroutines are used in practice. ## Coroutine concepts The `kotlinx.coroutines` library provides the core building blocks for running tasks concurrently, structuring coroutine execution, and managing shared state. ### Suspending functions and coroutine builders Coroutines in Kotlin are built on suspending functions, which allow code to pause and resume without blocking a thread. The `suspend` keyword marks functions that can perform long-running operations asynchronously. To launch new coroutines, use coroutine builders like [.launch()](https://kotlinlang.org/api/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/launch.html) and [.async()](https://kotlinlang.org/api/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/async.html). These builders are extension functions on [CoroutineScope](https://kotlinlang.org/api/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-coroutine-scope/), which defines the coroutine's lifecycle and provides the coroutine context. You can learn more about these builders in [Coroutine basics](coroutines-basics.html) and [Composing suspend functions](coroutines-and-channels.html). ### Coroutine context and behavior Launching a coroutine from a `CoroutineScope` creates a context that governs its execution. Builder functions like `.launch()` and `.async()` automatically create a set of elements that define how the coroutine behaves: * The [Job](https://kotlinlang.org/api/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-job/) interface tracks the coroutine's lifecycle and enables structured concurrency. * [CoroutineDispatcher](https://kotlinlang.org/api/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-coroutine-dispatcher/) controls where the coroutine runs, such as on a background thread or the main thread in UI applications. * [CoroutineExceptionHandler](https://kotlinlang.org/api/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-coroutine-exception-handler/) handles uncaught exceptions. These, along with other possible elements, make up the [coroutine context](coroutine-context-and-dispatchers.html), which is inherited by default from the coroutine's parent. This context forms a hierarchy that enables structured concurrency, where related coroutines can be [canceled](coroutines-cancellation.html) together or [handle exceptions](exception-handling.html) as a group. ### Asynchronous flow and shared mutable state Kotlin provides several ways for coroutines to communicate. Use one of the following options based on how you want to share values between coroutines: * [Flow](https://kotlinlang.org/api/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.flow/-flow/) produces values only when a coroutine actively collects them. * [Channel](https://kotlinlang.org/api/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.channels/-channel/) allows multiple coroutines to send and receive values, with each value delivered to exactly one coroutine. * [SharedFlow](https://kotlinlang.org/api/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.flow/-shared-flow/) continuously shares every value with all active collecting coroutines. When multiple coroutines need to access or update the same data, they share mutable state. Without coordination, this can lead to race conditions, where operations interfere with each other in unpredictable ways. To safely manage shared mutable state, use [StateFlow](https://kotlinlang.org/api/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.flow/-state-flow/#) to wrap the shared data. Then, you can update it from one coroutine and collect its latest value from others. For more information, see [Flows](coroutines-flow.html), [Channels](channels.html), and the [Coroutines and channels tutorial](coroutines-and-channels.html). ## What's next * Learn the fundamentals of coroutines, suspending functions, and builders in the [Coroutine basics guide](coroutines-basics.html). * Explore how to combine suspending functions and build coroutine pipelines in [Composing suspending functions](coroutine-context-and-dispatchers.html). * Learn how to [debug coroutines](debug-coroutines-with-idea.html) using built-in tools in IntelliJ IDEA. * For flow-specific debugging, see the [Debug Kotlin Flow using IntelliJ IDEA](debug-flow-with-idea.html) tutorial. * Read the [Guide to UI programming with coroutines](https://github.com/Kotlin/kotlinx.coroutines/blob/master/ui/coroutines-guide-ui.md) to learn about coroutine-based UI development. * Review [best practices for using coroutines in Android](https://developer.android.com/kotlin/coroutines/coroutines-best-practices). * Check out the [kotlinx.coroutines API reference](https://kotlinlang.org/api/kotlinx.coroutines/). # Reflection Reflection is a set of language and library features that allows you to introspect the structure of your program at runtime. Functions and properties are first-class citizens in Kotlin, and the ability to introspect them (for example, learning the name or the type of a property or function at runtime) is essential when using a functional or reactive style. Note: Kotlin/JS provides limited support for reflection features. [Learn more about reflection in Kotlin/JS](js-reflection.html). ## JVM dependency On the JVM platform, the Kotlin compiler distribution includes the runtime component required for using the reflection features as a separate artifact, `kotlin-reflect.jar`. This is done to reduce the required size of the runtime library for applications that do not use reflection features. To use reflection in a Gradle or Maven project, add the dependency on `kotlin-reflect`: * In Gradle: Kotlin: ```KOTLIN dependencies { implementation(kotlin("reflect")) } ``` Groovy: ```GROOVY dependencies { implementation "org.jetbrains.kotlin:kotlin-reflect:2.4.20" } ``` * In Maven: ```XML org.jetbrains.kotlin kotlin-reflect ``` If you don't use Gradle or Maven, make sure you have `kotlin-reflect.jar` in the classpath of your project. In other supported cases (IntelliJ IDEA projects that use the command-line compiler), it is added by default. In the command-line compiler, you can use the `-no-reflect` compiler option to exclude `kotlin-reflect.jar` from the classpath. ## Class references The most basic reflection feature is getting the runtime reference to a Kotlin class. To obtain the reference to a statically known Kotlin class, you can use the class literal syntax: ```KOTLIN val c = MyClass::class ``` The reference is a [KClass](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.reflect/-k-class/index.html) type value. Note: On JVM: a Kotlin class reference is not the same as a Java class reference. To obtain a Java class reference, use the `.java` property on a `KClass` instance. ### Bound class references You can get the reference to the class of a specific object with the same `::class` syntax by using the object as a receiver: ```KOTLIN val widget: Widget = ... assert(widget is GoodWidget) { "Bad widget: ${widget::class.qualifiedName}" } ``` You will obtain the reference to the exact class of an object, for example, `GoodWidget` or `BadWidget`, regardless of the type of the receiver expression (`Widget`). ## Callable references References to functions, properties, and constructors can also be called or used as instances of [function types](lambdas.html#function-types). The common supertype for all callable references is [KCallable<out R>](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.reflect/-k-callable/index.html), where `R` is the return value type. It is the property type for properties, and the constructed type for constructors. ### Function references When you have a named function declared as below, you can call it directly (`isOdd(5)`): ```KOTLIN fun isOdd(x: Int) = x % 2 != 0 ``` Alternatively, you can use the function as a function type value, that is, pass it to another function. To do so, use the `::` operator: ```KOTLIN fun isOdd(x: Int) = x % 2 != 0 fun main() { //sampleStart val numbers = listOf(1, 2, 3) println(numbers.filter(::isOdd)) //sampleEnd } ``` Here `::isOdd` is a value of function type `(Int) -> Boolean`. Function references belong to one of the [KFunction<out R>](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.reflect/-k-function/index.html) subtypes, depending on the parameter count. For instance, `KFunction3`. `::` can be used with overloaded functions when the expected type is known from the context. For example: ```KOTLIN fun main() { //sampleStart fun isOdd(x: Int) = x % 2 != 0 fun isOdd(s: String) = s == "brillig" || s == "slithy" || s == "tove" val numbers = listOf(1, 2, 3) println(numbers.filter(::isOdd)) // refers to isOdd(x: Int) //sampleEnd } ``` Alternatively, you can provide the necessary context by storing the method reference in a variable with an explicitly specified type: ```KOTLIN val predicate: (String) -> Boolean = ::isOdd // refers to isOdd(x: String) ``` If you need to use a member of a class or an extension function, it needs to be qualified: `String::toCharArray`. Even if you initialize a variable with a reference to an extension function, the inferred function type will have no receiver, but it will have an additional parameter accepting a receiver object. To have a function type with a receiver instead, specify the type explicitly: ```KOTLIN val isEmptyStringList: List.() -> Boolean = List::isEmpty ``` #### Example: function composition Consider the following function: ```KOTLIN fun compose(f: (B) -> C, g: (A) -> B): (A) -> C { return { x -> f(g(x)) } } ``` It returns a composition of two functions passed to it: `compose(f, g) = f(g(*))`. You can apply this function to callable references: ```KOTLIN fun compose(f: (B) -> C, g: (A) -> B): (A) -> C { return { x -> f(g(x)) } } fun isOdd(x: Int) = x % 2 != 0 fun main() { //sampleStart fun length(s: String) = s.length val oddLength = compose(::isOdd, ::length) val strings = listOf("a", "ab", "abc") println(strings.filter(oddLength)) //sampleEnd } ``` ### Property references To access properties as first-class objects in Kotlin, use the `::` operator: ```KOTLIN val x = 1 fun main() { println(::x.get()) println(::x.name) } ``` The expression `::x` evaluates to a `KProperty0` type property object. You can read its value using `get()` or retrieve the property name using the `name` property. For more information, see the [docs on the KProperty class](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.reflect/-k-property/index.html). For a mutable property such as `var y = 1`, `::y` returns a value with the [KMutableProperty0<Int>](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.reflect/-k-mutable-property/index.html) type which has a `set()` method: ```KOTLIN var y = 1 fun main() { ::y.set(2) println(y) } ``` A property reference can be used where a function with a single generic parameter is expected: ```KOTLIN fun main() { //sampleStart val strs = listOf("a", "bc", "def") println(strs.map(String::length)) //sampleEnd } ``` To access a property that is a member of a class, qualify it as follows: ```KOTLIN fun main() { //sampleStart class A(val p: Int) val prop = A::p println(prop.get(A(1))) //sampleEnd } ``` For an extension property: ```KOTLIN val String.lastChar: Char get() = this[length - 1] fun main() { println(String::lastChar.get("abc")) } ``` ### Interoperability with Java reflection On the JVM platform, the standard library contains extensions for reflection classes that provide a mapping to and from Java reflection objects (see package `kotlin.reflect.jvm`). For example, to find a backing field or a Java method that serves as a getter for a Kotlin property, you can write something like this: ```KOTLIN import kotlin.reflect.jvm.* class A(val p: Int) fun main() { println(A::p.javaGetter) // prints "public final int A.getP()" println(A::p.javaField) // prints "private final int A.p" } ``` To get the Kotlin class that corresponds to a Java class, use the `.kotlin` extension property: ```KOTLIN fun getKClass(o: Any): KClass = o.javaClass.kotlin ``` ### Constructor references Constructors can be referenced just like methods and properties. You can use them wherever the program expects a function type object that takes the same parameters as the constructor and returns an object of the appropriate type. Constructors are referenced by using the `::` operator and adding the class name. Consider the following function that expects a function parameter with no parameters and return type `Foo`: ```KOTLIN class Foo fun function(factory: () -> Foo) { val x: Foo = factory() } ``` Using `::Foo`, the zero-argument constructor of the class `Foo`, you can call it like this: ```KOTLIN function(::Foo) ``` Callable references to constructors are typed as one of the [KFunction<out R>](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.reflect/-k-function/index.html) subtypes depending on the parameter count. ### Bound function and property references You can refer to an instance method of a particular object: ```KOTLIN fun main() { //sampleStart val numberRegex = "\\d+".toRegex() println(numberRegex.matches("29")) val isNumber = numberRegex::matches println(isNumber("29")) //sampleEnd } ``` Instead of calling the method `matches` directly, the example uses a reference to it. Such a reference is bound to its receiver. It can be called directly (like in the example above) or used whenever a function type expression is expected: ```KOTLIN fun main() { //sampleStart val numberRegex = "\\d+".toRegex() val strings = listOf("abc", "124", "a70") println(strings.filter(numberRegex::matches)) //sampleEnd } ``` Compare the types of the bound and the unbound references. The bound callable reference has its receiver "attached" to it, so the type of the receiver is no longer a parameter: ```KOTLIN val isNumber: (CharSequence) -> Boolean = numberRegex::matches val matches: (Regex, CharSequence) -> Boolean = Regex::matches ``` A property reference can be bound as well: ```KOTLIN fun main() { //sampleStart val prop = "abc"::length println(prop.get()) //sampleEnd } ``` You don't need to specify `this` as the receiver: `this::foo` and `::foo` are equivalent. ### Bound constructor references A bound callable reference to a constructor of an [inner class](nested-classes.html#inner-classes) can be obtained by providing an instance of the outer class: ```KOTLIN class Outer { inner class Inner } val o = Outer() val boundInnerCtor = o::Inner ``` # Destructuring declarations Sometimes it is convenient to destructure an object into a number of variables, for example: ```KOTLIN val (name, age) = person ``` This syntax is called a destructuring declaration. A destructuring declaration creates multiple variables at once. You have declared two new variables: `name` and `age`, and can use them independently: ```KOTLIN println(name) println(age) ``` A destructuring declaration is compiled down to the following code: ```KOTLIN val name = person.component1() val age = person.component2() ``` The `component1()` and `component2()` functions are another example of the principle of conventions widely used in Kotlin (see operators like `+` and `*`, `for`-loops as an example). Anything can be on the right-hand side of a destructuring declaration, as long as the required number of component functions can be called on it. And, of course, there can be `component3()` and `component4()` and so on. Note: The `componentN()` functions need to be marked with the `operator` keyword to allow using them in a destructuring declaration. Destructuring declarations also work in `for`-loops: ```KOTLIN for ((a, b) in collection) { ... } ``` Variables `a` and `b` get the values returned by `component1()` and `component2()` called on elements of the collection. ## Example: returning two values from a function Assume that you need to return two things from a function - for example, a result object and a status of some sort. A compact way of doing this in Kotlin is to declare a [data class](data-classes.html) and return its instance: ```KOTLIN data class Result(val result: Int, val status: Status) fun function(...): Result { // computations return Result(result, status) } // Now, to use this function: val (result, status) = function(...) ``` Since data classes automatically declare `componentN()` functions, destructuring declarations work here. Note: You could also use the standard class `Pair` and have `function()` return `Pair`, but it's often better to have your data named properly. ## Example: destructuring declarations and maps Probably the nicest way to traverse a map is this: ```KOTLIN for ((key, value) in map) { // do something with the key and the value } ``` To make this work, you should * Present the map as a sequence of values by providing an `iterator()` function. * Present each of the elements as a pair by providing functions `component1()` and `component2()`. And indeed, the standard library provides such extensions: ```KOTLIN operator fun Map.iterator(): Iterator> = entrySet().iterator() operator fun Map.Entry.component1() = getKey() operator fun Map.Entry.component2() = getValue() ``` So you can freely use destructuring declarations in `for`-loops with maps (as well as collections of data class instances or similar). ## Underscore for unused variables If you don't need a variable in the destructuring declaration, you can place an underscore instead of its name: ```KOTLIN val (_, status) = getResult() ``` The `componentN()` operator functions are not called for the components that are skipped in this way. ## Destructuring in lambdas You can use the destructuring declarations syntax for lambda parameters. If a lambda has a parameter of the `Pair` type (or `Map.Entry`, or any other type that has the appropriate `componentN` functions), you can introduce several new parameters instead of one by putting them in parentheses: ```KOTLIN map.mapValues { entry -> "${entry.value}!" } map.mapValues { (key, value) -> "$value!" } ``` Note the difference between declaring two parameters and declaring a destructuring pair instead of a parameter: ```KOTLIN { a -> ... } // one parameter { a, b -> ... } // two parameters { (a, b) -> ... } // a destructured pair { (a, b), c -> ... } // a destructured pair and another parameter ``` If a component of the destructured parameter is unused, you can replace it with the underscore to avoid inventing its name: ```KOTLIN map.mapValues { (_, value) -> "$value!" } ``` You can specify the type for the whole destructured parameter or for a specific component separately: ```KOTLIN map.mapValues { (_, value): Map.Entry -> "$value!" } map.mapValues { (_, value: String) -> "$value!" } ``` ## Name-based destructuring Kotlin supports name-based destructuring declarations, where variables match properties by name instead of the position defined by `componentN()` functions in position-based destructuring. Tip: For more information about name-based destructuring, see the feature's [KEEP](https://github.com/Kotlin/KEEP/blob/main/proposals/KEEP-0438-name-based-destructuring.md). In position-based destructuring, variables correspond to the order of `componentN()` functions, for example: ```KOTLIN data class User(val username: String, val email: String) fun main() { val user = User("alice", "alice@example.com") val (email, username) = user println(email) // alice println(username) // alice@example.com } ``` In this example, because destructuring relies on the order of `componentN()` functions, `email` receives the value of `username`, and `username` receives the value of `email`. With name-based destructuring, property names determine which values are extracted rather than the position of `componentN()` functions: ```KOTLIN fun main() { val user = User("alice", "alice@example.com") // Uses name-based destructuring with explicit form (val mail = email, val name = username) = user println(name) // alice println(mail) // alice@example.com } ``` Name-based destructuring is [Experimental](components-stability.html#stability-levels-explained). When you enable this feature, it also introduces a new syntax for position-based destructuring using square brackets. Use this syntax for types where the order of elements matters, such as lists and other ordered collections, as well as unnamed tuples like `Pair` or `Triple`: ```KOTLIN val point = Pair(10, 20) // Uses position-based destructuring val [x, y] = point ``` You can control how the compiler interprets destructuring declarations with the `-Xname-based-destructuring` compiler option. It has the following modes: * `only-syntax` enables the explicit form of name-based destructuring without changing the behavior of existing destructuring declarations. * `name-mismatch` reports warnings when position-based destructuring in data classes uses variable names that don't match the property names. * `complete` enables short-form name-based destructuring with parentheses and continues supporting position-based destructuring with square bracket syntax. Tip: Before enabling `complete` mode, review and resolve the warnings reported in `name-mismatch` mode. These warnings show which destructuring declarations the compiler interprets differently in `complete` mode and include suggestions for rewriting those declarations accordingly. If you use `complete` mode, the short-form destructuring syntax with parentheses matches variables to property names instead of relying on position: ```KOTLIN val (email, username) = user ``` To enable name-based destructuring in your project, add the compiler option to your build configuration file: Gradle: ```KOTLIN kotlin { compilerOptions { freeCompilerArgs.add("-Xname-based-destructuring=only-syntax") } } ``` Maven: ```XML org.jetbrains.kotlin kotlin-maven-plugin -Xname-based-destructuring=only-syntax ``` # Backend development with Kotlin Kotlin is a great fit for developing server-side applications. With Kotlin, you can write concise and expressive code while maintaining full compatibility with existing Java-based technology stacks. ## Get started Kotlin supports gradual migration of large codebases from Java to Kotlin. You can start writing tests or new production code in Kotlin while keeping other parts of your project in Java. Configure your Java project to work with Kotlin and make use of the automated Java-to-Kotlin converter included in IntelliJ IDEA: [Introduce Kotlin to your Java project](mixing-java-kotlin-intellij.html) ## Explore frameworks Kotlin is fully compatible with all Java-based frameworks, so you can use your familiar technology stack while benefiting from Kotlin syntax. In addition to great IDE support, Kotlin offers framework-specific tooling, such as support for Spring and Ktor in IntelliJ IDEA with an Ultimate subscription. ### Spring [Spring](https://spring.io) makes use of Kotlin's language features to offer more concise APIs. The [online project generator](https://start.spring.io/#!language=kotlin) allows you to quickly generate a new project in Kotlin. [Get started with Spring Boot and Kotlin](jvm-get-started-spring-boot.html) ### Ktor [Ktor](https://github.com/kotlin/ktor) is a JetBrains framework for creating web applications in Kotlin. It uses coroutines for high scalability and offers an easy-to-use idiomatic API. [Create a new Ktor project](https://ktor.io/docs/server-create-a-new-project.html) ### Other frameworks Here are some other examples of the backend frameworks for Kotlin: | Framework |Description | -------------------------- | [Quarkus](https://quarkus.io/guides/kotlin) |An open-sourced framework that provides first-class support for Kotlin. Quarkus was built from the ground up for Kubernetes and provides a cohesive full-stack framework by leveraging a growing list of hundreds of best-of-breed libraries. | | [Vert.x](https://vertx.io) |A framework for building reactive web applications on the JVM. Vert.x offers [dedicated support](https://github.com/vert-x3/vertx-lang-kotlin) for Kotlin, including [integration of Kotlin coroutines](https://vertx.io/docs/vertx-lang-kotlin-coroutines/kotlin/). | | [kotlinx.html](https://github.com/kotlin/kotlinx.html) |A DSL that can be used to build HTML in web applications. It serves as an alternative to traditional templating systems such as JSP and FreeMarker. | | [Micronaut](https://micronaut.io/) |A modern JVM-based full-stack framework for building modular, easily testable microservices and serverless applications. Watch a webinar [Micronaut for microservices with Kotlin](https://micronaut.io/2020/12/03/webinar-micronaut-for-microservices-with-kotlin/) and explore a detailed [guide](https://guides.micronaut.io/latest/micronaut-kotlin-extension-fns.html) showing how you can use [Kotlin extension functions](extensions.html#extension-functions) in the Micronaut framework. | | [http4k](https://http4k.org/) |A functional toolkit with a small footprint for Kotlin HTTP applications, written in pure Kotlin. http4k provides the [CLI-enabled toolbox](https://toolbox.http4k.org) to generate fully formed project templates, and a web-based [project wizard](https://toolbox.http4k.org/project) to bootstrap a working http4k application with selected backend, modules, and build tooling. | | [Javalin](https://javalin.io) |A very lightweight web framework for Kotlin and Java which supports WebSockets, HTTP2, and async requests. | ## Deploy your applications Kotlin applications can be deployed to any host that supports Java web applications, including Amazon Web Services (AWS), Google Cloud Platform (GCP), and many others. * AWS provides a dedicated [SDK for Kotlin](https://docs.aws.amazon.com/sdk-for-kotlin/latest/developer-guide/home.html) to interact with its services. For serverless deployments, you can refer to [AWS Lambda code examples for Kotlin](https://docs.aws.amazon.com/sdk-for-kotlin/latest/developer-guide/kotlin_lambda_code_examples.html). * Ktor allows you to publish Kotlin applications to various cloud providers. For instance, you can follow Ktor tutorials to learn more about deploying to [Google App Engine](https://ktor.io/docs/google-app-engine.html) and other services. * Spring applications are also compatible with most popular cloud providers. See how to deploy Spring Boot applications to the cloud in the [official Spring documentation](https://docs.spring.io/spring-boot/how-to/deployment/cloud.html). ## Join the community * ![Slack](images/slack.svg) Kotlin slack: [get an invitation](https://surveys.jetbrains.com/s3/kotlin-slack-sign-up) and join the [#spring](https://kotlinlang.slack.com/archives/C0B8ZTWE4) and [#server](https://kotlinlang.slack.com/archives/C0B8RC352) channels * ![Stack Overflow](images/stackoverflow.svg) Stack Overflow: subscribe to the ["kotlin"](https://stackoverflow.com/questions/tagged/kotlin), ["spring-kotlin"](https://stackoverflow.com/questions/tagged/spring-kotlin), or ["ktor"](https://stackoverflow.com/questions/tagged/ktor) tags * ![YouTube](images/youtube.svg) Kotlin YouTube channel: subscribe and watch videos about [Kotlin with Spring](https://www.youtube.com/playlist?list=PLlFc5cFwUnmxOJL0GSSZ1Vot4KL2Vwe7x) ## Next steps * [Learn how to test your Java Maven project with Kotlin and JUnit](jvm-test-using-junit.html) * [Explore how to build asynchronous server applications with Ktor](https://ktor.io/docs/server-create-a-new-project.html) # Adding Kotlin to a Java project – tutorial Kotlin is fully interoperable with Java, so you can gradually introduce it into your existing Java projects without having to rewrite everything. In this tutorial, you'll learn how to: * Set up Maven or Gradle build tools to compile both Java and Kotlin code. * Organize Java and Kotlin source files in your project directories. * Convert Java files to Kotlin using IntelliJ IDEA. Tip: You can use any existing Java project for this tutorial or clone our public [sample project](https://github.com/kotlin-hands-on/kotlin-junit-sample/tree/main/complete) with both Maven and Gradle build files already set up. You can also hand over the conversion to your AI agent of choice using our [prepared skill](https://github.com/Kotlin/kotlin-agent-skills/blob/main/skills/kotlin-tooling-java-to-kotlin/SKILL.md). Keep in mind that AI processing results are not entirely predictable. ## Project configuration To add Kotlin to a Java project, you need to configure the project to use both Kotlin and Java, depending on the build tool you use. The project configuration ensures that both Kotlin and Java code are compiled properly and can reference each other seamlessly. ### Maven Note: Starting with IntelliJ IDEA 2025.3, when you add your first Kotlin file to a Maven-based Java project, the IDE automatically updates your `pom.xml` file to include the Kotlin Maven plugin and standard dependencies. You can still configure it manually if you want to customize versions or build phases. To use Kotlin and Java together in a Maven project, apply the Kotlin Maven plugin and add Kotlin dependencies in your `pom.xml` file: 1. In the `` section, add the Kotlin version property: ```XML 2.4.20 ``` 2. In the `` section, add the required dependencies to the `` section: ```XML org.junit.jupiter junit-jupiter-engine test org.junit.jupiter junit-jupiter-params test ``` 3. In the `` section, add the Kotlin plugin: ```XML org.jetbrains.kotlin kotlin-maven-plugin ${kotlin.version} true ``` Enabling `true` in the Kotlin Maven plugin helps to: * Automatically add the `kotlin-stdlib` dependency to the project. * Configure execution phases to compile Kotlin first, then Java. * Reference Kotlin code in Java code and vice versa. * Automatically align the JVM target version with the Java compiler version. You don't need a separate `maven-compiler-plugin` in the `` section when using the Kotlin Maven plugin with extensions. 4. Reload the Maven project in your IDE. 5. Run tests to verify the configuration: ```BASH ./mvnw clean test ``` ### Gradle To use Kotlin and Java together in a Gradle project, apply the Kotlin JVM plugin and add Kotlin dependencies in your `build.gradle.kts` file: 1. In the `plugins {}` block, add the Kotlin JVM plugin: ```KOTLIN plugins { // Other plugins kotlin("jvm") version "2.4.20" } ``` 2. Set the JVM toolchain version to match your Java version: ```KOTLIN kotlin { jvmToolchain(17) } ``` This ensures Kotlin uses the same JDK version as your Java code. 3. In the `dependencies {}` block, add the `kotlin("test")` library that provides Kotlin test utilities and integrates with JUnit: ```KOTLIN dependencies { // Other dependencies testImplementation(kotlin("test")) // Other test dependencies } ``` 4. Reload the Gradle project in your IDE. 5. Run your tests to verify the configuration: ```BASH ./gradlew clean test ``` ## Project structure With this configuration, you can mix Java and Kotlin files in the same source directories: ``` src/ ├── main/ │ ├── java/ # Java and Kotlin production code │ └── kotlin/ # Additional Kotlin production code (optional) └── test/ ├── java/ # Java and Kotlin test code └── kotlin/ # Additional Kotlin test code (optional) ``` You can create these directories manually or let IntelliJ IDEA create them when you add your first Kotlin file. The Kotlin plugin automatically recognizes both `src/main/java` and `src/test/java` directories, so you can keep `.kt` and `.java` files in the same directories. ## Convert Java files to Kotlin The Kotlin plugin also bundles a Java to Kotlin converter (J2K) that automatically converts Java files to Kotlin. To use J2K on a file, click Convert Java File to Kotlin File in its context menu or in the Code menu of IntelliJ IDEA. ![Convert Java to Kotlin](images/convert-java-to-kotlin.png) While the converter is not fool-proof, it does a pretty decent job of converting most boilerplate code from Java to Kotlin. However, some manual tweaking is sometimes required. ## Explore compiler plugins If you have a more complex project that uses [Spring](https://spring.io/) or Java Persistence API (JPA), you can use Kotlin compiler plugins that automatically adapt Kotlin's language features to framework expectations, reducing boilerplate: * The [all-open](all-open-plugin.html) plugin automatically makes classes and their members `open` when used with specific annotations. This is particularly useful for frameworks like Spring that require classes to be non-final. For Spring, you can use a dedicated [kotlin-spring](all-open-plugin.html#spring-support) plugin, which is a wrapper on top of `all-open`. It specifies Spring annotations automatically. * The [no-arg](no-arg-plugin.html) plugin generates an additional zero-argument constructor for classes with specific annotations. This allows JPA to instantiate classes that otherwise wouldn't have a default constructor. You can also use the [kotlin-jpa](no-arg-plugin.html#jpa-support) plugin, which is a wrapper on top of `no-arg`. It specifies no-arg annotations automatically. * The [power-assert](power-assert.html) plugin improves the debugging experience by providing detailed failure messages with contextual information for assertions. It shows intermediate values and helps you understand why a test failed. ## Next step The easiest way to start using Kotlin in a Java project is by adding Kotlin tests first: [Add your first Kotlin test to your Java project](jvm-test-using-junit.html) ### See also * [Kotlin and Java interoperability details](java-to-kotlin-interop.html) * [Maven build configuration reference](maven.html) # Test Java code using Kotlin and JUnit – tutorial Kotlin is fully interoperable with Java, which means you can write tests for Java code using Kotlin and run them together with your existing Java tests in the same project. In this tutorial, you'll learn how to: * Configure a mixed Java–Kotlin project to run tests using [JUnit](https://junit.org/). * Add Kotlin tests that verify Java code. * Run tests using Maven or Gradle. Note: Before you start, make sure you have: * [IntelliJ IDEA](https://www.jetbrains.com/idea/download/) or [VS Code](https://code.visualstudio.com/Download) with the installed [Kotlin extension](https://github.com/Kotlin/kotlin-lsp/tree/main?tab=readme-ov-file#vs-code-quick-start). * Java 17 or later. ## Configure the project 1. In your IDE, clone the sample project from version control: ```TEXT https://github.com/kotlin-hands-on/kotlin-junit-sample.git ``` 2. Navigate to the `initial` module and review the project structure: ```TEXT kotlin-junit-sample/ ├── initial/ │ ├── src/ │ │ ├── main/java/ # Java source code │ │ └── test/java/ # JUnit test in Java │ ├── pom.xml # Maven configuration │ └── build.gradle.kts # Gradle configuration ``` The `initial` module contains a simple Todo application in Java with a single test. 3. In the same directory, open your build file and update its contents to support Kotlin: Maven: ```XML 4.0.0 org.jetbrains.kotlin kotlin-junit-complete 1.0-SNAPSHOT kotlin-junit-complete https://kotlinlang.org/docs/jvm-test-using-junit.htm UTF-8 17 1.6.0 2.4.20 org.junit junit-bom 6.0.3 pom import org.junit.jupiter junit-jupiter-api test org.junit.jupiter junit-jupiter-engine test org.junit.jupiter junit-jupiter-params test com.gitlab.klamonte jexer ${jexer.version} maven-clean-plugin 3.4.0 maven-resources-plugin 3.3.1 maven-surefire-plugin 3.3.0 maven-jar-plugin 3.4.2 maven-install-plugin 3.1.2 maven-deploy-plugin 3.1.2 maven-site-plugin 3.12.1 maven-project-info-reports-plugin 3.6.1 org.jetbrains.kotlin kotlin-maven-plugin ${kotlin.version} true ``` * In the `` section, set the Kotlin version. * In the `` section, add JUnit Jupiter dependencies to run tests. * In the `` section, apply `kotlin-maven-plugin` with `` set to `true`. It automatically adds corresponding executions and the `kotlin-stdlib` dependency to the build. * You don't need to add `maven-compiler-plugin` to the `` section when using the Kotlin Maven plugin with extensions. Gradle: ```KOTLIN // build.gradle.kts group = "org.jetbrains.kotlin" version = "1.0-SNAPSHOT" description = "kotlin-junit-complete" java.sourceCompatibility = JavaVersion.VERSION_17 plugins { application kotlin("jvm") version "2.4.20" } kotlin { jvmToolchain(17) } application { mainClass.set("org.jetbrains.kotlin.junit.App") } repositories { mavenCentral() } dependencies { implementation("com.gitlab.klamonte:jexer:1.6.0") testImplementation(kotlin("test")) testImplementation(libs.org.junit.jupiter.junit.jupiter.api) testImplementation(libs.org.junit.jupiter.junit.jupiter.params) testRuntimeOnly(libs.org.junit.jupiter.junit.jupiter.engine) testRuntimeOnly(libs.org.junit.platform.junit.platform.launcher) } tasks.test { useJUnitPlatform() } ``` * In the `plugins {}` block, add the `kotlin("jvm")` plugin. * Set the JVM toolchain version to match your Java version. * In the `dependencies {}` block, add the `kotlin.test` library that provides Kotlin's test utilities and integrates with JUnit. Kotlin/JVM supports the latest stable JUnit version, JUnit 6. You can find it in the `gradle/libs.versions.toml` version catalog. If you generally prefer using the version catalog, you can even add the `kotlin("jvm")` plugin there: ```TOML # gradle/libs.versions.toml [versions] kotlin = "2.4.20" junit = "6.0.3" [libraries] org-junit-jupiter-junit-jupiter-api = { module = "org.junit.jupiter:junit-jupiter-api", version.ref = "junit" } org-junit-jupiter-junit-jupiter-params = { module = "org.junit.jupiter:junit-jupiter-params", version.ref = "junit" } org-junit-jupiter-junit-jupiter-engine = { module = "org.junit.jupiter:junit-jupiter-engine", version.ref = "junit" } org-junit-platform-junit-platform-launcher = { module = "org.junit.platform:junit-platform-launcher" } [plugins] kotlinJvm = { id = "org.jetbrains.kotlin.jvm", version.ref = "kotlin" } ``` 4. Reload the build file in your IDE. For more detailed instructions on build file setup, see [Project configuration](mixing-java-kotlin-intellij.html#project-configuration). ## Add your first Kotlin test The `TodoItemTest.java` test in `initial/src/test/java` already verifies the app basics: item creation, defaults, unique IDs, and state changes. You can expand the test coverage by adding a Kotlin test that verifies repository-level behavior: 1. Navigate to the same test source directory, `initial/src/test/java`. 2. Create a `TodoRepositoryTest.kt` file in the same package as the Java test. 3. Create the test class with field declarations and setup function: ```KOTLIN package org.jetbrains.kotlin.junit import org.junit.jupiter.api.BeforeEach import org.junit.jupiter.api.Assertions import org.junit.jupiter.api.Test import org.junit.jupiter.api.DisplayName internal class TodoRepositoryTest { lateinit var repository: TodoRepository lateinit var testItem1: TodoItem lateinit var testItem2: TodoItem @BeforeEach fun setUp() { repository = TodoRepository() testItem1 = TodoItem("Task 1", "Description 1") testItem2 = TodoItem("Task 2", "Description 2") } } ``` * JUnit annotations work the same in Kotlin as in Java. * In Kotlin, the [lateinit keyword](properties.html#late-initialized-properties-and-variables) allows declaring non-null properties that are initialized later. This helps to avoid having to use nullable types (`TodoRepository?`) in your tests. 4. Add a test inside the `TodoRepositoryTest` class to check the initial repository state and its size: ```KOTLIN @Test @DisplayName("Should start with empty repository") fun shouldStartEmpty() { Assertions.assertEquals(0, repository.size()) Assertions.assertTrue(repository.all.isEmpty()) } ``` * Unlike Java static import, Jupiter's `Assertions` is imported as a class and used as a qualifier for assertion functions. * Instead of `.getAll()` calls, you can access Java getters as properties in Kotlin with `repository.all`. 5. Write another test to verify copy behavior for all items: ```KOTLIN @Test @DisplayName("Should return defensive copy of items") fun shouldReturnDefensiveCopy() { repository.add(testItem1) val items1 = repository.all val items2 = repository.all Assertions.assertNotSame(items1, items2) Assertions.assertThrows( UnsupportedOperationException::class.java ) { items1.clear() } Assertions.assertEquals(1, repository.size()) } ``` * To get a Java class object from a Kotlin class, use `::class.java`. * You can split complex assertions across multiple lines without using any special continuation characters. 6. Add a test to verify finding items by ID: ```KOTLIN @Test @DisplayName("Should find item by ID") fun shouldFindItemById() { repository.add(testItem1) repository.add(testItem2) val found = repository.getById(testItem1.id()) Assertions.assertTrue(found.isPresent) Assertions.assertEquals(testItem1, found.get()) } ``` Kotlin works smoothly with the Java [Optional API](https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/util/Optional.html). It automatically converts getter methods to properties, that's why the `isPresent()` method is accessed here as a property. 7. Write a test to verify the item removal mechanism: ```KOTLIN @Test @DisplayName("Should remove item by ID") fun shouldRemoveItemById() { repository.add(testItem1) repository.add(testItem2) val removed = repository.remove(testItem1.id()) Assertions.assertTrue(removed) Assertions.assertEquals(1, repository.size()) Assertions.assertTrue(repository.getById(testItem1.id()).isEmpty) Assertions.assertTrue(repository.getById(testItem2.id()).isPresent) } @Test @DisplayName("Should return false when removing non-existent item") fun shouldReturnFalseForNonExistentRemoval() { repository.add(testItem1) val removed = repository.remove("non-existent-id") Assertions.assertFalse(removed) Assertions.assertEquals(1, repository.size()) } ``` In Kotlin, you can chain method calls and property access, for example `repository.getById(id).isEmpty`. Tip: You can add even more tests to the `TodoRepositoryTest` test class to cover additional functionality. See the full source code in the sample project's [complete](https://github.com/kotlin-hands-on/kotlin-junit-sample/blob/main/complete/src/test/java/org/jetbrains/kotlin/junit/TodoRepositoryTest.kt) module. ## Run tests Run both Java and Kotlin tests to verify your project works as expected: 1. Run the test using the gutter icon: ![Run the test](images/run-test.png)You can also run all project tests from the `initial` directory using the command line: Maven: ```BASH mvn test ``` Gradle: ```BASH ./gradlew test ``` 2. Check that the test works correctly by changing one of the variable values. For example, modify the `shouldAddItem` test to expect an incorrect repository size: ```KOTLIN @Test @DisplayName("Should add item to repository") fun shouldAddItem() { repository.add(testItem1) Assertions.assertEquals(2, repository.size()) // Changed from 1 to 2 Assertions.assertTrue(repository.all.contains(testItem1)) } ``` 3. Run the test again and verify that it fails: ![Check the test result. The test has failed](images/test-failed.png) Tip: You can find the fully configured project with tests in the sample project's [complete](https://github.com/kotlin-hands-on/kotlin-junit-sample/tree/main/complete) module. ## What's next Learn more about [testing Kotlin projects with Maven](jvm-test-maven.html). # Test Kotlin projects with Maven Kotlin integrates seamlessly with the Maven ecosystem, allowing you to use industry-standard tools to verify your backend applications. In this guide, you'll learn how to create tests with JUnit and use Maven plugins to run unit and integration tests. Tip: For a detailed guide to setting up your Maven project to use both Kotlin and Java, see [Project configuration](mixing-java-kotlin-intellij.html#project-configuration). ## Create tests with JUnit [JUnit](https://junit.org/) is the standard testing framework for Kotlin backend development. While Kotlin supports multiple JUnit versions, most modern projects should use JUnit 6. To create a test in Kotlin using JUnit, use the `@Test` annotation from the `kotlin.test` or JUnit package. ### Add dependency The `kotlin-test` library is the easiest way to start. It provides a common set of assertions and automatically pulls in the necessary JUnit artifacts. #### JUnit 5 and later For all new projects, use the `kotlin-test-junit5` artifact. It provides full support for JUnit, including features like nested tests and parallel execution. Kotlin/JVM supports the latest stable JUnit version, JUnit 6. Update your `pom.xml` file as follows: ```XML org.jetbrains.kotlin kotlin-test-junit5 2.4.20 test ``` Note: Despite its name, `kotlin-test-junit5` supports all latest JUnit versions, including JUnit 6. #### JUnit 4 If you'd like to use an earlier version of JUnit, for example, for a legacy project, use the `kotlin-test-junit` artifact that utilizes JUnit 4: ```XML org.jetbrains.kotlin kotlin-test-junit 2.4.20 test ``` Tip: For a detailed guide on using JUnit for testing and a sample project, see the [Test Java code with Kotlin](jvm-test-using-junit.html) tutorial. ### Write unit tests Unit tests verify isolated parts of your code, such as individual functions or classes. By convention, unit tests are named with the `*Test` suffix. For example: ```KOTLIN import kotlin.test.Test import kotlin.test.assertEquals class OrderServiceTest { @Test fun `calculate total should sum item prices`() { val service = OrderService() val result = service.calculateTotal(listOf(10.0, 25.0)) assertEquals(35.0, result) } } ``` ### Write integration tests Integration tests verify interaction between components, like a service and a database. By convention, integration tests are named with the `*IT` suffix. For example: ```KOTLIN import kotlin.test.Test import kotlin.test.assertNotNull class UserRepositoryIT { @Test fun saveFindUser() { // Example integration with a database or service val repository = UserRepository() repository.save(User("KotlinUser")) val user = repository.findByName("KotlinUser") assertNotNull(user) } } ``` ## Run tests In Maven projects, test execution is typically split between two plugins: Surefire and Failsafe to ensure a clean build lifecycle. ### With Surefire plugin The [Surefire plugin](https://maven.apache.org/surefire/maven-surefire-plugin/) handles unit tests. It runs all Kotlin and Java tests that follow the `*Test` naming pattern. By default, it executes during the `test` phase of the build lifecycle and fails the build immediately if a test fails. ```XML org.apache.maven.plugins maven-surefire-plugin 3.5.5 ``` To run only your unit tests, use the following command: ```BASH mvn test ``` ### With Failsafe plugin The [Failsafe plugin](https://maven.apache.org/surefire/maven-failsafe-plugin/) handles integration tests. It runs all Kotlin and Java tests that follow the `*IT` naming pattern. Unlike Surefire, Failsafe allows the build to continue if a test fails during the `integration-test` phase, allowing the `post-integration-test` phase tasks (like stopping a Docker container) to run. The build finally fails during the `verify` phase if there were any test failures. ```XML org.apache.maven.plugins maven-failsafe-plugin 3.5.5 integration-test verify ``` To run both unit and integration tests, use the following command: ```BASH mvn verify ``` ## Get detailed failure messages The Kotlin [Power-assert compiler plugin](power-assert.html) generates detailed failure messages that display intermediate values in your assertions, giving you the full diagrams in the console output. 1. To enable Power-assert, add the following configuration to your project's `pom.xml`: ```XML 2.4.20 17 org.jetbrains.kotlin kotlin-test-junit5 ${kotlin.version} test org.jetbrains.kotlin kotlin-maven-plugin ${kotlin.version} true compile process-sources compile test-compile process-test-sources test-compile power-assert org.jetbrains.kotlin kotlin-maven-power-assert ${kotlin.version} ``` * In the `` section, set the Kotlin version and the target JDK release version, for example, JDK 17. * In the `` section, add `kotlin-test-junit5` for running tests. * In the `` section, configure `kotlin-maven-plugin` with the `power-assert` compiler plugin. List the assertion functions you want to transform under `` and add the Power-assert plugin dependency. 2. Create a test file, `UserProfileBackendTest.kt`, in the `src/test/kotlin` directory: ```KOTLIN import kotlin.test.Test import kotlin.test.assertEquals class UserProfileBackendTest { data class UserProfile(val id: Long, val email: String) @Test fun `verify backend entity mapping matches`() { // Define expected object state val expectedRecord = UserProfile(id = 451L, email = "admin-dev@company.internal") // Simulate a mismatched backend response val actualRecord = UserProfile(id = 451L, email = "admin-prod@company.com") // Use a standard kotlin.test assertion assertEquals(expectedRecord, actualRecord, "Profile configurations out of sync") } } ``` 3. Run the test and verify the output: ```BASH mvn test ``` The console displays the full Power-assert diagram, showing the difference between the expected and actual values at each position in the expression: ```TEXT Profile configurations out of sync assertEquals(expectedRecord, actualRecord, "Profile configurations out of sync") | | | UserProfile(id=451, email=admin-prod@company.com) UserProfile(id=451, email=admin-dev@company.internal) ``` ## Explore other testing frameworks Besides JUnit, you can use other popular frameworks to make Kotlin tests more idiomatic and readable: | Library |Description | ------------------------ | [AssertJ](https://github.com/assertj/assertj) |Fluent assertion library with chainable assertions. | | [Mockito-Kotlin](https://github.com/mockito/mockito-kotlin) |Kotlin wrapper for Mockito that provides helper functions and better integration with the Kotlin type system. | | [MockK](https://github.com/mockk/mockk) |Native Kotlin mocking library that supports Kotlin-specific features, including coroutines and extension functions. | | [Kotest](https://github.com/kotest/kotest) |Assertion library for Kotlin offering multiple assertion styles and extensive matcher support. | | [Strikt](https://github.com/robfletcher/strikt) |Assertion library for Kotlin with type-safe assertions and support for data classes. | ## What's next * Explore the features of the [kotlin.test library](https://kotlinlang.org/api/latest/kotlin.test/kotlin.test/). * Learn more about the [Power-assert compiler plugin](power-assert.html). # Use annotation processors in Kotlin projects * Use [kapt](kapt.html) if: * You have a Maven project. * You have a Gradle project, but the required Java annotation processor doesn't support KSP yet. [See the list of supported libraries](ksp-overview.html#supported-libraries). * Use [KSP](ksp-overview.html) if: * You have a Gradle project, and the required Java annotation processor supports KSP. * You want to create your own annotation processors. Annotation processors analyze your source code at compile time to generate boilerplate code, validate usage, or produce other artifacts. Kotlin supports two ways to work with annotation processors: * [The kapt compiler plugin](#use-kapt-with-java-annotation-processors) works by generating stub files from Kotlin source code and then running the Java annotation processors on those stubs. This extra stub-generation step makes the build time slower and means kapt can't understand Kotlin-specific constructs, such as [extension functions](extensions.html) or [null safety](null-safety.html). kapt supports both Maven and Gradle. It's recommended for all Maven projects and for Gradle projects with processor libraries that haven't yet adopted KSP, such as [MapStruct](https://mapstruct.org/). * [The KSP framework](#use-ksp-in-gradle-projects) reads Kotlin source code directly through a Kotlin-first API, without generating stubs. It understands Kotlin-specific features natively and runs builds faster than kapt. Currently, KSP has official support only for Gradle. It's recommended for writing your own processors and working with KSP-compatible libraries like [Dagger](https://dagger.dev/). ## Use kapt with Java annotation processors [kapt](kapt.html) lets you use existing Java annotation processors in Kotlin projects without any changes to the processors themselves. The example below shows how to use the [MapStruct](https://mapstruct.org/) annotation processor, which generates type-safe mapper implementations between Java beans at compile time. 1. In your build file, apply the `kapt` plugin and add MapStruct to the `dependencies` section: Maven: ```XML 11 1.6.3 org.mapstruct mapstruct ${mapstruct.version} org.jetbrains.kotlin kotlin-maven-plugin ${kotlin.version} true kapt kapt src/main/kotlin src/main/java stubs org.mapstruct mapstruct-processor ${mapstruct.version} ``` * Add the execution of the `kapt` goal from `kotlin-maven-plugin` before the `compile` execution. * Configure the [mode of annotation processing](kapt.html#set-up-in-maven) using the `aptMode` option. Gradle Kotlin: ```KOTLIN plugins { kotlin("kapt") version "2.4.20" } dependencies { implementation("org.mapstruct:mapstruct:1.6.3") kapt("org.mapstruct:mapstruct-processor:1.6.3") } ``` Gradle Groovy: ```GROOVY plugins { id "org.jetbrains.kotlin.kapt" version "2.4.20" } dependencies { implementation "org.mapstruct:mapstruct:1.6.3" kapt "org.mapstruct:mapstruct-processor:1.6.3" } ``` 2. Define your data classes and a mapper interface: ```KOTLIN import org.mapstruct.Mapper import org.mapstruct.factory.Mappers data class UserDto(val id: Long, val firstName: String, val lastName: String) data class UserEntity(val id: Long, val firstName: String, val lastName: String) @Mapper interface UserMapper { fun toDto(entity: UserEntity): UserDto fun toEntity(dto: UserDto): UserEntity companion object : UserMapper by Mappers.getMapper(UserMapper::class.java) } ``` 3. Build the project. MapStruct generates the `UserMapperImpl` class in the generated sources' directory. Use the `UserMapper` companion object to call the generated implementation: ```KOTLIN fun main() { val entity = UserEntity(id = 1L, firstName = "John", lastName = "Doe") val dto = UserMapper.toDto(entity) println(dto) // UserDto(id=1, firstName=John, lastName=Doe) } ``` ## Use KSP in Gradle projects With [KSP](ksp-overview.html), you can use existing annotation processors in Gradle projects and create your own processors that generate code based on annotations in your source code. ### Use KSP with Java annotation processors For Gradle projects, use KSP with the compatible annotation processors. KSP is faster than kapt and can understand Kotlin-specific features natively. See the list of [libraries that already support KSP](ksp-overview.html#supported-libraries). The example below shows how to use [Dagger](https://dagger.dev/), a compile-time dependency injection framework that generates the wiring code for your dependency graph. 1. In your `build.gradle(.kts)` file, apply the KSP plugin and add Dagger to the `dependencies` block: Kotlin: ```KOTLIN // build.gradle.kts plugins { kotlin("jvm") version "2.4.20" id("com.google.devtools.ksp") version "2.3.10" } dependencies { implementation("com.google.dagger:dagger:2.59.2") ksp("com.google.dagger:dagger-compiler:2.59.2") } ``` Groovy: ```GROOVY // build.gradle plugins { id 'org.jetbrains.kotlin.jvm' version '2.4.20' id 'com.google.devtools.ksp' version '2.3.10' } dependencies { implementation 'com.google.dagger:dagger:2.59.2' ksp 'com.google.dagger:dagger-compiler:2.59.2' } ``` Tip: To find the latest version of KSP, check the GitHub [Releases](https://github.com/google/ksp/releases) page. 2. Annotate your Kotlin classes with Dagger annotations: ```KOTLIN import javax.inject.Inject import javax.inject.Singleton import dagger.Component import dagger.Module import dagger.Provides @Singleton class UserRepository @Inject constructor() { fun getUser(): String = "John Doe" } @Module class AppModule { @Provides @Singleton fun provideUserRepository(): UserRepository = UserRepository() } @Singleton @Component(modules = [AppModule::class]) interface AppComponent { fun userRepository(): UserRepository } ``` 3. Build the project. Dagger generates implementation classes, such as `DaggerAppComponent` in the `build/generated/ksp` directory. Use the generated class in your code: ```KOTLIN fun main() { val appComponent = DaggerAppComponent.create() val userRepository = appComponent.userRepository() println("User: ${userRepository.getUser()}") // User: John Doe } ``` For more information on Dagger support for KSP, see its [documentation](https://dagger.dev/dev-guide/ksp.html). ### Create your own annotation processor You can use the KSP API to write your own annotation processors that generate code at compile time. A new processor requires three modules: * An `annotation` module that declares the custom annotation. * A `processor` module that implements the `SymbolProcessor` and `SymbolProcessorProvider` factories. `SymbolProcessor` contains the main logic, while `SymbolProcessorProvider` creates the processor and registers the provider in the `META-INF/services/` path. * An `app` module that applies the KSP plugin depends on the processor, and uses the annotation. For complete step-by-step instructions, see the [KSP quickstart](ksp-quickstart.html#create-your-own-processor). ## What's next * [Learn more about kapt configuration](kapt.html) * [Get started with KSP](ksp-quickstart.html) * [See how to migrate from kapt to KSP](ksp-kapt-migration.html) # Code quality tools in Kotlin projects Code quality tools help you enforce coding standards, detect bugs early, measure test coverage, and maintain code quality across your Kotlin projects. This guide shows how to integrate popular tools like [ktlint](https://ktlint.github.io/ktlint/latest/), [detekt](https://detekt.dev/), [SonarQube](https://www.sonarsource.com/products/sonarqube/), [SonarCloud](https://www.sonarsource.com/products/sonarcloud/), and [Kover](https://kotlin.github.io/kotlinx-kover/) into your backend project for Maven or Gradle. ## Code formatting with ktlint [ktlint](https://github.com/ktlint/ktlint) is a Kotlin linter and formatter that enforces the official Kotlin [coding conventions](coding-conventions.html) with no extra configuration. ktlint checks rules such as indentation, spacing around operators, import ordering, and trailing commas. If a violation is found, the build fails with a message indicating the file and line number. Besides reporting violations, ktlint can also automatically fix straightforward issues. To integrate ktlint into your project: 1. Add the plugin to your build file: Maven: ```XML com.github.gantsign.maven ktlint-maven-plugin 3.7.1 check check ``` Gradle: ```KOTLIN // build.gradle.kts plugins { id("org.jlleitschuh.gradle.ktlint") version "12.3.0" } ``` 2. Run the linter to check your code style: Maven: ```BASH mvn ktlint:check ``` Gradle: ```BASH ./gradlew ktlintCheck ``` 3. (Optional) You can also add an `.editorconfig` file to the root of your project to customize rules. For example, to allow wildcard imports and disable trailing comma enforcement: ```INI [*.{kt,kts}] ij_kotlin_imports_layout = * ktlint_standard_trailing-comma-on-call-site = disabled ktlint_standard_trailing-comma-on-declaration-site = disabled ``` By default, ktlint follows the official Kotlin coding conventions. If you prefer the [Android Kotlin style guide](https://developer.android.com/kotlin/style-guide), which differs noticeably from the Kotlin conventions, set the code style to `android_studio` in your `.editorconfig` file: ```INI [*.{kt,kts}] ktlint_code_style = android_studio ``` 4. To automatically fix formatting issues, run: Maven: ```BASH mvn ktlint:format ``` Gradle: ```BASH ./gradlew ktlintFormat ``` For more information on available features and rules, see the [ktlint documentation](https://github.com/ktlint/ktlint/tree/master/documentation). ## Code analysis with detekt [detekt](https://github.com/detekt/detekt) is a static code analysis tool for Kotlin that detects code smells, complexity issues, and potential bugs. To integrate detekt into your project: 1. Add the plugin to your build file: Maven: ```XML com.github.ozsie detekt-maven-plugin 1.23.8 verify check ``` Gradle: ```KOTLIN // build.gradle.kts plugins { id("io.gitlab.arturbosch.detekt") version "1.23.8" } ``` 2. Generate a default `detekt.yml` [configuration file](https://detekt.dev/docs/introduction/configurations): Maven: ```BASH mvn detekt:generate-config ``` Gradle: ```BASH ./gradlew detektGenerateConfig ``` 3. Open the `detekt.yml` file and customize the rules in the generated file, for example: ```YAML complexity: LongMethod: threshold: 50 style: MagicNumber: active: false ``` 4. Reference the configuration file in your build file so that detekt can apply the new rules: Maven: ```XML com.github.ozsie detekt-maven-plugin 1.23.8 detekt.yml txt:reports/detekt.txt xml:reports/detekt.xml verify check ``` Gradle: ```KOTLIN // build.gradle.kts detekt { toolVersion = "1.23.8" config.setFrom(file("config/detekt/detekt.yml")) buildUponDefaultConfig = true } ``` 5. Run the analysis: Maven: ```BASH mvn detekt:check ``` Gradle: ```BASH ./gradlew detekt ``` detekt produces a report listing all rule violations with their severity, file location, and a description of the issue. By default, Gradle outputs reports to `build/reports/detekt`, while Maven outputs to the `reports/detekt` directory in the project root. For more information, see the detekt documentation for [Gradle](https://detekt.dev/docs/intro) and [Maven](https://github.com/Ozsie/detekt-maven-plugin). ## Code quality with SonarSource [SonarQube](https://github.com/SonarSource/sonarqube) and [SonarCloud](https://github.com/marketplace/sonarcloud) from SonarSource provide deep static analysis for Kotlin projects, including bug detection, vulnerability scanning, and code coverage tracking through a web dashboard. To analyze your project with SonarQube: 1. Add the plugin to your build file: Maven: ```XML org.sonarsource.scanner.maven sonar-maven-plugin 5.7.0.6970 ``` Gradle: ```KOTLIN // build.gradle.kts plugins { id("org.sonarqube") version "6.2.0.5505" } sonar { properties { property("sonar.projectKey", "my-project") property("sonar.host.url", "http://localhost:9000") } } ``` 2. (Optional) Configure analysis properties. For example, to make the build wait for the quality gate result and fail if the gate is not passed, add the `sonar.qualitygate.wait` property: Maven: ```BASH mvn verify sonar:sonar \ -Dsonar.qualitygate.wait=true \ -Dsonar.projectKey=my-project \ -Dsonar.host.url=http://localhost:9000 \ -Dsonar.token=YOUR_TOKEN ``` Gradle: ```KOTLIN // build.gradle.kts sonar { properties { property("sonar.qualitygate.wait", "true") } } ``` Note: Quality gate rules (such as minimum coverage thresholds and allowed issue counts) are defined in the SonarQube or SonarCloud web interface under Quality Gates, not in the build file. 3. Run the analysis against your SonarQube server: Maven: ```BASH mvn verify sonar:sonar \ -Dsonar.projectKey=my-project \ -Dsonar.host.url=http://localhost:9000 \ -Dsonar.token=YOUR_TOKEN ``` For SonarCloud, replace the host URL with `https://sonarcloud.io` and provide your organization key: ```BASH mvn verify sonar:sonar \ -Dsonar.projectKey=my-project \ -Dsonar.organization=my-org \ -Dsonar.host.url=https://sonarcloud.io \ -Dsonar.token=YOUR_TOKEN ``` Gradle: To run the analysis, use the `sonar` task and provide your authentication token: ```BASH ./gradlew sonar \ -Dsonar.token=YOUR_TOKEN ``` By default, the analysis is run against a local SonarQube server. To use SonarCloud, update the `sonar {}` block in your `build.gradle.kts` to use `https://sonarcloud.io` and add your organization key: ```KOTLIN sonar { properties { property("sonar.projectKey", "example-project") property("sonar.organization", "example-org") property("sonar.host.url", "https://sonarcloud.io") } } ``` 4. Open the SonarQube or SonarCloud dashboard to review the results. The dashboard shows issues grouped by type (bug, vulnerability, code smell) and severity. For more information, see the [SonarSource documentation](https://docs.sonarsource.com/). ## Code coverage with Kover [Kover](https://github.com/Kotlin/kotlinx-kover) is the official JetBrains code coverage tool for Kotlin. It measures which lines and branches of your code are covered by tests and generates human-readable reports. Unlike [JaCoCo](https://github.com/jacoco/jacoco), Kover correctly interprets Kotlin-specific constructs such as inline functions and data classes, so it reports accurate coverage numbers without false negatives caused by compiler-generated bytecode. To integrate Kover into your project: 1. Add the plugin to your build file: Maven: ```XML org.jetbrains.kotlinx kover-maven-plugin 0.9.8 instr instrumentation kover-verify verify kover-report-xml report-xml kover-report-html report-html ``` Gradle: ```KOTLIN // build.gradle.kts plugins { id("org.jetbrains.kotlinx.kover") version "0.9.8" } ``` 2. Run your tests to collect coverage data and generate the report: Maven: ```BASH mvn verify ``` Gradle: ```BASH ./gradlew koverVerify koverHtmlReport ``` 3. Open the HTML report generated in the `target/site/kover/html/` directory (`build/reports/kover/html/` for Gradle) to review line-by-line coverage. 4. (Optional) To enforce a minimum coverage threshold that fails the build if the conditions are not met, you can add a coverage verification configuration to your build file. For example: Maven: ```XML 50 LINE COVERED_PERCENTAGE ``` Gradle: ```KOTLIN // build.gradle.kts // Add a `kover` configuration block import kotlinx.kover.gradle.plugin.dsl.* kover { reports { total { log { aggregationForGroup = AggregationType.COVERED_PERCENTAGE coverageUnits = CoverageUnit.LINE } verify { rule { minBound(50) } } } } } ``` For more information on configuring verification rules, see the Kover documentation for [Maven](https://kotlin.github.io/kotlinx-kover/maven-plugin/) and [Gradle](https://kotlin.github.io/kotlinx-kover/gradle-plugin/). ## Other tools Besides ktlint, detekt, SonarQube, SonarCloud, and Kover, try out other tools to improve Kotlin code quality: | Tool |Description | --------------------- | [CodeQL](https://codeql.github.com/docs/) |Semantic code analysis engine by GitHub. Supports Kotlin and integrates with GitHub Actions to find security vulnerabilities automatically. | | [Semgrep](https://semgrep.dev/docs/) |Fast, lightweight static analysis tool that supports custom rules. Can be used to enforce patterns or detect anti-patterns in Kotlin code. | | [PMD](https://docs.pmd-code.org/latest/) |Source code analyzer that supports Kotlin (via its CPD copy-paste detector) and detects common programming flaws and duplicate code. | ## What's next * [Run tests in Maven projects](jvm-test-maven.html) * [Configure a Kotlin project with Maven](maven-configure-project.html) # Get started with Spring Boot and Kotlin Get started with Spring Boot and Kotlin by completing this tutorial: it walks you through the process of creating a simple application with Spring Boot and adding a database to store the information. Going through these four steps, you'll learn a lot of essential features of the Kotlin language: ![First step](images/icon-1.svg) [Create a Spring Boot project](jvm-create-project-with-spring-boot.html) ![Second step](images/icon-2.svg) [Add a data class to Spring Boot project](jvm-spring-boot-add-data-class.html) ![Third step](images/icon-3.svg) [Add database support for the Spring Boot project](jvm-spring-boot-add-db-support.html) ![Fourth step](images/icon-4.svg) [Use Spring Data CrudRepository for database access](jvm-spring-boot-using-crudrepository.html) ## Next step [Start](jvm-create-project-with-spring-boot.html) ### See also If you like to work with AI agents, try our tutorial for [creating a task manager application with Spring Boot and Claude](spring-boot-claude.html). Look through our Java to Kotlin (J2K) interop and migration guides: * [Calling Java from Kotlin](java-interop.html) and [Calling Kotlin from Java](java-to-kotlin-interop.html) * [Collections in Java and Kotlin](java-to-kotlin-collections-guide.html) * [Strings in Java and Kotlin](java-to-kotlin-idioms-strings.html) # Create a Spring Boot project with Kotlin The first part of the tutorial shows how to create a Spring Boot project with Gradle in IntelliJ IDEA using the Project Wizard. Note: This tutorial doesn't require using Gradle as the build system. You can follow the same steps if you use Maven. ## Before you start Download and install the latest version of [IntelliJ IDEA](https://www.jetbrains.com/idea/download/) and use an Ultimate subscription. Tip: If you use IntelliJ IDEA without an Ultimate subscription or you use another IDE, you can generate a Spring Boot project using a [web-based project generator](https://start.spring.io/#!language=kotlin&type=gradle-project-kotlin). ## Create a Spring Boot project Create a new Spring Boot project with Kotlin by using the Project Wizard in IntelliJ IDEA: 1. In IntelliJ IDEA, select File | New | Project. 2. In the panel on the left, select Spring Boot in the Generators section. 3. Specify the following fields and options in the New Project window: * Name: demo * Language: Kotlin * Type: Gradle - Kotlin Tip: This option specifies the build system and the DSL. * Package name: com.example.demo * JDK: Java JDK Note: This tutorial uses Amazon Corretto version 23. If you don't have a JDK installed, you can download it from the dropdown list. * Java: 17 Tip: If you don't have Java 17 installed, you can download it from the JDK dropdown list. ![Create Spring Boot project](images/create-spring-boot-project.png) 4. Ensure that you have specified all the fields and click Next. 5. Select the following dependencies that will be required for the tutorial: * Web | Spring Web * SQL | Spring Data JDBC * SQL | H2 Database ![Set up Spring Boot project](images/set-up-spring-boot-project.png) 6. Click Create to generate and set up the project. Tip: The IDE will generate and open a new project. It may take some time to download and import the project dependencies. 7. After this, you can observe the following structure in the Project view: ![Set up Spring Boot project](images/spring-boot-project-view.png)The generated Gradle project corresponds to the Maven's standard directory layout: * There are packages and classes under the `main/kotlin` folder that belong to the application. * The entry point to the application is the `main()` method of the `DemoApplication.kt` file. ## Explore the project Gradle build file Open the `build.gradle.kts` file: it is the Gradle Kotlin build script, which contains a list of the dependencies required for the application. The Gradle file is standard for Spring Boot, but it also contains necessary Kotlin dependencies, including the kotlin-spring Gradle plugin – `kotlin("plugin.spring")`. Here is the full script with the explanation of all parts and dependencies: ```KOTLIN // build.gradle.kts plugins { kotlin("jvm") version "2.3.21" // The version of Kotlin to use kotlin("plugin.spring") version "2.3.21" // The Kotlin Spring plugin id("org.springframework.boot") version "4.1.1" id("io.spring.dependency-management") version "1.1.7" } group = "com.example" version = "0.0.1-SNAPSHOT" java { toolchain { languageVersion = JavaLanguageVersion.of(17) } } repositories { mavenCentral() } dependencies { implementation("org.springframework.boot:spring-boot-h2console") implementation("org.springframework.boot:spring-boot-starter-data-jdbc") implementation("org.springframework.boot:spring-boot-starter-webmvc") implementation("org.jetbrains.kotlin:kotlin-reflect") // Kotlin reflection library, required for working with Spring implementation("tools.jackson.module:jackson-module-kotlin") // Jackson extensions for Kotlin for working with JSON runtimeOnly("com.h2database:h2") testImplementation("org.springframework.boot:spring-boot-starter-data-jdbc-test") testImplementation("org.springframework.boot:spring-boot-starter-webmvc-test") testImplementation("org.jetbrains.kotlin:kotlin-test-junit5") testRuntimeOnly("org.junit.platform:junit-platform-launcher") } kotlin { compilerOptions { freeCompilerArgs.addAll("-Xjsr305=strict", "-Xannotation-default-target=param-property") // `-Xjsr305=strict` enables the strict mode for JSR-305 annotations } } tasks.withType { useJUnitPlatform() } ``` As you can see, there are a few Kotlin-related artifacts added to the Gradle build file: 1. In the `plugins` block, there are two Kotlin artifacts: * The `kotlin("jvm")` plugin defines the version of Kotlin to be used in the project. * The Kotlin Spring compiler plugin, `kotlin("plugin.spring")`, adds the `open` modifier to Kotlin classes to make them compatible with Spring Framework features 2. In the `dependencies` block, a few Kotlin-related modules are listed: * The `tools.jackson.module:jackson-module-kotlin` module adds support for serialization and deserialization of Kotlin classes and data classes. * `org.jetbrains.kotlin:kotlin-reflect` is a Kotlin reflection library that enables full support for the [reflection features](reflection.html). 3. After the dependencies section, you can see the `kotlin` plugin configuration block. This is where you can add extra arguments to the compiler to enable or disable various language features. Learn more about the Kotlin compiler options in [Compiler options in the Kotlin Gradle plugin](gradle-compiler-options.html). ## Explore the generated Spring Boot application Open the `DemoApplication.kt` file: ```KOTLIN // DemoApplication.kt package com.example.demo import org.springframework.boot.autoconfigure.SpringBootApplication import org.springframework.boot.runApplication @SpringBootApplication class DemoApplication fun main(args: Array) { runApplication(*args) } ``` Declaring classes – class DemoApplication : Right after package declaration and import statements you can see the first class declaration, `class DemoApplication`. : In Kotlin, if a class doesn't include any members (properties or functions), you can omit the class body (`{}`) for good. @SpringBootApplication annotation : [@SpringBootApplication annotation](https://docs.spring.io/spring-boot/reference/using/using-the-springbootapplication-annotation.html#using.using-the-springbootapplication-annotation) is a convenience annotation in a Spring Boot application. It enables Spring Boot's [auto-configuration](https://docs.spring.io/spring-boot/reference/using/auto-configuration.html#using.auto-configuration), [component scan](https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/context/annotation/ComponentScan.html), and be able to define an extra configuration on their "application class". Program entry point – main() : The [main()](basic-syntax.html#program-entry-point) function is the entry point to the application. : It is declared as a [top-level function](functions.html#function-scope) outside the `DemoApplication` class. The `main()` function invokes the Spring's `runApplication(*args)` function to start the application with the Spring Framework. Variable arguments – args: Array : If you check the declaration of the `runApplication()` function, you will see that the parameter of the function is marked with [vararg modifier](functions.html#variable-number-of-arguments-varargs): `vararg args: String`. This means that you can pass a variable number of String arguments to the function. The spread operator – (*args) : The `args` is a parameter to the `main()` function declared as an array of Strings. Since there is an array of strings, and you want to pass its content to the function, use the spread operator (prefix the array with a star sign `*`). ## Create a controller The application is ready to run, but let's update its logic first. In the Spring application, a controller is used to handle the web requests. In the same package, next to the `DemoApplication.kt` file, create the `MessageController.kt` file with the `MessageController` class as follows: ```KOTLIN // MessageController.kt package com.example.demo import org.springframework.web.bind.annotation.GetMapping import org.springframework.web.bind.annotation.RequestParam import org.springframework.web.bind.annotation.RestController @RestController class MessageController { @GetMapping("/") fun index(@RequestParam("name") name: String) = "Hello, $name!" } ``` @RestController annotation : You need to tell Spring that `MessageController` is a REST Controller, so you should mark it with the `@RestController` annotation. : This annotation means this class will be picked up by the component scan because it's in the same package as our `DemoApplication` class. @GetMapping annotation : `@GetMapping` marks the functions of the REST controller that implement the endpoints corresponding to HTTP GET calls: : ```KOTLIN @GetMapping("/") fun index(@RequestParam("name") name: String) = "Hello, $name!" ``` @RequestParam annotation : The function parameter `name` is marked with `@RequestParam` annotation. This annotation indicates that a method parameter should be bound to a web request parameter. : Hence, if you access the application at the root and supply a request parameter called "name", like `/?name=`, the parameter value will be used as an argument for invoking the `index()` function. Single-expression functions – index() : Since the `index()` function contains only one statement you can declare it as a [single-expression function](functions.html#single-expression-functions). : This means the curly braces can be omitted and the body is specified after the equals sign `=`. Type inference for function return types : The `index()` function does not declare the return type explicitly. Instead, the compiler infers the return type by looking at the result of the statement on the right-hand side from the equals sign `=`. : The type of `Hello, $name!` expression is `String`, hence the return type of the function is also `String`. String templates – $name : `Hello, $name!` expression is called a [String template](strings.html#string-templates) in Kotlin. : String templates are String literals that contain embedded expressions. : This is a convenient replacement for String concatenation operations. ## Run the application The Spring application is now ready to run: 1. In the `DemoApplication.kt` file, click the green Run icon in the gutter beside the `main()` method: ![Run Spring Boot application](images/run-spring-boot-application.png) Tip: You can also run the `./gradlew bootRun` command in the terminal. This starts the local server on your computer. 2. Once the application starts, open the following URL: ```TEXT http://localhost:8080?name=John ``` You should see "Hello, John!" printed as a response: ![Spring Application response](images/spring-application-response.png) ## Next step In the next part of the tutorial, you'll learn about Kotlin data classes and how you can use them in your application. * [Next step](jvm-spring-boot-add-data-class.html) # Add a data class to Spring Boot project In this part of the tutorial, you'll add some more functionality to the application and discover more Kotlin language features, such as data classes. It requires changing the `MessageController` class to respond with a JSON document containing a collection of serialized objects. ## Update your application 1. In the same package, next to the `DemoApplication.kt` file, create a `Message.kt` file. 2. In the `Message.kt` file, create a data class with two properties: `id` and `text`: ```KOTLIN // Message.kt package com.example.demo data class Message(val id: String?, val text: String) ``` `Message` class will be used for data transfer: a list of serialized `Message` objects will make up the JSON document that the controller is going to respond to the browser request. Data classes – data class Message : The main purpose of [data classes](data-classes.html) in Kotlin is to hold data. Such classes are marked with the `data` keyword, and some standard functionality and some utility functions are often mechanically derivable from the class structure. : In this example, you declared `Message` as a data class as its main purpose is to store the data. val and var properties : [Properties in Kotlin](properties.html) classes can be declared either as: : * mutable, using the `var` keyword * read-only, using the `val` keyword : The `Message` class declares two properties using `val` keyword, the `id` and `text`. The compiler will automatically generate the getters for both of these properties. It will not be possible to reassign the values of these properties after an instance of the `Message` class is created. Nullable types – String? : Kotlin provides [built-in support for nullable types](null-safety.html#nullable-types-and-non-nullable-types). In Kotlin, the type system distinguishes between references that can hold `null` (nullable references) and those that cannot (non-nullable references). For example, a regular variable of type `String` cannot hold `null`. To allow nulls, you can declare a variable as a nullable string by writing `String?`. : The `id` property of the `Message` class is declared as a nullable type this time. Hence, it is possible to create an instance of `Message` class by passing `null` as a value for `id`: : ```KOTLIN Message(null, "Hello!") ``` 3. In the `MessageController.kt` file, instead of the `index()` function, create the `listMessages()` function returning a list of `Message` objects: ```KOTLIN // MessageController.kt package com.example.demo import org.springframework.web.bind.annotation.GetMapping import org.springframework.web.bind.annotation.RequestMapping import org.springframework.web.bind.annotation.RestController @RestController @RequestMapping("/") class MessageController { @GetMapping fun listMessages() = listOf( Message("1", "Hello!"), Message("2", "Bonjour!"), Message("3", "Privet!"), ) } ``` Collections – listOf() : The Kotlin Standard Library provides implementations for basic collection types: sets, lists, and maps. Each collection type can be read-only or mutable: : * A read-only collection comes with operations for accessing collection elements. * A mutable collection comes also with write operations for adding, removing, and updating its elements. : The corresponding factory functions are also provided by the Kotlin Standard Library to create instances of such collections. : In this tutorial, you use the [listOf()](https://kotlinlang.org/api/core/kotlin-stdlib/kotlin.collections/list-of.html) function to create a list of `Message` objects. This is the factory function to create a read-only list of objects: you can't add or remove elements from the list. If it is required to perform write operations on the list, call the [mutableListOf()](https://kotlinlang.org/api/core/kotlin-stdlib/kotlin.collections/mutable-list-of.html) function to create a mutable list instance. Trailing comma : A [trailing comma](coding-conventions.html#trailing-commas) is a comma symbol after the last item of a series of elements: : ```KOTLIN Message("3", "Privet!"), ``` : This is a convenient feature of Kotlin syntax and is entirely optional – your code will still work without them. : In the example above, creating a list of `Message` objects includes the trailing comma after the last `listOf()` function argument. The response from `MessageController` will now be a JSON document containing a collection of `Message` objects. Note: Any controller in the Spring application renders a JSON response by default if the Jackson library is on the classpath. As you [specified the spring-boot-starter-webmvc dependency in the build.gradle.kts file](jvm-create-project-with-spring-boot.html#explore-the-project-gradle-build-file), you received Jackson as a transitive dependency. Hence, the application responds with a JSON document if the endpoint returns a data structure that can be serialized to JSON. Here is a complete code of the `DemoApplication.kt`, `MessageController.kt`, and `Message.kt` files: ```KOTLIN // DemoApplication.kt package com.example.demo import org.springframework.boot.autoconfigure.SpringBootApplication import org.springframework.boot.runApplication @SpringBootApplication class DemoApplication fun main(args: Array) { runApplication(*args) } ``` ```KOTLIN // MessageController.kt package com.example.demo import org.springframework.web.bind.annotation.GetMapping import org.springframework.web.bind.annotation.RequestMapping import org.springframework.web.bind.annotation.RestController @RestController @RequestMapping("/") class MessageController { @GetMapping fun listMessages() = listOf( Message("1", "Hello!"), Message("2", "Bonjour!"), Message("3", "Privet!"), ) } ``` ```KOTLIN // Message.kt package com.example.demo data class Message(val id: String?, val text: String) ``` ## Run the application The Spring application is ready to run: 1. Run the application again. 2. Once the application starts, open the following URL: ```TEXT http://localhost:8080 ``` You will see a page with a collection of messages in JSON format: ![Run the application](images/messages-in-json-format.png) ## Next step In the next part of the tutorial, you'll add and configure a database to your project and make HTTP requests. * [Previous step](jvm-create-project-with-spring-boot.html) * [Next step](jvm-spring-boot-add-db-support.html) # Add database support for Spring Boot project In this part of the tutorial, you'll add and configure a database to your project using Java Database Connectivity (JDBC). In JVM applications, you use JDBC to interact with databases. For convenience, the Spring Framework provides the `JdbcTemplate` class that simplifies the use of JDBC and helps to avoid common errors. ## Add database support The common practice in Spring Framework-based applications is to implement the database access logic within the so-called service layer – this is where business logic lives. In Spring, you should mark classes with the `@Service` annotation to imply that the class belongs to the service layer of the application. In this application, you will create the `MessageService` class for this purpose. In the same package, create the `MessageService.kt` file and the `MessageService` class as follows: ```KOTLIN // MessageService.kt package com.example.demo import org.springframework.stereotype.Service import org.springframework.jdbc.core.JdbcTemplate @Service class MessageService(private val db: JdbcTemplate) { fun findMessages(): List = db.query("select * from messages") { response, _ -> Message(response.getString("id"), response.getString("text")) } fun save(message: Message): Message { db.update( "insert into messages values ( ?, ? )", message.id, message.text ) return message } } ``` Constructor argument and dependency injection – (private val db: JdbcTemplate) : A class in Kotlin has a primary constructor. It can also have one or more [secondary constructors](classes.html#secondary-constructors). The primary constructor is a part of the class header, and it goes after the class name and optional type parameters. In our case, the constructor is `(val db: JdbcTemplate)`. : `val db: JdbcTemplate` is the constructor's argument: : ```KOTLIN @Service class MessageService(private val db: JdbcTemplate) ``` Trailing lambda and SAM conversion : The `findMessages()` function calls the `query()` function of the `JdbcTemplate` class. The `query()` function takes two arguments: an SQL query as a String instance, and a callback that will map one object per row: : ```SQL db.query("...", RowMapper { ... } ) ``` : The `RowMapper` interface declares only one method, so it is possible to implement it via lambda expression by omitting the name of the interface. The Kotlin compiler knows the interface that the lambda expression needs to be converted to because you use it as a parameter for the function call. This is known as [SAM conversion in Kotlin](java-interop.html#sam-conversions): : ```SQL db.query("...", { ... } ) ``` : After the SAM conversion, the query function ends up with two arguments: a String at the first position, and a lambda expression at the last position. According to the Kotlin convention, if the last parameter of a function is a function, then a lambda expression passed as the corresponding argument can be placed outside the parentheses. Such syntax is also known as [trailing lambda](lambdas.html#passing-trailing-lambdas): : ```SQL db.query("...") { ... } ``` Underscore for unused lambda argument : For a lambda with multiple parameters, you can use the underscore `_` character to replace the names of the parameters you don't use. : Hence, the final syntax for the query function call looks like this: : ```KOTLIN db.query("select * from messages") { response, _ -> Message(response.getString("id"), response.getString("text")) } ``` ## Update the MessageController class Update `MessageController.kt` to use the new `MessageService` class: ```KOTLIN // MessageController.kt package com.example.demo import org.springframework.http.ResponseEntity import org.springframework.web.bind.annotation.GetMapping import org.springframework.web.bind.annotation.PostMapping import org.springframework.web.bind.annotation.RequestBody import org.springframework.web.bind.annotation.RequestMapping import org.springframework.web.bind.annotation.RestController import java.net.URI @RestController @RequestMapping("/") class MessageController(private val service: MessageService) { @GetMapping fun listMessages() = service.findMessages() @PostMapping fun post(@RequestBody message: Message): ResponseEntity { val savedMessage = service.save(message) return ResponseEntity.created(URI("/${savedMessage.id}")).body(savedMessage) } } ``` @PostMapping annotation : The method responsible for handling HTTP POST requests needs to be annotated with `@PostMapping` annotation. To be able to convert the JSON sent as HTTP Body content into an object, you need to use the `@RequestBody` annotation for the method argument. Thanks to having the Jackson library in the classpath of the application, the conversion happens automatically. ResponseEntity : `ResponseEntity` represents the whole HTTP response: status code, headers, and body. : Using the `created()` method you configure the response status code (201) and set the location header indicating the context path for the created resource. ## Update the MessageService class The `id` for `Message` class was declared as a nullable String: ```KOTLIN data class Message(val id: String?, val text: String) ``` It would not be correct to store the `null` as an `id` value in the database though: you need to handle this situation gracefully. Update your code of the `MessageService.kt` file to generate a new value when the `id` is `null` while storing the messages in the database: ```KOTLIN // MessageService.kt package com.example.demo import org.springframework.stereotype.Service import org.springframework.jdbc.core.JdbcTemplate import java.util.UUID @Service class MessageService(private val db: JdbcTemplate) { fun findMessages(): List = db.query("select * from messages") { response, _ -> Message(response.getString("id"), response.getString("text")) } fun save(message: Message): Message { val id = message.id ?: UUID.randomUUID().toString() // Generate new id if it is null db.update( "insert into messages values ( ?, ? )", id, message.text ) return message.copy(id = id) // Return a copy of the message with the new id } } ``` Elvis operator – ?: : The code `message.id ?: UUID.randomUUID().toString()` uses the [Elvis operator (if-not-null-else shorthand) ?:](null-safety.html#elvis-operator). If the expression to the left of `?:` is not `null`, the Elvis operator returns it; otherwise, it returns the expression to the right. Note that the expression on the right-hand side is evaluated only if the left-hand side is `null`. The application code is ready to work with the database. It is now required to configure the data source. ## Configure the database Configure the database in the application: 1. Create the `schema.sql` file in the `src/main/resources` directory. It will store the database object definitions: ![Create database schema](images/create-database-schema.png) 2. Update the `src/main/resources/schema.sql` file with the following code: ```SQL -- schema.sql CREATE TABLE IF NOT EXISTS messages ( id VARCHAR(60) PRIMARY KEY, text VARCHAR NOT NULL ); ``` It creates the `messages` table with two columns: `id` and `text`. The table structure matches the structure of the `Message` class. 3. Open the `application.properties` file located in the `src/main/resources` folder and add the following application properties: ``` spring.application.name=demo spring.datasource.driver-class-name=org.h2.Driver spring.datasource.url=jdbc:h2:file:./data/testdb spring.datasource.username=name spring.datasource.password=password spring.sql.init.schema-locations=classpath:schema.sql spring.sql.init.mode=always ``` These settings enable the database for the Spring Boot application. See the full list of common application properties in the [Spring documentation](https://docs.spring.io/spring-boot/appendix/application-properties/index.html). ## Add messages to database via HTTP request You should use an HTTP client to work with previously created endpoints. In IntelliJ IDEA, use the embedded HTTP client: 1. Run the application. Once the application is up and running, you can execute POST requests to store messages in the database. 2. Create the `requests.http` file in the project root folder and add the following HTTP requests: ```HTTP_REQUEST_FULL ### Post "Hello!" POST http://localhost:8080/ Content-Type: application/json { "text": "Hello!" } ### Post "Bonjour!" POST http://localhost:8080/ Content-Type: application/json { "text": "Bonjour!" } ### Post "Privet!" POST http://localhost:8080/ Content-Type: application/json { "text": "Privet!" } ### Get all the messages GET http://localhost:8080/ ``` 3. Execute all POST requests. Use the green Run icon in the gutter next to the request declaration. These requests write the text messages to the database: ![Execute POST request](images/execute-post-requests.png) 4. Execute the GET request and see the result in the Run tool window: ![Execute GET requests](images/execute-get-requests.png) ### Alternative way to execute requests You can also use any other HTTP client or the cURL command-line tool. For example, run the following commands in the terminal to get the same result: ```BASH curl -X POST --location "http://localhost:8080" -H "Content-Type: application/json" -d "{ \"text\": \"Hello!\" }" curl -X POST --location "http://localhost:8080" -H "Content-Type: application/json" -d "{ \"text\": \"Bonjour!\" }" curl -X POST --location "http://localhost:8080" -H "Content-Type: application/json" -d "{ \"text\": \"Privet!\" }" curl -X GET --location "http://localhost:8080" ``` ## Retrieve messages by id Extend the functionality of the application to retrieve the individual messages by id. 1. In the `MessageService` class, add the new function `findMessageById(id: String)` to retrieve the individual messages by id: ```KOTLIN // MessageService.kt package com.example.demo import org.springframework.stereotype.Service import org.springframework.jdbc.core.JdbcTemplate import org.springframework.jdbc.core.query import java.util.* @Service class MessageService(private val db: JdbcTemplate) { fun findMessages(): List = db.query("select * from messages") { response, _ -> Message(response.getString("id"), response.getString("text")) } fun findMessageById(id: String): Message? = db.query("select * from messages where id = ?", id) { response, _ -> Message(response.getString("id"), response.getString("text")) }.singleOrNull() fun save(message: Message): Message { val id = message.id ?: UUID.randomUUID().toString() // Generate new id if it is null db.update( "insert into messages values ( ?, ? )", id, message.text ) return message.copy(id = id) // Return a copy of the message with the new id } } ``` vararg argument position in the parameter list : The `query()` function takes three arguments: : * SQL query string that requires a parameter to run * `id`, which is a parameter of type String * `RowMapper` instance, which implemented by a lambda expression : The second parameter for the `query()` function is declared as a variable argument (`vararg`). In Kotlin, the position of the variable arguments parameter is not required to be the last in the parameters list. singleOrNull() function : The [singleOrNull()](https://kotlinlang.org/api/core/kotlin-stdlib/kotlin.collections/single-or-null.html) function returns a single element, or `null` if the array is empty or has more than one element with the same value. Warning: The `.query()` function used to fetch the message by its id is a [Kotlin extension function](extensions.html#extension-functions) provided by the Spring Framework. It requires an additional import `import org.springframework.jdbc.core.query` as demonstrated in the code above. 2. Add the new `index(...)` function with the `id` parameter to the `MessageController` class: ```KOTLIN // MessageController.kt package com.example.demo import org.springframework.http.ResponseEntity import org.springframework.web.bind.annotation.GetMapping import org.springframework.web.bind.annotation.PathVariable import org.springframework.web.bind.annotation.PostMapping import org.springframework.web.bind.annotation.RequestBody import org.springframework.web.bind.annotation.RequestMapping import org.springframework.web.bind.annotation.RestController import java.net.URI @RestController @RequestMapping("/") class MessageController(private val service: MessageService) { @GetMapping fun listMessages() = ResponseEntity.ok(service.findMessages()) @PostMapping fun post(@RequestBody message: Message): ResponseEntity { val savedMessage = service.save(message) return ResponseEntity.created(URI("/${savedMessage.id}")).body(savedMessage) } @GetMapping("/{id}") fun getMessage(@PathVariable id: String): ResponseEntity = service.findMessageById(id).toResponseEntity() private fun Message?.toResponseEntity(): ResponseEntity = // If the message is null (not found), set response code to 404 this?.let { ResponseEntity.ok(it) } ?: ResponseEntity.notFound().build() } ``` Retrieving a value from the context path : The message `id` is retrieved from the context path by the Spring Framework as you annotated the new function by `@GetMapping("/{id}")`. By annotating the function argument with `@PathVariable`, you tell the framework to use the retrieved value as a function argument. The new function makes a call to `MessageService` to retrieve the individual message by its id. Extension function with nullable receiver : Extensions can be defined with a nullable receiver type. If the receiver is `null`, then `this` is also `null`. So when defining an extension with a nullable receiver type, it is recommended performing a `this == null` check inside the function body. : You can also use the null-safe invocation operator (`?.`) to perform the null check as in the `toResponseEntity()` function above: : ```KOTLIN this?.let { ResponseEntity.ok(it) } ``` ResponseEntity : `ResponseEntity` represents the HTTP response, including the status code, headers, and body. It is a generic wrapper that allows you to send customized HTTP responses back to the client with more control over the content. Here is a complete code of the application: ```KOTLIN // DemoApplication.kt package com.example.demo import org.springframework.boot.autoconfigure.SpringBootApplication import org.springframework.boot.runApplication @SpringBootApplication class DemoApplication fun main(args: Array) { runApplication(*args) } ``` ```KOTLIN // Message.kt package com.example.demo data class Message(val id: String?, val text: String) ``` ```KOTLIN // MessageService.kt package com.example.demo import org.springframework.stereotype.Service import org.springframework.jdbc.core.JdbcTemplate import org.springframework.jdbc.core.query import java.util.* @Service class MessageService(private val db: JdbcTemplate) { fun findMessages(): List = db.query("select * from messages") { response, _ -> Message(response.getString("id"), response.getString("text")) } fun findMessageById(id: String): Message? = db.query("select * from messages where id = ?", id) { response, _ -> Message(response.getString("id"), response.getString("text")) }.singleOrNull() fun save(message: Message): Message { val id = message.id ?: UUID.randomUUID().toString() db.update( "insert into messages values ( ?, ? )", id, message.text ) return message.copy(id = id) } } ``` ```KOTLIN // MessageController.kt package com.example.demo import org.springframework.http.ResponseEntity import org.springframework.web.bind.annotation.GetMapping import org.springframework.web.bind.annotation.PathVariable import org.springframework.web.bind.annotation.PostMapping import org.springframework.web.bind.annotation.RequestBody import org.springframework.web.bind.annotation.RequestMapping import org.springframework.web.bind.annotation.RestController import java.net.URI @RestController @RequestMapping("/") class MessageController(private val service: MessageService) { @GetMapping fun listMessages() = ResponseEntity.ok(service.findMessages()) @PostMapping fun post(@RequestBody message: Message): ResponseEntity { val savedMessage = service.save(message) return ResponseEntity.created(URI("/${savedMessage.id}")).body(savedMessage) } @GetMapping("/{id}") fun getMessage(@PathVariable id: String): ResponseEntity = service.findMessageById(id).toResponseEntity() private fun Message?.toResponseEntity(): ResponseEntity = this?.let { ResponseEntity.ok(it) } ?: ResponseEntity.notFound().build() } ``` ## Run the application The Spring application is ready to run: 1. Run the application again. 2. Open the `requests.http` file and add the new GET request: ```HTTP_REQUEST_FULL ### Get the message by its id GET http://localhost:8080/id ``` 3. Execute the GET request to retrieve all the messages from the database. 4. In the Run tool window, copy one of the ids and add it to the request, like this: ```HTTP_REQUEST_FULL ### Get the message by its id GET http://localhost:8080/f910aa7e-11ee-4215-93ed-1aeeac822707 ``` Note: Put your message id instead of the mentioned above. 5. Execute the GET request and see the result in the Run tool window: ![Retrieve message by its id](images/retrieve-message-by-its-id.png) ## Next step The final step shows you how to use a more popular connection to the database using Spring Data. * [Previous step](jvm-spring-boot-add-data-class.html) * [Next step](jvm-spring-boot-using-crudrepository.html) # Use Spring Data CrudRepository for database access In this part, you will migrate the service layer to use the [Spring Data](https://docs.spring.io/spring-data/commons/docs/current/api/org/springframework/data/repository/CrudRepository.html) `CrudRepository` instead of `JdbcTemplate` for database access. CrudRepository is a Spring Data interface for generic [CRUD](https://en.wikipedia.org/wiki/Create,_read,_update_and_delete) operations on a repository of a specific type. It provides several methods out of the box for interacting with a database. ## Update your application First, you need to adjust the `Message` class for work with the `CrudRepository` API: 1. Add the `@Table` annotation to the `Message` class to declare mapping to a database table. Add the `@Id` annotation before the `id` field. Note: These annotations also require additional imports. ```KOTLIN // Message.kt package com.example.demo import org.springframework.data.annotation.Id import org.springframework.data.relational.core.mapping.Table @Table("MESSAGES") data class Message(@Id val id: String?, val text: String) ``` In addition, to make the use of the `Message` class more idiomatic, you can set the default value for `id` property to null and flip the order of the data class properties: ```KOTLIN @Table("MESSAGES") data class Message(val text: String, @Id val id: String? = null) ``` Now if you need to create a new instance of the `Message` class, you can only specify the `text` property as a parameter: ```KOTLIN val message = Message("Hello") // id is null ``` 2. Declare an interface for the `CrudRepository` that will work with the `Message` data class. Create the `MessageRepository.kt` file and add the following code to it: ```KOTLIN // MessageRepository.kt package com.example.demo import org.springframework.data.repository.CrudRepository interface MessageRepository : CrudRepository ``` 3. Update the `MessageService` class. It will now use the `MessageRepository` instead of executing SQL queries: ```KOTLIN // MessageService.kt package com.example.demo import org.springframework.data.repository.findByIdOrNull import org.springframework.stereotype.Service @Service class MessageService(private val db: MessageRepository) { fun findMessages(): List = db.findAll().toList() fun findMessageById(id: String): Message? = db.findByIdOrNull(id) fun save(message: Message): Message = db.save(message) } ``` Extension functions : The `findByIdOrNull()` function is an [extension function](extensions.html#extension-functions) for `CrudRepository` interface in Spring Data JDBC. CrudRepository save() function : [This function works](https://docs.spring.io/spring-data/relational/reference/#jdbc.entity-persistence) with an assumption that the new object doesn't have an id in the database. Hence, the id should be null for insertion. : If the id isn't null, `CrudRepository` assumes that the object already exists in the database and this is an update operation as opposed to an insert operation. After the insert operation, the `id` will be generated by the data store and assigned back to the `Message` instance. 4. Update the messages table definition to generate the ids for the inserted objects. Since `id` is a string, you can use the `RANDOM_UUID()` function to generate the id value by default: ```SQL -- schema.sql CREATE TABLE IF NOT EXISTS messages ( id VARCHAR(60) DEFAULT RANDOM_UUID() PRIMARY KEY, text VARCHAR NOT NULL ); ``` 5. Update the name of the database in the `application.properties` file located in the `src/main/resources` folder: ``` spring.application.name=demo spring.datasource.driver-class-name=org.h2.Driver spring.datasource.url=jdbc:h2:file:./data/testdb2 spring.datasource.username=name spring.datasource.password=password spring.sql.init.schema-locations=classpath:schema.sql spring.sql.init.mode=always ``` Here is the complete code of the application: ```KOTLIN // DemoApplication.kt package com.example.demo import org.springframework.boot.autoconfigure.SpringBootApplication import org.springframework.boot.runApplication @SpringBootApplication class DemoApplication fun main(args: Array) { runApplication(*args) } ``` ```KOTLIN // Message.kt package com.example.demo import org.springframework.data.annotation.Id import org.springframework.data.relational.core.mapping.Table @Table("MESSAGES") data class Message(val text: String, @Id val id: String? = null) ``` ```KOTLIN // MessageRepository.kt package com.example.demo import org.springframework.data.repository.CrudRepository interface MessageRepository : CrudRepository ``` ```KOTLIN // MessageService.kt package com.example.demo import org.springframework.data.repository.findByIdOrNull import org.springframework.stereotype.Service @Service class MessageService(private val db: MessageRepository) { fun findMessages(): List = db.findAll().toList() fun findMessageById(id: String): Message? = db.findByIdOrNull(id) fun save(message: Message): Message = db.save(message) } ``` ```KOTLIN // MessageController.kt package com.example.demo import org.springframework.http.ResponseEntity import org.springframework.web.bind.annotation.GetMapping import org.springframework.web.bind.annotation.PathVariable import org.springframework.web.bind.annotation.PostMapping import org.springframework.web.bind.annotation.RequestBody import org.springframework.web.bind.annotation.RequestMapping import org.springframework.web.bind.annotation.RestController import java.net.URI @RestController @RequestMapping("/") class MessageController(private val service: MessageService) { @GetMapping fun listMessages() = ResponseEntity.ok(service.findMessages()) @PostMapping fun post(@RequestBody message: Message): ResponseEntity { val savedMessage = service.save(message) return ResponseEntity.created(URI("/${savedMessage.id}")).body(savedMessage) } @GetMapping("/{id}") fun getMessage(@PathVariable id: String): ResponseEntity = service.findMessageById(id).toResponseEntity() private fun Message?.toResponseEntity(): ResponseEntity = // If the message is null (not found), set response code to 404 this?.let { ResponseEntity.ok(it) } ?: ResponseEntity.notFound().build() } ``` ## Run the application Congratulations! The application is ready to run again. After replacing `JdbcTemplate` with `CrudRepository`, the functionality remains the same, so the application works just as before. You can now [run the POST and GET HTTP requests](jvm-spring-boot-add-db-support.html#add-messages-to-database-via-http-request) from the `requests.http` file and get the same results. * [Previous step](jvm-spring-boot-add-db-support.html) ## What's next Get your personal language map to help you navigate Kotlin features and track your progress in studying the language: [Get the Kotlin language map](https://resources.jetbrains.com/storage/products/kotlin/docs/Kotlin_Language_Features_Map.pdf) * Check out the [Spring Framework](https://docs.spring.io/spring-framework/reference/) documentation. * Create a simple web application with protected resources in the [Securing a web application](https://spring.io/guides/gs/securing-web) tutorial. * Complete the [Building web applications with Spring Boot and Kotlin](https://spring.io/guides/tutorials/spring-boot-kotlin) tutorial. # Create a task manager app with Spring Boot and Claude In this tutorial, you'll learn how to use [Claude](https://claude.com/product/overview) to create a Kotlin app to manage tasks. The tutorial uses Spring Boot to manage the backend infrastructure, while Claude plans and develops the application. If you prefer to create an app without the help of AI, you can follow our [Create a web app with Kotlin and Spring Boot](jvm-get-started-spring-boot.html) tutorial. Note: As with any AI-powered tool, Claude can make mistakes. Review Claude's changes carefully and only use it with code you trust. For more information on Claude's security policy, see [Claude Code Docs](https://code.claude.com/docs/en/security). ## Set up the environment Tip: This tutorial uses Claude through the JetBrains AI Assistant, but you can also work through the tutorial steps using Claude Code in the terminal. 1. Download and install the latest version of [IntelliJ IDEA](https://www.jetbrains.com/idea/download/). 2. Install the [JetBrains AI Assistant](https://plugins.jetbrains.com/plugin/22282-jetbrains-ai-assistant). 3. Activate Claude Agent in one of the following ways: * [Using a JetBrains AI subscription](https://www.jetbrains.com/help/ai-assistant/activate-agents.html#activate-claude-agent-with-jbai-subscription) * [Using an API key](https://www.jetbrains.com/help/ai-assistant/activate-agents.html#activate-claude-agent-with-api-key) * [Using Anthropic Console](https://www.jetbrains.com/help/ai-assistant/activate-agents.html#activate-agent-with-provider-specific-method) ## Create a project Tip: You can also create a Spring Boot project using [Spring's web-based project generator](https://start.spring.io/#!language=kotlin&type=gradle-project-kotlin). Create a new Spring Boot project in IntelliJ IDEA: 1. In IntelliJ IDEA, select File | New | Project. 2. In the panel on the left, select New Project | Spring Boot. 3. Specify the following fields and options in the New Project window: * Name: task-manager-demo * Language: Kotlin * Type: Gradle - Kotlin Tip: This option specifies the build system and the DSL. * Package name: org.jetbrains.kotlin.taskmanagerdemo * JDK: jbr-21 * Java: 17 Tip: If you don't have these Java and JDK versions installed, you can download them from the dropdown lists. ![Create Spring Boot project](images/create-spring-claude-project.png) 4. Make sure that you specified all the fields, then click Next. 5. Select the latest stable Spring Boot version in the Spring Boot field. 6. Select the Web | Spring Web dependency. ![Set up Spring Boot project](images/spring-claude-dependency.png) 7. Click Create to generate and set up the project. The IDE generates and opens the new project. It may take some time to download and import the project dependencies. ## Create a development plan In your project: 1. Open the ![AI Chat](images/toolWindowChat%4020x20.svg) AI Chat tool window. By default, the Chat mode is selected. Select Claude Agent. ![Select Claude Agent](images/select-claude-agent.png) 2. Click Mode: Default ![Operation mode](images/app-client.expui.general.chevronDownLarge.svg) and select Mode: Plan Mode. Claude Agent is now ready to plan without executing actions. ![Select Plan Mode](images/claude-plan-mode.png) Tip: For more information about the different operation modes, see [Select operation mode](https://www.jetbrains.com/help/ai-assistant/claude-agent.html#select-operation-mode). 3. Write a prompt asking Claude to create a task manager app. Share some details on what you think it should include. For example: ```TEXT I'd like to create a task manager application for managing tasks, such as a grocery list. It should have a basic UI and include categories, due dates, priorities, and status tracking. Use VCS while working. Work step by step and create commits at each stage so I can review the changes afterward. ``` Tip: For guidance on how to design your prompt, see [Claude Code best practices](https://code.claude.com/docs/en/best-practices). Claude explores the existing project structure and suggests a plan. 4. Review the plan carefully before proceeding. If you want to make some modifications, select No, keep planning and share your follow-up comments. 5. When you're ready to proceed, select the Yes ... option that fits how much control you want over Claude's changes. ![Ready to code](images/ready-to-code.png) Tip: For more information on the different options, see [Claude Code permission modes](https://code.claude.com/docs/en/best-practices). 6. Claude exits Plan Mode and begins working. Wait until the work is complete. ## Review the commits Before running the app, review the generated changes carefully: 1. Open the Git tool window to see the list of commits. 2. Select a commit and double-click each modified file to review the diff in IntelliJ IDEA's side-by-side viewer. ![Side-by-side viewer](images/side-by-side-viewer.png) ## Run the app Once you are happy with the changes, run the app: 1. Run the `bootRun` Gradle task or enter the following command in the terminal: ```BASH ./gradlew bootRun ``` 2. In a browser, open the localhost URL. The default is usually: ```TEXT http://localhost:8080 ``` You should now see the basic UI that Claude created. ![Run the app](images/run-spring-claude-app.png) Tip: Since Claude designs the UI, your UI may look different from the version in this tutorial. ## Test the app Now it's time for you to test the app. ### Test the UI manually Start by testing the UI functionality. Try some simple actions: 1. Create a task and test the form fields. 2. Edit a task to check that changes persist. 3. Change the status of a task. 4. Delete a task. 5. Change the category of a task. If any of these actions don't work, send a new prompt to Claude asking it to investigate and fix the problem. ### Run unit tests Claude also creates some tests automatically. Check that all the tests pass by running: ```BASH ./gradlew test ``` Alternatively, in the `src/test` directory, open a test and click the run icon ![run icon](images/app-client.expui.run.run.svg) in the gutter. A successful test shows ![run success icon](images/app-client.expui.gutter.runSuccess.svg). If any test doesn't work, send a new prompt to Claude asking it to investigate and fix the problem. ## Make refinements Now that the initial task is complete, you can make refinements. For example, let's improve the UI so users can edit tasks directly in the list. You can send a prompt like: ```TEXT As a next step, allow users to edit tasks inline. For example, let users click on a task title to edit it directly in the list, and update fields like priority, due date, or status without leaving the current view. This change should make the app feel faster and more intuitive to use. ``` Just as before, Claude explores the existing project structure and suggests a plan. After you accept the plan, wait for Claude to finish, review the changes, and then run the app again. ![Refine your Spring Boot app with Claude](images/make-refinements-claude.gif) Congratulations! You used Claude to plan, build, test, and refine a Kotlin Spring Boot application directly in IntelliJ IDEA. ## What's next? * Learn about [Kotlin AI skills](kotlin-ai-skills.html) * Check out our tutorial on using [Junie with Kotlin AI skills](https://kotlinlang.org/docs/multiplatform/multiplatform-cocoapods-spm-migration-ai.html) # Overview Kotlin, through Kotlin Multiplatform, offers two approaches for web development: * [JavaScript-based (using the Kotlin/JS compiler)](#kotlin-js) * [WebAssembly-based (using the Kotlin/Wasm compiler)](#kotlin-wasm) Both approaches let you share code in your web app, but they support different use cases. They also differ in technical aspects such as target browser support. ## Kotlin/JS [Kotlin/JS](js-overview.html) enables running Kotlin apps in JavaScript (JS) environments by transpiling your code, standard library, and all the supported dependencies into JS. When developing with Kotlin/JS, you can run your apps either in the browser or the Node.js environment. Tip: For information about configuring Kotlin/JS targets, see the [Configure a Gradle project](gradle-configure-project.html#targeting-javascript) guide. ### Kotlin/JS use cases Kotlin/JS is suitable when your goal is to: * [Share business logic with a JavaScript/TypeScript codebase](#share-business-logic-with-a-javascript-typescript-codebase). * [Build non-shareable web apps with Kotlin](#build-web-apps-with-kotlin-without-sharing-the-code). #### Share business logic with a JavaScript/TypeScript codebase If you need to share Kotlin code (such as domain or data logic) with a native JavaScript/TypeScript app, the Kotlin/JS target offers: * Direct interoperability with JavaScript/TypeScript. * Minimal overhead in interoperability (for example, avoiding unnecessary data copying). This allows the shared code to integrate smoothly into a JS-based workflow. #### Build web apps with Kotlin without sharing the code For projects where the web app is implemented entirely in Kotlin, without sharing it with other platforms (iOS, Android, or Desktop), an HTML-based solution provides better control. HTML-based solutions improve SEO and accessibility. They also provide better browser integration, including features such as find on page and page translation. For HTML-based solutions, Kotlin/JS supports multiple approaches: * Using Compose HTML-based frameworks, such as [Kobweb](https://kobweb.varabyte.com/) or [Kilua](https://kilua.dev/), to build UIs with a Compose-style architecture. * Using React-based solutions with Kotlin wrappers to implement [React components in Kotlin](https://kotlinlang.org/docs/js-react.html). ## Kotlin/Wasm [Kotlin/Wasm](wasm-overview.html) compiles Kotlin code into WebAssembly (Wasm), enabling apps to run across environments and devices that support Wasm while meeting Kotlin’s requirements. In browsers, Kotlin/Wasm lets you build web apps with [Compose Multiplatform](https://kotlinlang.org/compose-multiplatform/). Outside the browser, it runs in standalone Wasm virtual machines, using the [WebAssembly System Interface (WASI)](https://wasi.dev/) to access platform APIs. When developing with Kotlin/Wasm, you can target: * `wasmJs`: for running in browsers or Node.js. * `wasmWasi`: for running in Wasm environments supporting WASI, such as Wasmtime, WasmEdge, and so on. Tip: For information about configuring Kotlin/Wasm targets, see the [Configure a Gradle project](gradle-configure-project.html#targeting-webassembly) guide. ### Kotlin/Wasm use cases Use Kotlin/Wasm if you want to share both logic and UI across multiple platforms. #### Build cross-platform apps with Compose Multiplatform If you want to share both logic and UI across multiple platforms, including web, Kotlin/Wasm with [Compose Multiplatform](https://kotlinlang.org/compose-multiplatform/) provides a shared UI layer: * Ensuring a consistent UI implementation for all platforms. * Using Wasm for improved rendering and smoother UI updates, such as responsive animations. * Supporting the latest version of the [WebAssembly Garbage Collection (WasmGC)](https://developer.chrome.com/blog/wasmgc) proposal, which allows Kotlin/Wasm to run on all major modern browsers. ## Choose your web approach The table below summarizes the recommended target based on your use case: | Use case |Recommended target |Description | --------------------------------------------- | Sharing business logic, but using web-native UI |Kotlin/JS |Offers straightforward interop with JS and minimal overhead. | | Sharing both UI and business logic |Kotlin/Wasm |Provides better performance for rendering with [Compose Multiplatform](https://kotlinlang.org/compose-multiplatform/). | | Non-shareable UI |Kotlin/JS |Allows building UIs with HTML-based frameworks like [Kobweb](https://kobweb.varabyte.com/), [Kilua](https://kilua.dev/), or [React](https://kotlinlang.org/docs/js-react.html), using existing JS ecosystems and tooling. | Note: If you need guidance on selecting the appropriate target, join our [Slack community](https://slack-chats.kotlinlang.org/c/multiplatform). You can ask about platform differences, performance considerations, and recommended practices for specific use cases. ## Compatibility mode for web targets You can enable compatibility mode for your web app to ensure it works on all browsers out of the box. In this mode, you can build the UI with Wasm for modern browsers, while older ones fall back to JS. Compatibility mode is achieved through cross-compilation for both the `js` and `wasmJs` targets. [See more information about compatibility mode for web and how to enable it](https://kotlinlang.org/docs/multiplatform/compose-multiplatform-create-first-app.html#compatibility-mode-for-web-targets). # Kotlin/JavaScript Kotlin/JavaScript (Kotlin/JS) lets you transpile your Kotlin code, the Kotlin standard library, and any compatible dependencies to JavaScript. This way, your Kotlin applications can run in any environment that supports JavaScript. Use Kotlin/JS through the [Kotlin Multiplatform Gradle plugin](https://kotlinlang.org/docs/multiplatform/multiplatform-dsl-reference.html) (`kotlin.multiplatform`) to configure and manage Kotlin projects targeting JavaScript from a single place. The Kotlin Multiplatform Gradle plugin gives you access to features such as controlling your application's bundling and adding JavaScript dependencies directly from npm. To get an overview of the available configuration options, see [Set up a Kotlin/JS project](js-project-setup.html). Tip: The current implementation of Kotlin/JS targets the [ES5](https://www.ecma-international.org/ecma-262/5.1/) and [ES2015](https://262.ecma-international.org/6.0/) standards. ## Use cases for Kotlin/JS Here are some common ways to use Kotlin/JS: * Sharing common logic between frontend and JVM backend If your backend is written in Kotlin or another JVM-compatible language, you can share common code between your web application and the backend. This includes data-transfer objects (DTOs), validation and authentication rules, abstractions for REST API endpoints, and more. * Sharing common logic between Android, iOS, and web clients You can share business logic between your web interface and mobile applications for Android and iOS, while keeping native user interfaces. This avoids duplicating common functionality such as REST API abstractions, user authentication, form validation, and domain models. * Building frontend web applications using Kotlin/JS Use Kotlin to develop traditional web frontends while integrating with existing tools and libraries: * If you are familiar with Android development, you can build web applications with Compose-based frameworks like [Kobweb](https://kobweb.varabyte.com/) or [Kilua](https://kilua.dev/). * Build fully type-safe React applications with Kotlin/JS using the [Kotlin wrappers for common JavaScript libraries](https://github.com/JetBrains/kotlin-wrappers) provided by JetBrains. The Kotlin wrappers (`kotlin-wrappers`) offer abstractions and integrations for React and other JavaScript frameworks. These wrappers also support complementary libraries, like [React Redux](https://react-redux.js.org/), [React Router](https://reactrouter.com/), and [styled-components](https://styled-components.com/). You can also use third-party React components and component libraries through interoperability with the JavaScript ecosystem. * Use [Kotlin/JS frameworks](js-frameworks.html), which integrate with the Kotlin ecosystem and support concise and expressive code. * Building multiplatform applications that support older browsers With Compose Multiplatform, you can use Kotlin to build applications and reuse mobile and desktop user interfaces in your web projects. While [Kotlin/Wasm](wasm-overview.html) is the primary target for this purpose, you can extend support to older browsers by also targeting Kotlin/JS. * Building server-side and serverless applications using Kotlin/JS The Node.js target in Kotlin/JS lets you create applications for server-side or serverless environments on a JavaScript runtime. This offers a fast startup and low memory usage. The [kotlinx-nodejs](https://github.com/Kotlin/kotlinx-nodejs) library provides type-safe access to the [Node.js API](https://nodejs.org/docs/latest/api/) from Kotlin. Depending on your use case, Kotlin/JS projects can use compatible libraries from the Kotlin ecosystem and third-party libraries from the JavaScript and TypeScript ecosystems. To use third-party libraries from your Kotlin code, you can create your own type-safe wrappers or use community-maintained wrappers. Additionally, you can use the Kotlin/JS [dynamic type](dynamic-type.html), which lets you skip strict typing and library wrappers, at the cost of type safety. Kotlin/JS is also compatible with the most common module systems: [ESM](https://tc39.es/ecma262/#sec-modules), [CommonJS](https://nodejs.org/api/modules.html#modules-commonjs-modules), [UMD](https://github.com/umdjs/umd), and [AMD](https://github.com/amdjs/amdjs-api). This allows you to [produce and consume modules](js-modules.html) and integrate with the JavaScript ecosystem in a structured manner. ### Share your use cases The list in [Use cases for Kotlin/JS](#use-cases-for-kotlin-js) isn't exhaustive. Feel free to experiment with different approaches and find the best fit for your project. Share your use cases, experiences, and questions with the Kotlin/JS community in the [#javascript](https://kotlinlang.slack.com/archives/C0B8L3U69) channel on [Kotlin Slack](https://surveys.jetbrains.com/s3/kotlin-slack-sign-up). ## Get started with Kotlin/JS Explore the fundamentals and initial steps to start working with Kotlin/JS: * If you're new to Kotlin, start by reviewing the [basic syntax](basic-syntax.html) and exploring the [Kotlin tour](kotlin-tour-welcome.html). * Check out the list of [Kotlin/JS sample projects](#sample-projects-for-kotlin-js) for inspiration. These samples contain useful code snippets and patterns that can help you get started with your projects. * If you’re new to Kotlin/JS, start with the [setup guide](js-project-setup.html) before exploring more advanced topics. Would you like to try Kotlin/JS yourself? [Get started with Kotlin/JS](js-get-started.html) ## Sample projects for Kotlin/JS The following table lists a set of sample projects demonstrating various Kotlin/JS use cases, architectures, and code-sharing strategies: | Project |Description | ------------------------ | [Petclinic with common code between Spring and Angular](https://github.com/Kotlin/kmp-spring-petclinic/#readme) |Demonstrates how to avoid code duplication in enterprise applications by sharing data-transfer objects, validation and authentication rules, and abstractions for REST API endpoints. The code is shared between a [Spring Boot](https://spring.io/projects/spring-boot) backend and a [Angular](https://angular.dev/) frontend. | | [Fullstack Conference CMS](https://github.com/Kotlin/kmp-fullstack-conference-cms/#readme) |Showcases multiple code-sharing approaches, ranging from the simplest to all-in code sharing between [Ktor](https://ktor.io/), [Jetpack Compose](https://developer.android.com/compose), and [Vue.js](https://vuejs.org/) applications. | | [Todo App on a Compose-HTML-based Kobweb framework](https://github.com/varabyte/kobweb-templates/tree/main/examples/todo/#readme) |Shows how to create a to-do list application by reusing an approach familiar to Android developers. It builds a client UI application powered by the [Kobweb framework](https://kobweb.varabyte.com/). | | [Simple logic sharing between Android, iOS, and web](https://github.com/Kotlin/kmp-logic-sharing-simple-example/#readme) |Contains a template for building a project with common logic in Kotlin, which is consumed in platform-native UI applications on Android ([Jetpack Compose](https://developer.android.com/compose)), iOS ([SwiftUI](https://developer.apple.com/tutorials/swiftui/)), and web ([React](https://react.dev/)). | | [Full-stack collaborative to-do list](https://github.com/kotlin-hands-on/jvm-js-fullstack/#readme) |Shows how to create a to-do list application for collaborative work using Kotlin Multiplatform with JS and JVM targets. It uses [Ktor](https://ktor.io/) for the backend, and Kotlin/JS with React for the frontend. | ## Kotlin/JS frameworks Kotlin/JS frameworks simplify web development by providing ready-to-use components, routing, state management, and other tools for building modern web applications. [Check the available frameworks for Kotlin/JS written by different authors](js-frameworks.html). ## Join the Kotlin/JS community You can join the [#javascript](https://kotlinlang.slack.com/archives/C0B8L3U69) channel in the official [Kotlin Slack](https://surveys.jetbrains.com/s3/kotlin-slack-sign-up) to chat with the community and the Kotlin/JS team. ## What's next * [Set up a Kotlin/JS project](js-project-setup.html) * [Run Kotlin/JS projects](running-kotlin-js.html) * [Debug Kotlin/JS code](js-debugging.html) * [Run tests in Kotlin/JS](js-running-tests.html) # Get started with Kotlin/JS This tutorial shows how to create a web application for the browser using Kotlin/JavaScript (Kotlin/JS). To create your app, choose the tool that best fits your workflow: * [IntelliJ IDEA](#create-your-application-in-intellij-idea): clone the project template from version control and work on it in IntelliJ IDEA. * [Gradle build system](#create-your-application-using-gradle): create build files for your project manually to better understand how the setup works under the hood. Tip: Besides targeting the browser, with Kotlin/JS you can compile for other environments. For more information, see [Execution environments](js-project-setup.html#execution-environments). ## Create your application in IntelliJ IDEA To create your Kotlin/JS web application, you can use [IntelliJ IDEA](https://www.jetbrains.com/idea/download/). ### Set up the environment 1. Download and install the latest version of [IntelliJ IDEA](https://www.jetbrains.com/idea/). 2. Install the [Kotlin Multiplatform IDE plugin](https://plugins.jetbrains.com/plugin/14936-kotlin-multiplatform) (not to be confused with the Kotlin Multiplatform Gradle plugin). ### Create your project 1. In IntelliJ IDEA, select File | New | Project from Version Control. 2. Enter the URL of the [Kotlin/JS template project](https://github.com/Kotlin/kmp-js-wizard): ```TEXT https://github.com/Kotlin/kmp-js-wizard ``` 3. Click Clone. ### Configure your project 1. Open the `kmp-js-wizard/gradle/libs.versions.toml` file. It contains the version catalog for project dependencies. 2. Make sure the Kotlin version matches the version of the Kotlin Multiplatform Gradle plugin, which is required to create a web application targeting Kotlin/JS: ```TOML [versions] kotlin = "2.4.20" [plugins] kotlin-multiplatform = { id = "org.jetbrains.kotlin.multiplatform", version.ref = "kotlin" } ``` 3. Synchronize the Gradle files (if you updated the `libs.versions.toml` file). Click the Load Gradle Changes icon that appears in your build file. ![Load the Gradle changes button](images/load-gradle-changes.png)Alternatively, click the refresh button in the Gradle tool window. For more information about the Gradle configuration for multiplatform projects, see the [Multiplatform Gradle DSL reference](https://kotlinlang.org/docs/multiplatform/multiplatform-dsl-reference.html). ### Build and run the application 1. Open the `src/jsMain/kotlin/Main.kt` file. * The `src/jsMain/kotlin/` directory contains the main Kotlin source files for the JavaScript target of your project. * The `Main.kt` file includes code that uses the [kotlinx.browser](https://github.com/Kotlin/kotlinx-browser) API to render "Hello, Kotlin/JS!" on the browser page. 2. Click the Run icon in the `main()` function to run the code. ![Run the application](images/js-run-gutter.png) The web application opens automatically in your browser. Alternatively, you can open the following URL in your browser when the run is finished: ```TEXT http://localhost:8080/ ``` You can see the web application: ![Application output](images/js-output-gutter-1.png) After you run the application for the first time, IntelliJ IDEA creates its corresponding run configuration (jsMain [js]) at the top bar: ![Gradle run configuration](images/js-run-config.png) Tip: In IntelliJ IDEA with an Ultimate subscription, you can use the [JS Debugger](https://www.jetbrains.com/help/idea/configuring-javascript-debugger.html) to debug code directly from the IDE. ### Enable continuous build Gradle can automatically rebuild your project whenever you make changes: 1. Select jsMain [js] in the list of run configurations and click More Actions | Edit. ![Gradle edit run configuration](images/js-edit-run-config.png) 2. In the Run/Debug Configurations dialog, enter `jsBrowserDevelopmentRun --continuous` within the Run field. ![Continuous run configuration](images/js-continuous-run-config.png) 3. Click OK. Now, when you run the application and make any changes, Gradle automatically performs incremental builds for the project and hot-reloads the browser whenever you save (`Ctrl + S`/`Cmd + S`) or change a class file. ### Modify the application Modify the application to add a feature that counts the number of letters in a word. #### Add an input element 1. In the `src/jsMain/kotlin/Main.kt` file, add an [HTML input element](https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/input) through an [extension function](extensions.html#extension-functions) to read user input: ```KOTLIN // Replace the Element.appendMessage() function fun Element.appendInput() { val input = document.createElement("input") appendChild(input) } ``` 2. Call the `appendInput()` function in `main()`. It displays an input element on the page: ```KOTLIN fun main() { // Replace document.body!!.appendMessage(message) document.body?.appendInput() } ``` 3. [Run the application again](#build-and-run-the-application). Your application looks like this: ![Application with an input element](images/js-added-input-element.png) #### Add an input event handling 1. Add a listener inside the `appendInput()` function to read the input value and react to changes: ```KOTLIN // Replace the current appendInput() function fun Element.appendInput(onChange: (String) -> Unit = {}) { val input = document.createElement("input").apply { addEventListener("change") { event -> onChange(event.target.unsafeCast().value) } } appendChild(input) } ``` 2. Follow the IDE's suggestions to import the `HTMLInputElement` dependency. ![Import dependencies](images/js-import-dependency.png) 3. Call the `onChange` callback in `main()`. It reads and handles the input value: ```KOTLIN fun main() { // Replace document.body?.appendInput() document.body?.appendInput(onChange = { println(it) }) } ``` #### Add an output element 1. Add a text element to display the output by defining an [extension function](extensions.html#extension-functions) that creates a paragraph: ```KOTLIN fun Element.appendTextContainer(): Element { return document.createElement("p").also(::appendChild) } ``` 2. Call the `appendTextContainer()` function in `main()`. It creates the output element: ```KOTLIN fun main() { // Creates a text container for our output // Replace val message = Message(topic = "Kotlin/JS", content = "Hello!") val output = document.body?.appendTextContainer() // Reads the input value document.body?.appendInput(onChange = { println(it) }) } ``` #### Process the input to count the letters Process the input by removing whitespace and displaying the output with the number of letters. Add the following code to the `appendInput()` function within the `main()` function: ```KOTLIN fun main() { // Creates a text container for our output val output = document.body?.appendTextContainer() // Reads the input value // Replace the current appendInput() function document.body?.appendInput(onChange = { name -> name.replace(" ", "").let { output?.textContent = "Your name contains ${it.length} letters" } }) } ``` From the code above: * The [replace() function](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.text/replace.html) removes the empty spaces in the name. * The [let{} scope function](scope-functions.html#let) runs the function within the object context. * The [string template](strings.html#string-templates) (`${it.length}`) inserts the word's length into the string by prefixing it with a dollar sign (`$`) and enclosing it in curly braces (`{}`). Whereas `it` is the default name of a [lambda parameter](coding-conventions.html#lambda-parameters). #### Run the application 1. [Run the application](#build-and-run-the-application). 2. Enter your name. 3. Press `Enter`. You can see the result: ![Application output](images/js-output-gutter-2.png) #### Process the input to count unique letters As an additional exercise, let's process the input to calculate and display the number of unique letters in the word: 1. In the `src/jsMain/kotlin/Main.kt` file, add the `.countDistinctCharacters()` [extension function](extensions.html#extension-functions) for `String`: ```KOTLIN fun String.countDistinctCharacters() = lowercase().toList().distinct().count() ``` From the code above: * The [.lowercase() function](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.text/lowercase.html) converts the name to lowercase. * The [toList() function](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.text/to-list.html) converts the input string to a list of characters. * The [distinct() function](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.collections/distinct.html) selects only the distinct characters from the word. * The [count() function](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.collections/count.html) counts the distinct characters. 2. Call the `.countDistinctCharacters()` function in `main()`. It counts the unique letters in your name: ```KOTLIN fun main() { // Creates a text container for our output val output = document.body?.appendTextContainer() // Reads the input value document.body?.appendInput(onChange = { name -> name.replace(" ", "").let { // Prints the number of unique letters // Replace output?.textContent = "Your name contains ${it.length} letters" output?.textContent = "Your name contains ${it.countDistinctCharacters()} unique letters" } }) } ``` 3. Follow the steps to [run the application and enter your name](#run-the-application). You can see the result: ![Application output](images/js-output-gutter-3.png) ## Create your application using Gradle In this section, you can learn how to manually create a Kotlin/JS application using [Gradle](https://gradle.org). Gradle is the default build system for Kotlin/JS and Kotlin Multiplatform projects. It is also commonly used in Java, Android, and other ecosystems. ### Create project files 1. Make sure you use a Gradle version that is compatible with the Kotlin Gradle plugin (KGP). See the [compatibility table](gradle-configure-project.html#apply-the-plugin) for more details. 2. Create an empty directory for your project using your file explorer, the command line, or any tool you prefer. 3. Inside the project directory, create a `build.gradle.kts` file with the following content: Kotlin: ```KOTLIN // build.gradle.kts plugins { kotlin("multiplatform") version "2.4.20" } repositories { mavenCentral() } kotlin { js { // Use browser() for running in a browser or nodejs() for running in Node.js browser() binaries.executable() } } ``` Groovy: ```GROOVY // build.gradle plugins { id 'org.jetbrains.kotlin.multiplatform' version '2.4.20' } repositories { mavenCentral() } kotlin { js { // Use browser() for running in a browser or nodejs() for running in Node.js browser() binaries.executable() } } ``` Note: You can use different [execution environments](js-project-setup.html#execution-environments), such as `browser()` or `nodejs()`. Each environment defines where your code runs and determines how Gradle generates task names in the project. 4. Within the project directory, create an empty `settings.gradle.kts` file. 5. Within the project directory, create a `src/jsMain/kotlin` directory. 6. Inside the `src/jsMain/kotlin` directory, add a `hello.kt` file with the following content: ```KOTLIN fun main() { println("Hello, Kotlin/JS!") } ``` By convention, all sources are located in the `src/[Main|Test]/kotlin` directory: * `Main` is the location for the source code. * `Test` is the location for tests. * `` corresponds to the target platform (`js` in this case). For the `browser` environment Note: Follow the next steps if you are working with the `browser` environment. If you are working with the `nodejs` environment, go to the [Build and run the project](#build-and-run-the-project) section. 1. Within the project directory, create a `src/jsMain/resources` directory. 2. Inside the `src/jsMain/resources` directory, create an `index.html` file with the following content: ```HTML Application title ``` 3. Replace the `<$NAME_OF_YOUR_PROJECT_DIRECTORY>` placeholder with the name of your project directory. ### Build and run the project To build the project, run the following command from the root project directory: ```BASH # For browser gradle jsBrowserDevelopmentRun # OR # For Node.js gradle jsNodeDevelopmentRun ``` If you are using the `browser` environment, you can see that the browser opens the `index.html` file and prints `"Hello, Kotlin/JS!"` to the browser console. You can open the console using the `Ctrl + Shift + J`/`Cmd + Option + J` commands. ![Application output](images/js-output-gutter-4.png) If you are using the `nodejs` environment, you can see that the terminal prints `"Hello, Kotlin/JS!"`. ![Application output](images/js-output-gutter-5.png) ### Open the project in an IDE You can open your project in any IDE that supports Gradle. If you use IntelliJ IDEA: 1. Select File | Open. 2. Find the project directory. 3. Click Open. IntelliJ IDEA automatically detects if it's a Kotlin/JS project. If you encounter a problem with the project, IntelliJ IDEA displays the error message in the Build pane. ## What's next? * [Set up your Kotlin/JS project](js-project-setup.html). * Learn how to [debug Kotlin/JS applications](js-debugging.html). * Learn how to [write and run tests with Kotlin/JS](js-running-tests.html). * Learn how to [write Gradle build scripts for real-life Kotlin/JS projects](https://kotlinlang.org/docs/multiplatform/multiplatform-dsl-reference.html). * Read more about the [Gradle build system](gradle.html). # Set up a Kotlin/JS project Kotlin/JS projects use Gradle as a build system. To let developers easily manage their Kotlin/JS projects, we offer the `kotlin.multiplatform` Gradle plugin that provides project configuration tools together with helper tasks for automating routines typical for JavaScript development. The plugin downloads npm dependencies in the background using the [npm](https://www.npmjs.com/) or [Yarn](https://yarnpkg.com/) package managers and builds a JavaScript bundle from a Kotlin project using [webpack](https://webpack.js.org/). Dependency management and configuration adjustments can be done to a large part directly from the Gradle build file, with the option to override automatically generated configurations for full control. You can apply the `org.jetbrains.kotlin.multiplatform` plugin to a Gradle project manually in the `build.gradle(.kts)` file: Kotlin: ```KOTLIN plugins { kotlin("multiplatform") version "2.4.20" } ``` Groovy: ```GROOVY plugins { id 'org.jetbrains.kotlin.multiplatform' version '2.4.20' } ``` The Kotlin Multiplatform Gradle plugin lets you manage aspects of your project in the `kotlin {}` block of the build script: ```GROOVY kotlin { // ... } ``` Inside the `kotlin {}` block, you can manage the following aspects: * [Target execution environment](#execution-environments): browser or Node.js * [Support for ES2015 features](#support-for-es2015-features): classes, modules, and generators * [Configure output granularity](#configure-output-granularity) * [Generation of TypeScript declaration files](#generation-of-typescript-declaration-files-d-ts) * [Project dependencies](#dependencies): Maven and npm * [Run configuration](#run-task) * [Test configuration](#test-task) * [Bundling](#webpack-bundling) and [CSS support](#css) for browser projects * [Target directory](#distribution-target-directory) and [module name](#module-name) * [Project's package.json file](#package-json-customization) ## Execution environments Kotlin/JS projects can target two different execution environments: * Browser for client-side scripting in browsers * [Node.js](https://nodejs.org/) for running JavaScript code outside a browser, for example, for server-side scripting. To define the target execution environment for a Kotlin/JS project, add the `js {}` block with `browser {}` or `nodejs {}` inside: ```KOTLIN kotlin { js { browser { } binaries.executable() } } ``` The instruction `binaries.executable()` explicitly instructs the Kotlin compiler to emit executable `.js` files. Omitting `binaries.executable()` will cause the compiler to only generate Kotlin-internal library files, which can be used from other projects but not run on their own. Tip: This is typically faster than creating executable files, and can be a possible optimization when dealing with non-leaf modules of your project. The Kotlin Multiplatform plugin automatically configures its tasks for working with the selected environment. This includes downloading and installing the required environment and dependencies for running and testing the application. This allows developers to build, run, and test simple projects without additional configuration. There is also an option to use an existing installation. Learn how to [use pre-installed Node.js](#use-pre-installed-node-js). ## Support for ES2015 features Kotlin provides support for ES2015 features, including: * Modules that simplify your codebase and improve maintainability. * Classes that allow incorporating OOP principles, resulting in cleaner and more intuitive code. * Generators for compiling [suspend functions](https://kotlinlang.org/docs/composing-suspending-functions.html) that improve the final bundle size and help with debugging. * [JavaScript code inlining](js-interop.html#inline-javascript). You can enable all the supported ES2015 features at once by adding the `es2015` compilation target to your `build.gradle(.kts)` file: ```KOTLIN tasks.withType().configureEach { compilerOptions { target = "es2015" } } ``` [Learn more about ES2015 (ECMAScript 2015, ES6) in the official documentation](https://262.ecma-international.org/6.0/). ## Configure output granularity You can choose how the compiler outputs `.js` files in your project: * One per module. By default, the JS compiler outputs separate `.js` files for each project module as a compilation result. * One per project. You can compile the whole project into a single `.js` file by adding the following line to the `gradle.properties` file: ``` kotlin.js.ir.output.granularity=whole-program // 'per-module' is the default ``` * One per file. You can set up a more granular output that generates one (or two, if the file contains exported declarations) JavaScript file per each Kotlin file. To enable the per-file compilation mode: 1. Set `es2015` as the [compilation target](#support-for-es2015-features) to support ES2015 features in your project. 2. Add the following line to the `gradle.properties` file: ``` kotlin.js.ir.output.granularity=per-file // 'per-module' is the default ``` ## Generation of TypeScript declaration files (`d.ts`) The Kotlin/JS compiler can generate TypeScript definitions from your Kotlin code. These definitions can be used by JavaScript tools and IDEs when working on hybrid applications to: * Provide autocompletion * Support static analyzers * Simplify the addition of Kotlin code in JavaScript and TypeScript projects Generating TypeScript definitions is especially valuable for the [business logic sharing use cases](js-overview.html#use-cases-for-kotlin-js). The compiler collects any top-level declarations marked with [@JsExport](js-to-kotlin-interop.html#jsexport-annotation) and automatically generates TypeScript definitions in a `.d.ts` file. To generate TypeScript definitions, explicitly configure it in your Gradle build file. Add the `generateTypeScriptDefinitions()` function to your `build.gradle.kts` file in the [js {} block](#execution-environments): ```KOTLIN kotlin { js { binaries.executable() browser { } generateTypeScriptDefinitions() } } ``` You can find the definitions in the `build/js/packages//kotlin` directory alongside the corresponding un-webpacked JavaScript code. ## Dependencies To declare a dependency, use the `dependencies {}` block in the `jsMain` source set in your `build.gradle(.kts)` file: Kotlin: ```KOTLIN kotlin { sourceSets { jsMain { dependencies { implementation("org.example.myproject:1.1.0") } } } } ``` Groovy: ```GROOVY kotlin { sourceSets { jsMain { dependencies { implementation 'org.example.myproject:1.1.0' } } } } ``` Only libraries that include artifacts for Kotlin/JS can be used as dependencies. To resolve dependencies, declare the repositories where Gradle should look for them in the `repositories {}` block of your `build.gradle(.kts)` file. For example: ```KOTLIN repositories { mavenCentral() } ``` If the library you are adding has dependencies on [packages from npm](#npm-dependencies), Gradle automatically resolves these transitive dependencies as well. ### Kotlin standard libraries The dependencies on the [standard library](https://kotlinlang.org/api/latest/jvm/stdlib/index.html) are added automatically. The version of the standard library is the same as the version of the Kotlin Multiplatform plugin. For multiplatform tests, the [kotlin.test](https://kotlinlang.org/api/latest/kotlin.test/) API is available. When you create a multiplatform project, you can add test dependencies to all the source sets by using a single dependency in `commonTest`: Kotlin: ```KOTLIN kotlin { sourceSets { commonTest.dependencies { implementation(kotlin("test")) // Brings all the platform dependencies automatically } } } ``` Groovy: ```GROOVY kotlin { sourceSets { commonTest { dependencies { implementation kotlin("test") // Brings all the platform dependencies automatically } } } } ``` ### npm dependencies In the JavaScript world, the most common way to manage dependencies is [npm](https://www.npmjs.com/). It offers the biggest public repository of JavaScript modules. The Kotlin Multiplatform Gradle plugin lets you declare npm dependencies in the Gradle build script, just how you declare any other dependencies. To declare an npm dependency, pass its name and version to the `npm()` function inside a dependency declaration. You can also specify one or multiple version ranges based on [npm's semver syntax](https://docs.npmjs.com/about-semantic-versioning). Kotlin: ```KOTLIN kotlin { sourceSets { jsMain { dependencies { implementation(npm("core-js", "^3.38.1")) } } } } ``` Groovy: ```GROOVY kotlin { sourceSets { jsMain { dependencies { implementation npm('core-js', '^3.38.1') } } } } ``` By default, the plugin uses a separate instance of the [Yarn](https://yarnpkg.com/lang/en/) package manager to download and install npm dependencies. It works out of the box without additional configuration, but you can [tune it to specific needs](#yarn). You can also work with npm dependencies directly using the [npm](https://www.npmjs.com/) package manager instead. To use npm as your package manager, in your `gradle.properties` file, set the following property: ``` kotlin.js.yarn=false ``` Besides regular dependencies, there are three more types of dependencies that can be used from the Gradle DSL. To learn more about when each type of dependency can best be used, have a look at the official documentation linked from npm: * [devDependencies](https://docs.npmjs.com/files/package.json#devdependencies), via `devNpm(...)`, * [optionalDependencies](https://docs.npmjs.com/files/package.json#optionaldependencies) via `optionalNpm(...)`, and * [peerDependencies](https://docs.npmjs.com/files/package.json#peerdependencies) via `peerNpm(...)`. Once an npm dependency is installed, you can use its API in your code as described in [Calling JS from Kotlin](js-interop.html). ## run task The Kotlin Multiplatform Gradle plugin provides a `jsBrowserDevelopmentRun` task that lets you run pure Kotlin/JS projects without additional configuration. For running Kotlin/JS projects in the browser, this task is an alias for the `browserDevelopmentRun` task (which is also available in Kotlin multiplatform projects). It uses the [webpack-dev-server](https://webpack.js.org/configuration/dev-server/) to serve your JavaScript artifacts. If you want to customize the configuration used by `webpack-dev-server`, for example, adjust the port the server runs on, use the [webpack configuration file](#webpack-bundling). For running Kotlin/JS projects targeting Node.js, use the `jsNodeDevelopmentRun` task that is an alias for the `nodeRun` task. To run a project, execute the standard lifecycle `jsBrowserDevelopmentRun` task, or the alias to which it corresponds: ```BASH ./gradlew jsBrowserDevelopmentRun ``` To automatically trigger a re-build of your application after making changes to the source files, use the Gradle [continuous build](https://docs.gradle.org/current/userguide/command_line_interface.html#sec:continuous_build) feature: ```BASH ./gradlew jsBrowserDevelopmentRun --continuous ``` or ```BASH ./gradlew jsBrowserDevelopmentRun -t ``` Once the build of your project has succeeded, the `webpack-dev-server` will automatically refresh the browser page. ## test task The Kotlin Multiplatform Gradle plugin automatically sets up a test infrastructure for projects. It downloads and installs the required test runners and other dependencies. For browser projects, you can choose between the [Karma](#karma) test runner and the new [DSL for browser testing](#dsl-for-browser-testing). For Node.js projects, the [Mocha](#node-js) test framework is available. The plugin also provides useful testing features, for example: * Source map generation * Test report generation * Test run results in the console ### Karma Warning: The Karma project has been [deprecated](https://github.com/karma-runner/karma#karma). No new features or bug fixes are expected. As an alternative for browser testing, try out the new [DSL for browser testing](#dsl-for-browser-testing). To configure the [Karma](https://karma-runner.github.io/) test runner, add the `useKarma {}` block inside the browser's `testTask` in your `build.gradle(.kts)` file. For example, to run tests against specific browsers, use: ```KOTLIN kotlin { js { browser { testTask { useKarma { useIe() useSafari() useFirefox() useChrome() useChromeCanary() useChromeHeadless() usePhantomJS() useOpera() } } } binaries.executable() // ... } } ``` Alternatively, you can add test targets for browsers in the `gradle.properties` file: ```TEXT kotlin.js.browser.karma.browsers=firefox,safari ``` This allows you to define a list of browsers for all modules and then add specific browsers in the build files of particular modules. The Kotlin Multiplatform Gradle plugin automatically generates a Karma configuration file at `build/js/packages/projectName-test/karma.conf.js` at build time. The file includes settings you set in the `useKarma {}` block in your build file. You can also place additional configuration files inside the `karma.config.d` directory at the root of your project. All `.js` configuration files in this directory are picked up and automatically merged into the generated `karma.conf.js` at build time. For more information on the Karma configuration, see [Karma's documentation](https://karma-runner.github.io/6.4/config/configuration-file.html). ### DSL for browser testing Kotlin offers an experimental DSL for running Kotlin/JS tests in a browser environment. It's designed to be technology-agnostic. The current implementation includes the following tools under the hood: * [Playwright](https://playwright.dev/) acts as a browser driver and a distribution manager that supports the Chromium, Firefox, and WebKit (Safari) browser engines. * [Mocha](https://mochajs.org/) acts as a test runner. * [webpack](https://webpack.js.org/) acts as a bundler (will be replaced with [Vite](https://vite.dev/) in [future releases](https://youtrack.jetbrains.com/issue/KT-48308/)). To try out the new DSL for browser testing, add the opt-in `test {}` block inside `browser {}` for your Kotlin/JS target: ```KOTLIN import org.jetbrains.kotlin.gradle.ExperimentalJsTestDsl import kotlin.time.Duration.Companion.seconds kotlin { js { browser { @OptIn(ExperimentalJsTestDsl::class) test { // Configures the default timeout for all runners with kotlin.Duration timeout = 30.seconds // Configures headless mode using Gradle providers headless = providers .environmentVariable("IS_IN_CI") .map { it.toBoolean() } .orElse(false) // Enables and configures a custom Chromium runner chromium("chromium-no-webgl2") { // Overrides the default timeout for this runner timeout = 10.seconds // Chromium-specific extra launch argument launchArgs.add("--disable-webgl2") } // Enables the Firefox runner firefox() // Enable WebKit (Safari) test runner webkit() // Enables and configures a custom WebKit runner webkit("headful") { headless = false } } } } } ``` For more information on the configuration of the new DSL for browser testing, see [Run tests in Kotlin/JS](js-running-tests.html#advanced-configuration). ### Node.js For Node.js projects, the Kotlin Multiplatform Gradle plugin automatically sets up the [Mocha](https://mochajs.org/) test framework. To specify environment variables used by your Node.js test runners (for example, to pass external information to your tests, or to fine-tune package resolution), use the `environment()` function with a key-value pair inside the `testTask {}` block in your build file: ```KOTLIN kotlin { js { nodejs { testTask { environment("key", "value") } } } } ``` ### Run tests By default, the Kotlin Multiplatform Gradle plugin uses [Headless Chrome](https://chromium.googlesource.com/chromium/src/+/lkgr/headless/README.md) to run browser tests. No browsers are bundled with the plugin; test runners handle missing browsers differently: * With [Karma](#karma), any other browser should already be installed on your machine so that the plugin can use it to run tests. If you are executing Kotlin/JS tests on a continuous integration server, ensure that the browsers you want to test against are installed there as well. * With the new [DSL for browser testing](#dsl-for-browser-testing), the plugin installs the necessary browsers on the first run by using the [playwright install](https://playwright.dev/docs/browsers#install-browsers) command. Playwright manages the location of these browsers and doesn't use locally installed browsers. To run tests, execute the standard lifecycle `check` task: ```BASH ./gradlew check ``` If you want to skip tests, disable them in the `testTask {}` block in your build file: ```KOTLIN kotlin { js { browser { testTask { enabled.set(false) } } binaries.executable() // ... } } ``` ## webpack bundling For browser targets, the Kotlin Multiplatform Gradle plugin uses the widely known [webpack](https://webpack.js.org/) module bundler. ### webpack task The most common webpack adjustments can be made directly via the `kotlin.js.browser.webpackTask {}` configuration block in the Gradle build file: * `mainOutputFileName` − the name of the webpacked output file. It will be generated in `/build/kotlin-webpack//` after an execution of a webpack task. The default value is the project name. * `output.libraryTarget` − the module system for the webpacked output. Learn more about [available module systems for Kotlin/JS projects](js-modules.html). The default value is `umd`. ```GROOVY webpackTask { mainOutputFileName = "mycustomfilename.js" output.libraryTarget = "commonjs2" } ``` You can also configure common webpack settings to use in bundling, running, and testing tasks in the `commonWebpackConfig {}` block. ### webpack configuration file The Kotlin Multiplatform Gradle plugin automatically generates a standard webpack configuration file at the build time. It is located in `build/js/packages/projectName/webpack.config.js`. If you want to make further adjustments to the webpack configuration, place your additional configuration files inside a directory called `webpack.config.d` in the root of your project. When building your project, all `.js` configuration files will automatically be merged into the `build/js/packages/projectName/webpack.config.js` file. For example, To add a new [webpack loader](https://webpack.js.org/loaders/), add the following to a `.js` file inside the `webpack.config.d` directory: Note: In this case, the configuration object is the `config` global object. You need to modify it in your script. ```GROOVY config.module.rules.push({ test: /\.extension$/, loader: 'loader-name' }); ``` All webpack configuration capabilities are well described in its [documentation](https://webpack.js.org/concepts/configuration/). ### Building executables For building executable JavaScript artifacts through webpack, the Kotlin Multiplatform Gradle plugin contains the `jsBrowserDevelopmentWebpack` and `jsBrowserProductionWebpack` Gradle tasks. * `jsBrowserDevelopmentWebpack` creates development artifacts, which are larger but take little time to create. As such, use the `jsBrowserDevelopmentWebpack` tasks during active development. * `jsBrowserProductionWebpack` applies dead code elimination to the generated artifacts and minifies the resulting JavaScript file, which takes more time but generates executables that are smaller. As such, use the `jsBrowserProductionWebpack` task when preparing your project for production use. Execute either of these tasks to obtain the respective artifacts for development or production. The generated files will be available in `build/kotlin-webpack` unless [specified otherwise](#distribution-target-directory). ```BASH ./gradlew jsBrowserProductionWebpack ``` Note that these tasks will only be available if your target is configured to generate executable files (via `binaries.executable()`). To generate the distribution in the `build/dist//` directory, run the `jsBrowserDistribution` task instead: ```BASH ./gradlew jsBrowserDistribution ``` This task generates a ready-to-use distribution that includes the project resources. ## CSS The Kotlin Multiplatform Gradle plugin also provides support for webpack's [CSS](https://webpack.js.org/loaders/css-loader/) and [style](https://webpack.js.org/loaders/style-loader/) loaders. While all options can be changed by directly modifying the [webpack configuration files](#webpack-bundling) that are used to build your project, the most commonly used settings are available directly from the `build.gradle(.kts)` file. To turn on CSS support in your project, set the `cssSupport.enabled` option in the Gradle build file in the `commonWebpackConfig {}` block. This configuration is also enabled by default when creating a new project using the wizard. Kotlin: ```KOTLIN browser { commonWebpackConfig { cssSupport { enabled.set(true) } } } ``` Groovy: ```GROOVY browser { commonWebpackConfig { cssSupport { it.enabled = true } } } ``` Alternatively, you can add CSS support independently for `webpackTask {}`, `runTask {}`, and `testTask {}`: Kotlin: ```KOTLIN browser { webpackTask { cssSupport { enabled.set(true) } } runTask { cssSupport { enabled.set(true) } } testTask { useKarma { // ... webpackConfig.cssSupport { enabled.set(true) } } } } ``` Groovy: ```GROOVY browser { webpackTask { cssSupport { it.enabled = true } } runTask { cssSupport { it.enabled = true } } testTask { useKarma { // ... webpackConfig.cssSupport { it.enabled = true } } } } ``` Activating CSS support in your project helps prevent common errors that occur when trying to use style sheets from an unconfigured project, such as `Module parse failed: Unexpected character '@' (14:0)`. You can use `cssSupport.mode` to specify how encountered CSS should be handled. The following values are available: * `"inline"` (default): styles are added to the global `