Skip to content

HugoMatilla/KotlinCheatSheet

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

33 Commits
 
 
 
 
 
 

Repository files navigation

Hello Kotlin

Hello World

We declare a package-level function main which returns Unit and takes an Array of strings as a parameter. Note that semicolons are optional.

	fun main(args: Array<String>) {
    	println("Hello, world!")
	}

Reading a name from the command line

Line 13 demonstrates string templates and array access. See this pages for details: http://kotlinlang.org/docs/reference/basic-types.html#strings http://kotlinlang.org/docs/reference/basic-types.html#arrays

	fun main(args: Array<String>) {
	    if (args.size == 0) {
	        println("Please provide a name as a command-line argument")
	        return
	    }
	    println("Hello, ${args[0]}!")
	}

Reading many names from the command line

Line 2 demonstrates the for-loop, that would have been called "enhanced" if there were any other for-loop in Kotlin. See http://kotlinlang.org/docs/reference/basic-syntax.html#using-a-for-loop

	fun main(args: Array<String>) {
	    for (name in args)
	        println("Hello, $name!")
	    
	    for (i in args.indices)
	    	print(args[i])
	}

When

In this example, val denotes a declaration of a read-only local variable, that is assigned an pattern matching expression. See http://kotlinlang.org/docs/reference/control-flow.html#when-expression

	fun main(args: Array<String>) {
	    val language = if (args.size == 0) "EN" else args[0]
	    println(when (language) {
	        "EN" -> "Hello!"
	        "FR" -> "Salut!"
	        "IT" -> "Ciao!"
	        else -> "Sorry, I can't greet you in $language yet"
	    })
	}

OOP Simple Class

Here we have a class with a primary constructor and a member function. Note that there's no new keyword used to create an object. See http://kotlinlang.org/docs/reference/classes.html#classes

	class Greeter(val name: String) {
		fun greet() {
		    println("Hello, ${name}");
		}
	}

	fun main(args: Array<String>) {
	    Greeter(args[0]).greet()
	}

Basics

if

if is an expression, i.e. it returns a value. Therefore there is no ternary operator (condition ? then : else), because ordinary if works fine in this role. See http://kotlinlang.org/docs/reference/control-flow.html#if-expression

	fun main(args: Array<String>) {
    	println(max(Integer.parseInt(args[0]), Integer.parseInt(args[1])))
	}

	fun max(a: Int, b: Int) = if (a > b) a else b

Nullables

A reference must be explicitly marked as nullable to be able hold a null. See http://kotlinlang.org/docs/reference/null-safety.html#null-safety

	package multiplier

	// Return null if str does not hold a number
	fun parseInt(str: String): Int? {
	    try {
	        return Integer.parseInt(str)
	    } catch (e: NumberFormatException) {
	        println("One of the arguments isn't Int")
	    }
	    return null
	}

	fun main(args: Array<String>) {
	    if (args.size < 2) {
	        println("No number supplied");
	    } else {
	        val x = parseInt(args[0])
	        val y = parseInt(args[1])

	        // We cannot say 'xy' now because they may hold nulls
	        if (x != null && y != null) {
	            print(xy) // Now we can
	        } else {
	            println("One of the arguments is null")
	    }
	    }
	}

is

The is operator checks if an expression is an instance of a type and more. If we is-checked an immutable local variable or property, there's no need to cast it explicitly to the is-checked type. See this pages for details: http://kotlinlang.org/docs/reference/classes.html#classes-and-inheritance http://kotlinlang.org/docs/reference/typecasts.html#smart-casts

	fun main(args: Array<String>) {
		println(getStringLength("aaa"))
    	println(getStringLength(1))
	}

	fun getStringLength(obj: Any): Int? {
	    if (obj is String)
	        return obj.length // no cast to String is needed
	    return null
	}

while and do..while

See http://kotlinlang.org/docs/reference/control-flow.html#while-loops

	fun main(args: Array<String>) {
    var i = 0
    while (i < args.size)
        println(args[i++])
}

Ranges

Check if a number lies within a range. Check if a number is out of range. Check if a collection contains an object. See http://kotlinlang.org/docs/reference/ranges.html#ranges

	fun main(args: Array<String>) {
    val x = Integer.parseInt(args[0])
    //Check if a number lies within a range:
    val y = 10
    if (x in 1..y - 1)
        println("OK")

    //Iterate over a range:
    for (a in 1..5)
        print("${a} ")

    //Check if a number is out of range:
    println()
    val array = arrayListOf<String>()
    array.add("aaa")
    array.add("bbb")
    array.add("ccc")

    if (x !in 0..array.size - 1)
        println("Out: array has only ${array.size} elements. x = ${x}")

    //Check if a collection contains an object:
    if ("aaa" in array) // collection.contains(obj) is called
        println("Yes: array contains aaa")

    if ("ddd" in array) // collection.contains(obj) is called
        println("Yes: array contains ddd")
    else
        println("No: array doesn't contains ddd")
}

