Skip to the content.

Kotlin Language Basics

Readonly/Immutable Variables

Equality Checks

Strings

Strings are written with "

Templates

In a template string use $variable and ${operation()}

Escape using backslash \$ and \"

Raw Strings

Strings where no escaping is done - are written with 3 quotes """

Multiline Strings

Similar to raw strings with using 3 quotes. If no indentation is needed start the additional lines with | combined with 🔗 String.trimMargin()

val withoutMargin1 = """ABC
                        |123
                        |456""".trimMargin()
println(withoutMargin1) // ABC\n123\n456

Nullable Types

Types

🔗 Any is the root of the class hierarchy. Defines equals(), hashCode(), toString(). The property javaClass returns the runtime Java class of an object.

println(someObj.javaClass)

Type Check

class Test {
  override operator fun equals(other: Any?) = other is Test
}

Explicit Cast

In general this is not necessary if a type check with is is performed

val msg1: String = fetchMessage() as String
val msg2: String? = fetchMessage() as? String

Functions

fun sum(a: Int, b: Int) = a + b // one line function

fun noReturn(arg: String) = println(arg) // returns `Unit`

Arguments to functions are val by design. The can not be reassigned within the function.

For one line functions the function return type does not need to be specified.

Default and named arguments

fun greet(name: String, msg: String = "Hello"): String = "$msg $name" // default arguments

// calling using named arguments
greet(name = "Alice", msg = "Hi")

Varargs and spread operator

fun greet(msg: String, vararg names: String): String = "$msg ${names.joinToString(",")}" // names will be an array

greet("Hi", "Alice", "Bob")

// calling with an array using the spread operator
greet("Hi", *arrayOf("Alice", "Bob"))

// if a list instead of an array, it must be converted before being spread
greet("Hi", *listOf("Alice", "Bob").toTypedArray())

External Iteration

The default imported package 🔗 kotlin.ranges gives us range classes. Both for the native types like IntRange and CharRange and for all Comparable types with ClosedRange<T: Comparable<T>>.

val oneToFive: IntRange = 1..5 // both 1 and 5 are included
val aToE: CharRange = 'a'..'e'
val stringRange: ClosedRange<String> = "helo".."helz"

// iteration
for (i in 1..5) println("$i")
for (i in 5 downTo 1) println("$i") // actually 5.downTo(1) written with infix notation (skipping parenthesis)
for (i in 0 until 5) println("$i") // excluding the end

Iteration over Arrays and Lists

val integerArray = arrayOf(1, 2, 3)
println(integerArray.javaClass) // class [Ljava.lang.Integer;
val nativeIntArray = intArrayOf(1, 2, 3)
println(nativeIntArray.javaClass) // class [I
val integerList = listOf(1, 2, 3)
println(integerList.javaClass) // class java.util.Arrays$ArrayList

for (i in integerArray) println("$i")
for (i in integerList) println("$i")

Index based Iteration

// index based
for (ix in integerArray.indices) println("elem at [$ix] is ${integerArray[ix]}")

// index and elem
for ((ix, elem) in integerArray.withIndex()) println("elem at [$ix] is $elem")

when instead of switch

The syntax for when is examplified in the below function

// simple function to show different match types in when
fun whatToDo(dayOfWeek: Any): String = when (dayOfWeek) {
  "Saturday", "Sunday" -> "Relax" // comma separated list
  in listOf("Monday", "Tuesday", "Wednesday", "Thursday") -> "Work hard" // list check
  in 2..4 -> "Work hard" // range check
  "Friday" -> "Party" // simple match
  is String -> "What?" // type check
  else -> "No clue" // the default if no match
}

local scope variable in when

fun systemInfo(): String = when (val coreCount = Runtime.getRuntime().availableProcessors()) {
  1 -> "1 core"
  in 2..4 -> "desktop with $coreCount cores"
  else -> "server with $coreCount cores"
}
:load WhenTests.kt
println(whatToDo(2))
println(whatToDo(true))
println(whatToDo("unknown"))
println(whatToDo("Friday"))

println(systemInfo())

(WhenTests.kt)

Enums

enum class Suit { CLUBS, DIAMONDS, HEARTS, SPADES }

val clubs = Suit.CLUBS
println(clubs) // CLUBS

// parse a string as an enum instance
val diamonds = Suit.valueOf("DIAMONDS")

val err = Suit.valueOf("NON EXISTING") // throws IllegalArgumentException

// iteration
for (suit in Suit.values()) println(suit)

// enum with state and methods
enum class Suit(val symbol: Char) {
  CLUBS('\u2663'),
  DIAMONDS('\u2666'),
  HEARTS('\u2665') {
    override fun display() = "${super.display()} $symbol"
  },
  SPADES('\u2660'); // note this semicolon is necessary

  open fun display() = "$symbol $name"
}

for (suit in Suit.values()) println(suit.display())
// ♣ CLUBS
// ♦ DIAMONDS
// ♥ HEARTS ♥
// ♠ SPADES