Kotlin
What is Kotlin?
Section titled “What is Kotlin?”Since 2019, Google recommends that all new Android apps are written in Kotlin. Kotlin is a statically-typed, multi-paragidm, high-level programming language that runs on the JVM. Let’s break that down:
- Statically-typed: the compiler knows the type of every variable, and variable types can’t change at runtime.
- Multi-paradigm: Kotlin combines features from many different kinds of programming languages: it’s a bit imperative, object-oriented, and functional, all at the same time.
- High-level: Kotlin is very abstracted from the hardware that it runs on, which makes it a good language for things like app development, but not a good language for writing operating systems or device drivers.
- Runs on the JVM: Kotlin code compiles down to Java Virtual Machine (JVM) bytecode instead of machine code*, which means (1) it’s portable across different operating systems and CPU architectures, and (2) Kotlin code and Java code are interoperable. Kotlin functions can be called from Java functions and vice versa.
*Technically, on Android, both Java and Kotlin compile to DEX bytecode, which runs on the Android runtime (ART). However, that distinction isn’t important for us. Just know that Kotlin and Java programs are interoperable.
Kotlin is named after a Russian island, following Java’s naming after the largest island in Indonesia. Kotlin is also a Polish ketchup brand :)

Why Kotlin?
Section titled “Why Kotlin?”- Null safety: Kotlin allows you to declare variables that can’t be assigned to
null, which helps prevent the “billion-dollar mistake” from showing up in your programs. - Expressiveness: Kotlin allows you to do more with less code. It allows you to build your own domain-specific languages without writing your own compiler or parser. In fact, Gradle (the most common build system used in Android projects) configuration files are written in Kotlin. This kind of syntax is also used when writing code with Jetpack Compose.
- Concurrency: Kotlin has an official library for coroutines, which make it really easy to orchestrate asynchronous work across multiple threads and multiplex many tasks on few threads.
Let’s See Some Syntax!
Section titled “Let’s See Some Syntax!”Here’s a typical Hello World program in Kotlin:
fun main() { println("Hello, world!")}Program execution starts at the main function.
Unlike Java, methods and variables don’t need to be declared inside classes. Kotlin also doesn’t require semicolons!
Variables
Section titled “Variables”var i = 1i = i + 1println(i) // 2
val j = 1j = j + 1 // Compiler error: `val` can't be modifiedvar defines a variable, and val defines a constant. Anything declared with val can’t be updated after it’s initialized, and it needs to be initialized when it’s declared.
Type Inference & Explicit Types
Section titled “Type Inference & Explicit Types”Note that I didn’t declare the type in the example above. The compiler determined that Int was the correct type by looking at context. In most cases, the compiler can infer the type, but if it can’t, you can add it manually:
val myVariable: Int = 5Function parameters and returns always need to have explicit types:
fun add(a: Int, b: Int): Int { return a + b}Nullability
Section titled “Nullability”Nullability is enforced at the type level in Kotlin. This means that, whenever you declare a variable, it’s non-null by default. You can opt in by adding a ? after the name of the type.
var a: String = "Hello"a = null // Compiler error
var b: String? = "Hello 2"b = null // WorksControl Flow
Section titled “Control Flow”Kotlin has if and while statements, just like in Java:
val myBool = falseif (myBool) { println("Boo!")}
var i = 0while (i < 10) { i++ println(i)}Kotlin’s ternary operator is just if as an expression:
val number = 5val message = if (number > 5) "High" else "Low"
// You can add braces if you want:val message = if (number > 5) { "High"} else { println("Side effect") // <-- // You can run multiple statements in a block, // and the result of the last one is returned implicitly. "Low"}For loops are a bit different from Java. You always need to iterate over an Iterable.
val myList = listOf("apples", "bananas", "crocodiles")for (item in myList) { println("I like $item") // <-- String interpolation is // equivalent to ("I like " + item)}To iterate over numbers:
for (i in 1..10) { // i starts at 1 and goes up to and including 10 println(i)}
for (i in 1 until 10) { // i starts at 1 and ends at 9 println(i)}Kotlin also has break and continue with labels:
outer@ for (var i in 0..10) { for (var j in 5..15) { if (j > 10) continue@outer println(".") }}Collection Types
Section titled “Collection Types”Kotlin has built-in lists, maps, sets, and other convenient types. Most of them are immutable by default, so if you want to be able to modify them, you need to ask for the mutable version.
val myArray: Array<Int> = arrayOf(1, 2, 3)myArray[0] = 1
val myImmutableList: List<String> = listOf("item 1", "item 2", "item 3")val myMutableList: MutableList<String> = mutableListOf("item 1", "item 2", "item 3")
val myMap: Map<String, Int> = mapOf("Hello" to 1, "World" to 2)val myMutableMap: MutableMap<String, Int> = mutableMapOf(...)
val mySet: Set<String> = setOf("App", "Dev", "Club") // or mutableSetOf(...)
val myPair: Pair<Int, Int> = 1 to 2// Values are stored in myPair.first, myPair.second// You can also destructure:val (a, b) = myPairThe basic generic syntax in Kotlin is the same as in Java.
Unique Function Calling Modes
Section titled “Unique Function Calling Modes”Kotlin has some weird ways of calling functions.
- Infix functions: placing the function name in between the arguments.
- Extension functions: adding functions to a sealed type or a type you can’t modify.
// Extension function: 5.factorial()fun Int.factorial(): Int { if (this <= 1) return 1 return this * (this - 1).factorial()}
// Infix function: 5 choose 3infix fun Int.choose(k: Int): Int { val n = this return n.factorial() / ((n - k).factorial() * k.factorial())}
// These functions need to be in the same or higher scope// in the same file, or they need to be imported to be used.
println(1.factorial()) // 1println(2.factorial()) // 2println(3.factorial()) // 6println(4.factorial()) // 24println(5.factorial()) // 120println(5 choose 3) // 10
// Built-in infix function: `to`val myPair: Pair<Int, Int> = 5 to 10Object-Orientation
Section titled “Object-Orientation”abstract class MyBaseClass { abstract fun myMethod(): Int}
interface MyInterface { fun myOtherMethod(): Float}
// MyClass extends MyBaseClass and implements MyInterfaceclass MyClass : MyBaseClass(), MyInterface { override fun myMethod(): Int { return 5 }
override fun myOtherMethod() = 5.0f}
val myInstance = MyClass() // Instantiation. Kotlin doesn't have a `new` keyword.Kotlin also has data classes, which are classes where the equals, hashCode, and toString are generated by the compiler.
data class DiningLocation ( val name: String, val isOpen: Boolean)
val loc = DiningLocation("Fountain", true)println(loc) // DiningLocation(name=Fountain, isOpen=true)Properties
Section titled “Properties”Class variables can have custom getters and setters that are called every time the variable is accessed or updated.
class MyClass { // A custom getter and setter that don't do anything var myVar: Int = 0 get() = field // `field` is a reference to `myVar` set(value) { field = value }
var mySecondVar: Int = 0 // If only a setter is specified, the getter is the default, and vice versa private set // You can change the visibilities of the getter and setter separately}Why would you need this?
- Enforce invariants in a setter
- Make a setter private while keeping the getter public
- Create a property that delegates to another
Here’s an example of the third:
class MyClass { private val myValue: Int = 5
val myPublicValue: Int get() = myValue}We will be using this pattern to make lists public, but keep their mutable versions private.
class MyProtectedList { private val _list: MutableList<String> = mutableListOf("a", "b", "c") val list: List<String> = _list // Users of `list` can only see the read-only methods. // From within this class, we can use `_list` to modify it.}Iterable Operations & Function Arguments
Section titled “Iterable Operations & Function Arguments”Here are a few common list operations:
val myList = listOf("a", "b", "c", "a")val filtered = myList.filter { it != "b" }println(filtered) // [a, b, a]
val mapped = myList.map { it + "1" }println(mapped) // [a1, b1, c1, a1]
val sorted = myList.sortedBy { it[0].code }println(sorted) // [a, a, b, c]Notice that these functions (filter, map, and sortedBy) take in a function as their last argument.
In this case, Kotlin allows us to place the function body outside of the parentheses for the function call.
That first filter would be equivalent to:
val filtered = myList.filter({ it != "b" })Also, these functions each take one parameter. You can give it a name if you want:
val filtered = myList.filter { item -> item != "b" }If you don’t give that first parameter a name, it’ll be called it.
Challenges
Section titled “Challenges”Open up Android Studio. Navigate to File > New > Scratch File, and select Kotlin as the language.
- Write a program that prints out the first 25 numbers in the Fibonacci sequence. Each Fibonacci number is equal to the sum of the previous two numbers, and the first two numbers are 0 and 1.
- Extend your program to add all of the Fibonacci numbers to a new mutable list. Then, print out the sum of those numbers without using the
+operator. Hint: type the name of your list and then a., and then look at the method names that show up. - Extend your program to filter the list to only even numbers using
list.filterand then print out the list.