Control flow when

See http://kotlinlang.org/docs/reference/control-flow.html#when-expression

	fun main(args: Array<String>) {
    cases("Hello")
    cases(1)
    cases(System.currentTimeMillis())
    cases(MyClass())
    cases("hello")
}

	fun cases(obj: Any) {
	    when (obj) {
	        1 -> println("One")
	        "Hello" -> println("Greeting")
	        is Long -> println("Long")
	        !is String -> println("Not a string")
	        else -> println("Unknown")
	    }
	}

	class MyClass() {
	}

Multi-declarations and Data classes

Multi-declarations

This example introduces a concept that we call mutli-declarations. It creates multiple variable at once. Anything can be on the right-hand side of a mutli-declaration, as long as the required number of component functions can be called on it. See http://kotlinlang.org/docs/reference/multi-declarations.html#multi-declarations

	fun main(args: Array<String>) {
	    val pair = Pair(1, "one")

	    val (num, name) = pair

	    println("num = $num, name = $name")
	}

	class Pair<K, V>(val first: K, val second: V) {
	    operator fun component1(): K {
	        return first
	    }

	    operator fun component2(): V {
	        return second
	    }
	}

Data classes

Data class gets component functions, one for each property declared in the primary constructor, generated automatically, same for all the other goodies common for data toString(), equals(), hashCode() and copy(). See http://kotlinlang.org/docs/reference/data-classes.html#data-classes

	data class User(val name: String, val id: Int)

	fun getUser(): User {
	    return User("Alex", 1)
	}

	fun main(args: Array<String>) {
	    val user = getUser()
	    println("name = ${user.name}, id = ${user.id}")

	    // or

	    val (name, id) = getUser()
	    println("name = $name, id = $id")

	    // or

	    println("name = ${getUser().component1()}, id = ${getUser().component2()}")
	}

Data Maps

Kotlin Standart Library provide component functions for Map.Entry

	fun main(args: Array<String>) {
	    val map = hashMapOf<String, Int>()
	    map.put("one", 1)
	    map.put("two", 2)

	    for ((key, value) in map) {
	        println("key = $key, value = $value")
	    }
	}

Autogenerated Functions

Data class gets next functions, generated automatically: component functions, toString(), equals(), hashCode() and copy(). See http://kotlinlang.org/docs/reference/data-classes.html#data-classes

	data class User(val name: String, val id: Int)

	fun main(args: Array<String>) {
	    val user = User("Alex", 1)
	    println(user) // toString()

	    val secondUser = User("Alex", 1)
	    val thirdUser = User("Max", 2)

	    println("user == secondUser: ${user == secondUser}")
	    println("user == thirdUser: ${user == thirdUser}")

	    // copy() function
	    println(user.copy())
	    println(user.copy("Max"))
	    println(user.copy(id = 2))
	    println(user.copy("Max", 2))
	}

Delegated properties

Custom Delegate

There's some new syntax: you can say val 'property name': 'Type' by 'expression'. The expression after by is the delegate, because get() and set() methods corresponding to the property will be delegated to it. Property delegates don't have to implement any interface, but they have to provide methods named get() and set() to be called.

	import kotlin.reflect.KProperty

	class Example {
	    var p: String by Delegate()

	    override fun toString() = "Example Class"
	}

	class Delegate() {
	): String {
	        return "$thisRef, thank you for delegating '${prop.name}' to me!"
	    }

	, value: String) {
	        println("$value has been assigned to ${prop.name} in $thisRef")
	    }
	}

	fun main(args: Array<String>) {
	    val e = Example()
	    println(e.p)
	    e.p = "NEW"
	}

Lazy property

Delegates.lazy() is a function that returns a delegate that implements a lazy property: the first call to get() executes the lambda expression passed to lazy() as an argument and remembers the result, subsequent calls to get() simply return the remembered result. If you want thread safety, use blockingLazy() instead: it guarantees that the values will be computed only in one thread, and that all threads will see the same value.

	class LazySample {
	    val lazy: String by lazy {
	        println("computed!")
	        "my lazy"
	    }
	}

	fun main(args: Array<String>) {
	    val sample = LazySample()
	    println("lazy = ${sample.lazy}")
	    println("lazy = ${sample.lazy}")
	}

Observable Property

The observable() function takes two arguments: initial value and a handler for modifications. The handler gets called every time we assign to name, it has three parameters: a property being assigned to, the old value and the new one. If you want to be able to veto the assignment, use vetoable() instead of observable().

	import kotlin.properties.Delegates

	class User {
	    var name: String by Delegates.observable("no name") {
	        d, old, new ->
	        println("$old - $new")
	    }
	}

	fun main(args: Array<String>) {
	    val user = User()
	    user.name = "Carl"
	}

NotNull property

Users frequently ask what to do when you have a non-null var, but you don't have an appropriate value to assign to it in constructor (i.e. it must be assigned later)? You can't have an uninitialized non-abstract property in Kotlin. You could initialize it with null, bit then you'd have to check every time you access it. Now you have a delegate to handle this. If you read from this property before writing to it, it throws an exception, after the first assignment it works as expected.

	import kotlin.properties.Delegates

	class User {
	    var name: String by Delegates.notNull()

	    fun init(name: String) {
	        this.name = name
	    }
	}

	fun main(args: Array<String>) {
	    val user = User()
	    // user.name -> IllegalStateException
	    user.init("Carl")
	    println(user.name)
	}

Properties in map

Properties stored in a map. This comes up a lot in applications like parsing JSON or doing other "dynamic" stuff. Delegates take values from this map (by the string keys - names of properties). Of course, you can have var's as well (add import kotlin.properties.setValue), that will modify the map upon assignment (note that you'd need MutableMap instead of read-only Map).

	import kotlin.properties.getValue

	class User(val map: Map<String, Any?>) {
	    val name: String by map
	    val age: Int     by map
	}

	fun main(args: Array<String>) {
	    val user = User(mapOf(
	            "name" to "John Doe",
	            "age"  to 25
	    ))

	    println("name = ${user.name}, age = ${user.age}")
	}

Callable references

Reference to a function

"Callable References" or "Feature Literals", i.e. an ability to pass named functions or properties as values. Users often ask "I have a foo() function, how do I pass it as an argument?". The answer is: "you prefix it with a ::".

	fun main(args: Array<String>) {
	    val numbers = listOf(1, 2, 3)
	    println(numbers.filter(::isOdd))
	}

	fun isOdd(x: Int) = x % 2 != 0

Composition of functions

The composition function return a composition of two functions passed to it: compose(f, g) = f(g). Now, you can apply it to callable references.

	fun main(args: Array<String>) {
	    val oddLength = compose(::isOdd, ::length)
	    val strings = listOf("a", "ab", "abc")
	    println(strings.filter(oddLength))
	}

	fun isOdd(x: Int) = x % 2 != 0
	fun length(s: String) = s.length

	fun <A, B, C> compose(f: (B) -> C, g: (A) -> B): (A) -> C {
	    return { x -> f(g(x)) }
	}

Longer Examples

99 Botles of Beer

This example implements the famous "99 Bottles of Beer" program See http://99-bottles-of-beer.net/ The point is to print out a song with the following lyrics:

  • The "99 bottles of beer" song
  • 99 bottles of beer on the wall, 99 bottles of beer.
  • Take one down, pass it around, 98 bottles of beer on the wall.
  • 98 bottles of beer on the wall, 98 bottles of beer.
  • Take one down, pass it around, 97 bottles of beer on the wall.
  • ...
  • 2 bottles of beer on the wall, 2 bottles of beer.
  • Take one down, pass it around, 1 bottle of beer on the wall.
  • 1 bottle of beer on the wall, 1 bottle of beer.
  • Take one down, pass it around, no more bottles of beer on the wall.
  • No more bottles of beer on the wall, no more bottles of beer.
  • Go to the store and buy some more, 99 bottles of beer on the wall.

Additionally, you can pass the desired initial number of bottles to use (rather than 99) as a command-line argument

	package bottles

	fun main(args: Array<String>) {
	    if (args.isEmpty) {
	        printBottles(99)
	    } else {
	        try {
	            printBottles(Integer.parseInt(args[0]))
	        } catch (e: NumberFormatException) {
	            System.err.println("You have passed '${args[0]}' as a number of bottles, " +
	                    "but it is not a valid integer number")
	        }
	    }
	}

	fun printBottles(bottleCount: Int) {
	    if (bottleCount <= 0) {
	        println("No bottles - no song")
	        return
	    }

	    println("The \"${bottlesOfBeer(bottleCount)}\" song\n")

	    var bottles = bottleCount
	    while (bottles > 0) {
	        val bottlesOfBeer = bottlesOfBeer(bottles)
	        print("$bottlesOfBeer on the wall, $bottlesOfBeer.\nTake one down, pass it around, ")
	        bottles--
	        println("${bottlesOfBeer(bottles)} on the wall.\n")
	    }
	    println("No more bottles of beer on the wall, no more bottles of beer.\n" +
	            "Go to the store and buy some more, ${bottlesOfBeer(bottleCount)} on the wall.")
	}

	fun bottlesOfBeer(count: Int): String =
	        when (count) {
	            0 -> "no more bottles"
	            1 -> "1 bottle"
	            else -> "$count bottles"
	        } + " of beer"

	An excerpt from the Standard Library



	// This is an extension property, i.e. a property that is defined for the
	// type Array<T>, but does not sit inside the class Array
	val <T> Array<T>.isEmpty: Boolean get() = size == 0

HTML Builder

This is an example of a Type-Safe Groovy-style Builder Builders are good for declaratively describing data in your code. In this example we show how to describe an HTML page in Kotlin. See this page for details: http://kotlinlang.org/docs/reference/type-safe-builders.html

	package html

	fun main(args: Array<String>) {
	    val result =
	            html {
	                head {
	                    title { +"XML encoding with Kotlin" }
	                }
	                body {
	                    h1 { +"XML encoding with Kotlin" }
	                    p { +"this format can be used as an alternative markup to XML" }

	                    // an element with attributes and text content
	                    a(href = "http://jetbrains.com/kotlin") { +"Kotlin" }

	                    // mixed content
	                    p {
	                        +"This is some"
	                        b { +"mixed" }
	                        +"text. For more see the"
	                        a(href = "http://jetbrains.com/kotlin") { +"Kotlin" }
	                        +"project"
	                    }
	                    p { +"some text" }

	                    // content generated from command-line arguments
	                    p {
	                        +"Command line arguments were:"
	                        ul {
	                            for (arg in args)
	                                li { +arg }
	            			}
	                    }
	                }
	            }
	    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")
	    }
	}

	abstract class Tag(val name: String) : Element {
	    val children = arrayListOf<Element>()
	    val attributes = hashMapOf<String, String>()

	    protected fun <T : Element> 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</$name>\n")
	    }

	    private fun renderAttributes(): String? {
	        val builder = StringBuilder()
	        for (a in attributes.keys) {
	            builder.append(" $a=\"${attributes[a]}\"")
	    }
	        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") {
	    public var href: String
	        get() = attributes["href"]!!
	        set(value) {
	            attributes["href"] = value
	        }
	}

	fun html(init: HTML.() -> Unit): HTML {
	    val html = HTML()
	    html.init()
	    return html
	}

Game of life

Ommitted

Maze

Ommitted

Problems

Sum

Your task is to implement the sum() function so that it computes the sum of all elements in the given array a.

	package sum

	fun sum(a: IntArray): Int {
	    var result=0
	      for (number in a)
	    	result += number
	    return result
	}

indexOfMax

Your task is to implement the indexOfMax() function so that it returns the index of the largest element in the array, or null if the array is empty.

	package maxindex

	fun indexOfMax(a: IntArray): Int? {
	    var maxNumber = Integer.MIN_VALUE
	    var result = 0
	    if (a.size==0)
	    	return null
	    else{
	    	for (i in a.indices){
	            maxNumber = max(maxNumber,a[i])
				if(maxNumber == a[i])
		            result = i
	        }
	    }
	    return result
	}
	fun max(a: Int, b: Int) = if (a > b) a else b

Runs

Any array may be viewed as a number of "runs" of equal numbers. For example, the following array has two runs: 1, 1, 1, 2, 2 Three 1's in a row form the first run, and two 2's form the second. This array has two runs of length one: 3, 4 And this one has five runs: 1, 0, 1, 1, 1, 2, 0, 0, 0, 0, 0, 0, 0
Your task is to implement the runs() function so that it returns the number of runs in the given array.

	package runs

	fun runs(a: IntArray): Int {
		if (a.size==0)
		    return 0
	    
	    var runNumber =a[0]
	    var result = 1
	    
	    for (number in a)
	    	if(runNumber != number){
	    		result ++
	            runNumber = number
	        }
	    return result
	}

Pairless

Think of a perfect world where everybody has a soulmate. Now, the real world is imperfect: there is exactly one number in the array that does not have a pair. A pair is an element with the same value.

For example in this array: 1, 2, 1, 2 every number has a pair, but in this one: 1, 1, 1 one of the ones is lonely.

Your task is to implement the findPairless() function so that it finds the lonely number and returns it. A hint: there's a solution that looks at each element only once and uses no data structures like collections or trees.

	package pairless

	fun findPairless(a: IntArray): Int {
	    val distinctElements = a.distinct()
	    for (element in distinctElements){
	        if(!a.count{it == element}.isEven())
	           return element
	    }
	    return 0
	}
	fun Int.isEven() = this.mod(2) !=1

Canvas

Ommitted

Koans

joinOptions

	fun joinOptions(options: Collection<String>) = options.joinToString(", ","[","]")

Default arguments

	fun foo(name: String, number: Int = 42, toUpperCase: Boolean = false) =
        (if (toUpperCase) name.toUpperCase() else name) + number

	fun useFoo() = listOf(
	        foo("a"),
	        foo("b", number = 1),
	        foo("c", toUpperCase = true),
	        foo(name = "d", number = 2, toUpperCase = true)
	)

Lambdas

	fun containsEven(collection: Collection<Int>): Boolean = collection.any { it.mod(2) == 0 }

Strings

	val s = "abc"
	val str = "$s.length is ${s.length}" // evaluates to "abc.length is 3"
	...
	val month = "(JAN|FEB|MAR|APR|MAY|JUN|JUL|AUG|SEP|OCT|NOV|DEC)"
	fun getPattern() = """\d{2} ${month} \d{4}"""

Data classes

	data class Person (var name: String, var age: Int) 

	fun getPeople(): List<Person> {
	    return listOf(Person("Alice", 29), Person("Bob", 31))
	}

Nullable types

	fun sendMessageToClient(client: Client?, message: String?, mailer: Mailer){
		    val mail = client?.personalInfo?.email ?: return
		    if (message!=null)
			    mailer.sendMessage(mail, message)
		}

	class Client (val personalInfo: PersonalInfo?)
	class PersonalInfo (val email: String?)
	interface Mailer {fun sendMessage(email: String, message: String)}

Smart Cast

	fun eval(expr: Expr): Int =
        when (expr) {
            is Num -> expr.value
            is Sum -> eval(expr.left) + eval(expr.right) 
            else -> throw IllegalArgumentException("Unknown expression")
        }

	interface Expr
	class Num(val value: Int) : Expr
	class Sum(val left: Expr, val right: Expr) : Expr

Extension Functions

	fun Int.r(): RationalNumber = RationalNumber(this,1)
	fun Pair<Int, Int>.r(): RationalNumber = RationalNumber(this.component1(),this.component2())

	data class RationalNumber(val numerator: Int, val denominator: Int)

Object expressions

	import java.util.*

	fun getList(): List<Int> {
	    val arrayList = arrayListOf(1, 5, 2)
	    Collections.sort(arrayList, object : Comparator<Int> {
	    	override fun compare(x: Int, y: Int) = y - x
	    })
	    return arrayList
	}

SAM conversions

	import java.util.*

	fun getList(): List<Int> {
	    val arrayList = arrayListOf(1, 5, 2)
	    Collections.sort(arrayList, { x, y -> y-x })
	    return arrayList
	}

Extension functions on collections

	fun getList(): List<Int> {
    	return arrayListOf(1, 5, 2).sortedDescending()
	}

Conventions

Comparison

	data class MyDate(val year: Int, val month: Int, val dayOfMonth: Int) : Comparable<MyDate> {
	    override fun compareTo(other: MyDate) = when {
	        year != other.year -> year - other.year
	        month != other.month -> month - other.month
	        else -> dayOfMonth - other.dayOfMonth
	    }
}

In range

	class DateRange(val start: MyDate, val endInclusive: MyDate){
		operator fun contains(item: MyDate): Boolean = start <= item && item <= endInclusive
	}        
	    

	fun checkInRange(date: MyDate, first: MyDate, last: MyDate): Boolean {
	    return date in DateRange(first, last)
	}

	operator fun MyDate.rangeTo(other: MyDate) = DateRange(this, other)

	class DateRange(override val start: MyDate, override val endInclusive: MyDate): ClosedRange<MyDate> 

	data class MyDate(val year: Int, val month: Int, val dayOfMonth: Int) : Comparable<MyDate>{
	    override fun compareTo(other: MyDate): Int{
	        if(year != other.year) return year - other.year
	        if(month != other.month) return month - other.month
	        return dayOfMonth - other.dayOfMonth
	    }
	}

	fun checkInRange(date: MyDate, first: MyDate, last: MyDate): Boolean {
	    return date in first..last
	}

For loop

	class DateRange(val start: MyDate, val end: MyDate): Iterable<MyDate>{
	    override fun iterator(): Iterator<MyDate> = DateIterator(this)
	}

	class DateIterator(val dateRange:DateRange) : Iterator<MyDate> {
	    var current: MyDate = dateRange.start
	    override fun next(): MyDate {
	        val result = current
	        current = current.nextDay()
	        return result
	    }
	    override fun hasNext(): Boolean = current <= dateRange.end
	}

	fun iterateOverDateRange(firstDate: MyDate, secondDate: MyDate, handler: (MyDate) -> Unit) {
	    for (date in firstDate..secondDate) {
	        handler(date)
	    }
	}

Operators overloading

	operator fun MyDate.plus(timeInterval: TimeInterval) = addTimeIntervals(timeInterval, 1)

	class RepeatedTimeInterval(val timeInterval: TimeInterval, val number: Int)
	operator fun TimeInterval.times(number: Int) = RepeatedTimeInterval(this, number)

	operator fun MyDate.plus(timeIntervals: RepeatedTimeInterval) = addTimeIntervals(timeIntervals.timeInterval, timeIntervals.number)

Destructuring declarations

	data class MyDate(val year: Int, val month: Int, val dayOfMonth: Int)

	fun isLeapDay(date: MyDate): Boolean {

	    val (year, month, dayOfMonth) = date

	    // 29 February of a leap year
	    return year % 4 == 0 && month == 2 && dayOfMonth == 29
	}

Invoke

	class Invokable {
	public var numberOfInvocations: Int = 0
	    private set
	operator public fun invoke(): Invokable {
	    numberOfInvocations++
	    return this  }
	}

	fun invokeTwice(invokable: Invokable) = invokable()()

Collections

Introduction

Default collections in Kotlin are Java collections, but there are lots of useful extension functions for them. For example, operations that transform a collection to another one, starting with 'to': toSet or toList.

	data class Shop(val name: String, val customers: List<Customer>)

	data class Customer(val name: String, val city: City, val orders: List<Order>) {
	    override fun toString() = "$name from ${city.name}"
	}

	data class Order(val products: List<Product>, val isDelivered: Boolean)

	data class Product(val name: String, val price: Double) {
	    override fun toString() = "'$name' for $price"
	}

	data class City(val name: String) {
	    override fun toString() = name
	}
	fun Shop.getSetOfCustomers(): Set<Customer> = this.customers.toSet()

filter map

	val numbers = listOf(1, -1, 2)
	numbers.filter { it > 0 } == listOf(1, 2)
	numbers.map { it * it } == listOf(1, 1, 4)

	// Return the set of cities the customers are from
	fun Shop.getCitiesCustomersAreFrom(): Set<City> = customers.map {it.city}.toSet()

	// Return a list of the customers who live in the given city
	fun Shop.getCustomersFrom(city: City): List<Customer> = this.customers.filter {it.city == city}

all, any count and find

	val numbers = listOf(-1, 0, 2)
	val isZero: (Int) -> Boolean = { it == 0 }
	numbers.any(isZero) == true
	numbers.all(isZero) == false
	numbers.count(isZero) == 1
	numbers.find { it > 0 } == 2

	// Return true if all customers are from the given city
	fun Shop.checkAllCustomersAreFrom(city: City): Boolean = customers.all{it.city== city}

	// Return true if there is at least one customer from the given city
	fun Shop.hasCustomerFrom(city: City): Boolean = customers.any{it.city== city}

	// Return the number of customers from the given city
	fun Shop.countCustomersFrom(city: City): Int = customers.count{it.city== city}

	// Return a customer who lives in the given city, or null if there is none
	fun Shop.findAnyCustomerFrom(city: City): Customer? = customers.find{it.city== city}

flatMap

	val result = listOf("abc", "12").flatMap { it.toCharList() }
	result == listOf('a', 'b', 'c', '1', '2')

	// Return all products this customer has ordered
	fun Customer.getOrderedProducts(): Set<Product> = orders.flatMap{it.products}.toSet()

	// Return all products that were ordered by at least one customer
	fun Shop.getAllOrderedProducts(): Set<Product> = customers.flatMap{it.getOrderedProducts()}.toSet()

max, min, maxBy and minBy

	
	listOf(1, 42, 4).max() == 42
	listOf("a", "ab").minBy { it.length } == "a"

	// Return a customer whose order count is the highest among all customers
	fun Shop.getCustomerWithMaximumNumberOfOrders(): Customer? = customers.maxBy {it.orders.size}

	// Return the most expensive product which has been ordered
	fun Customer.getMostExpensiveOrderedProduct(): Product? = orders.flatMap{it.products}.maxBy{it.price}
	

sort

	listOf("bbb", "a", "cc").sorted() == listOf("a", "bbb", "cc")
	listOf("bbb", "a", "cc").sortedBy { it.length } == listOf("a", "cc", "bbb")

	// Return a list of customers, sorted by the ascending number of orders they made
	fun Shop.getCustomersSortedByNumberOfOrders(): List<Customer> = customers.sortedBy{it.orders.size}
	

sum

	listOf(1, 5, 3).sum() == 9
	listOf("a", "b", "cc").sumBy { it.length() } == 4

	// Return the sum of prices of all products that a customer has ordered.
	// Note: the customer may order the same product for several times.
	fun Customer.getTotalOrderPrice(): Double = orders.flatMap{it.products}.sumByDouble{it.price}

groupBy

	val result = listOf("a", "b", "ba", "ccc", "ad").groupBy { it.length() }
	result == mapOf(1 to listOf("a", "b"), 2 to listOf("ba", "ad"), 3 to listOf("ccc"))

	// Return a map of the customers living in each city
	fun Shop.groupCustomersByCity(): Map<City, List<Customer>> = customers.groupBy{it.city}
	

partition

	val numbers = listOf(1, 3, -4, 2, -11)
	val (positive, negative) = numbers.partition { it > 0 }
	positive == listOf(1, 3, 2)
	negative == listOf(-4, -11)

	// Return customers who have more undelivered orders than delivered
	fun Shop.getCustomersWithMoreUndeliveredOrdersThanDelivered(): Set<Customer> = customers.filter{
	    val (delivered, undelivered) = it.orders.partition { it.isDelivered }
	    undelivered.size > delivered.size
	}.toSet()
	

fold

	listOf(1, 2, 3, 4).fold(1, {
	    partProduct, element ->
	    element * partProduct
	}) == 24

	fun Shop.getSetOfProductsOrderedByEveryCustomer(): Set<Product> {
	    val allProducts = customers.flatMap { it.orders.flatMap { it.products }}.toSet()
	    return customers.fold(allProducts, {
	        orderedByAll, customer ->
	        orderedByAll.intersect(customer.orders.flatMap { it.products }.toSet())
	    })
	}
	

Compound tasks

	fun Customer.getMostExpensiveDeliveredProduct(): Product? {
	    return orders.filter { it.isDelivered }.flatMap { it.products }.maxBy { it.price }
	}

	fun Shop.getNumberOfTimesProductWasOrdered(product: Product): Int {
	    return customers.flatMap { it.getOrderedProductsList() }.count { it == product }
	}

	fun Customer.getOrderedProductsList(): List<Product> {
	    return orders.flatMap { it.products }
	}

Get used to new style

	fun doSomethingStrangeWithCollection(collection: Collection<String>): Collection<String>? {

	    val groupsByLength = collection. groupBy { s -> s.length }

	    val maximumSizeOfGroup = groupsByLength.values.map { group -> group.size }.max()

	    return groupsByLength.values.firstOrNull { group -> group.size == maximumSizeOfGroup }
	}

Properties

Properties

	class PropertyExample() {
	    var counter = 0
	    var propertyWithCounter: Int? = null
	    	set(v:Int?) {
	            field = v
	   			counter++
	        }
	}

Lazy property

	
	class LazyProperty(val initializer: () -> Int) {
    var value: Int? = null
    val lazy: Int
        get() {
            if (value == null) {
                value = initializer()
            }
            return value!!
        }
}

Delegates example

	class LazyProperty(val initializer: () -> Int) {
	    val lazyValue: Int by lazy(initializer)
	}

Delegates how it works

	
	class EffectiveDate<R> : ReadWriteProperty<R, MyDate> {

	    var timeInMillis: Long? = null

	    override fun getValue(thisRef: R, property: KProperty<*>): MyDate = timeInMillis!!.toDate()

	    override fun setValue(thisRef: R, property: KProperty<*>, value: MyDate) {
	        timeInMillis = value.toMillis()
	    }
	}

Extension function literals

A higher-order function is a function that takes functions as parameters, or returns a function.

	fun task(): List<Boolean> {
	    val isEven: Int.() -> Boolean = { this % 2 == 0 }
	    val isOdd: Int.() -> Boolean = { this % 2 != 0 }

	    return listOf(42.isOdd(), 239.isOdd(), 294823098.isEven())
	}

	fun buildString(build: StringBuilder.() -> Unit): String {
	    val stringBuilder = StringBuilder()
	    stringBuilder.build()
	    return stringBuilder.toString()
	}

	val s = buildString {
	    this.append("Numbers: ")
	    for (i in 1..3) {
	        // 'this' can be omitted
	        append(i)
	    }
	}

	s == "Numbers: 123"

	---

	import java.util.HashMap

	fun <K, V> buildMap(build: HashMap<K, V>.() -> Unit): Map<K, V> {
	    val map = HashMap<K, V>()
	    map.build()
	    return map
	}


	fun usage(): Map<Int, String> {
	    return buildMap {
	        put(0, "0")
	        for (i in 1..10) {
	            put(i, "$i")
	        }
	    }
	}

The function apply

	fun <T> T.myApply(f: T.() -> Unit): T { f(); return this } 

	fun buildString(): String {
	    return StringBuilder().myApply {
	        append("Numbers: ")
	        for (i in 1..10) {
	            append(i)
	        }
	    }.toString()
	}



	fun buildMap(): Map<Int, String> {
	    return hashMapOf<Int, String>().myApply {
	        put(0, "0")
	        for (i in 1..10) {
	            put(i, "$i")
	        }
	    }
	}

Html builder

	
	fun renderProductTable(): String {
	    return html {
	        table {
	            tr (color = getTitleColor()) {
	                td {
	                    text("Product")
	                }
	                td {
	                    text("Price")
	                }
	                td {
	                    text("Popularity")
	                }
	            }
	            val products = getProducts()
	            for ((index, product) in products.withIndex()) {
	                tr {
	                    td (color = getCellColor(index, 0)) {
	                        text(product.description)
	                    }
	                    td (color = getCellColor(index, 1)) {
	                        text(product.price)
	                    }
	                    td (color = getCellColor(index, 2)) {
	                        text(product.popularity)
	                    }
	                }
	            }
	        }
	    }.toString()
	}

	Look at the questions below and give your answers

	1. In the Kotlin code

	tr {
	    td {
	        text("Product")
	    }
	    td {
	        text("Popularity")
	    }
	}
	'td' is:

	a. special built-in syntactic construct

	b. function declaration

	c. function invocation

	---------------------

	2. In the Kotlin code

	tr (color = "yellow") {
	    td {
	        text("Product")
	    }
	    td {
	        text("Popularity")
	    }
	}
	'color' is:

	a. new variable declaration

	b. argument name

	c. argument value

	---------------------
	
	3. The block

	{
	    text("Product")
	}
	from the previous question is:

	a. block inside built-in syntax construction td

	b. function literal (or "lambda")

	c. something mysterious

	---------------------
	
	4. For the code

	tr (color = "yellow") {
	    this.td {
	        text("Product")
	    }
	    td {
	        text("Popularity")
	    }
	}
	which of the following is true:

	a. this code doesn't compile

	b. this refers to an instance of an outer class

	c. this refers to a receiver parameter TR of the function literal:

	tr (color = "yellow") { TR.(): Unit ->
	      this.td {
	          text("Product")
	      }
	}

	1 to c, 2 to b, 3 to b, 4 to c

Generic functions

	
	import java.util.*

	fun <T, C: MutableCollection<T>> Collection<T>.partitionTo(first: C, second: C, predicate: (T) -> Boolean): Pair<C, C> {
	    for (element in this) {
	        if (predicate(element)) {
	            first.add(element)
	        } else {
	            second.add(element)
	        }
	    }
	    return Pair(first, second)
	}

	fun partitionWordsAndLines() {
	    val (words, lines) = listOf("a", "a b", "c", "d e").
	            partitionTo(ArrayList<String>(), ArrayList()) { s -> !s.contains(" ") }
	    words == listOf("a", "c")
	    lines == listOf("a b", "d e")
	}

	fun partitionLettersAndOtherSymbols() {
	    val (letters, other) = setOf('a', '%', 'r', '}').
	            partitionTo(HashSet<Char>(), HashSet()) { c -> c in 'a'..'z' || c in 'A'..'Z'}
	    letters == setOf('a', 'r')
	    other == setOf('%', '}')
	}

About

A reference (copy/paste) of the the examples listed in http://try.kotlinlang.org/ in one single document. Good for fast search and quick reference

Topics

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published