This document provides an introduction and overview of the Kotlin programming language. It begins with an agenda and quote about Kotlin being a good choice for Spring applications. The remainder of the document covers what Kotlin is, its main features like type inference, functional programming support, interoperability with Java, and language concepts like properties, classes, inheritance, interfaces, functions, collections and more. Code examples are provided to illustrate many of the language features. Resources for learning more about Kotlin are listed at the end.
3. If I were writing a Spring app today, I would
strongly consider Kotlin. It brings the same kind
of simplification to Java code as Spring did to
J2EE.
Rod Johnson.
3
4. What is Kotlin?
● Statically with type inference and strongly typed(1).
● Multi paradigm (object-oriented and functional)
● Fully Interoperate with Java
● Mainly targets the JVM (targets other runtimes as well)
● Semicolons are optional
● Type comes after the variable (val age: Int = 30)
(1) see appendix 1
4
5. What is Kotlin?
● val keyword used to declare immutable variables
● var keyword used to declare mutable variables
● Classes and class members are public by default
● Classes and methods are final by default
● open keyword used to mark class as extensible and method as
overridable
5
6. What is Kotlin?
● Interface methods are abstract and open by default
● Has package-level functions as well as class-level functions
● Supports extension functions to patch any library classes with new
functionality (a.k.a Monkey patching)
● Support limited set of operator overloading using operator keyword
6
operator fun String.not() = this.reversed()
println(!"hello") // prints olleh
7. What is Kotlin?
● Functions in kotlin supports:
○ default arguments
○ named arguments
○ variable-length argument lists
● data classes provides:
○ equals()/hashCode()
○ toString()
○ componentN() functions
○ copy()
○ Destructuring declarations: val (name, age) = jane
● Multiline strings with string interpolation
● Delegated Properties that allows lazy variable evaluation 7
8. What is Kotlin?
● object used to declare objects, which might used as:
○ singletons
○ companion object
○ Anonymous classes
● Access modifiers:
○ public
○ private
○ protected
○ internal
● Can use to write Domain-Specific Languages (DSL)
● Has Tail call optimization (tail recursion)
8
12. If as an expression
● Traditional usage:
12
var max = a
if (a < b) max = b
13. If as an expression
● Traditional usage with else:
13
var max: Int
if (a > b) {
max = a
} else {
max = b
}
14. If as an expression
● As an expression
14
val max = if (a > b) a else b
15. If as an expression
● As an expression
15
val max = if (a > b) {
print("choose a")
a
} else {
print("choose b")
b
}
16. When expression
16
when (x) {
1 -> print("x == 1")
2 -> print("x == 2")
else -> { // Note the block
print("x is neither 1 or 2")
}
}
17. When expression
17
when (x) {
in 1..10 -> print("x is in range")
in validNumbers -> print("x is valid")
!in 10..20 -> print("x is outside the range3")
else -> print("none of the above")
}
20. When expression
● when scoped variables:
20
fun Request.getBody() =
when (val response = executeRequest()) {
is Success -> response.body
is HttpError -> throw HttpException(response.status)
}
21. For Loops
● For loops used to for iterates through anything that provides an iterator,
which means:
○ has a member- or extension-function iterator(), whose return type:
■ has a member- or extension-function next(), and
■ has a member- or extension-function hasNext() that returns Boolean.
21
26. Loops and labels
● Kotlin has while loops as well
● Both for and while loops support break and continue (w/o labels)
26
loop@ for (i in 1..10) {
for (j in 1..10) {
if (...) break@loop
}
}
27. For Loops
27
var counter = 0
operator fun Int.iterator() = this
operator fun Int.next() = this
operator fun Int.hasNext() = counter++ < this
// usage:
for (n in 20) {
println(n)
}
37. Inheritance
37
open class Shape {
open fun draw() {/* ... */}
fun fill() {/* ... */ }
}
class Circle : Shape() {
override fun draw() {/* ... */}
}
38. Inheritance
38
typealias NodeList = ArrayList<Node>
sealed class Node
object EmptyNode : Node()
data class ValueNode(val value: Any?) : Node()
data class ObjectNode(val props: ArrayList<Pair<String, Any?>>) : Node()
data class ArrayNode(val elements: NodeList) : Node()
source: https://github.com/mhewedy/eureka-klient/blob/de7a1bf2ebec72a3bc1c9ca32868f5d93da32765/src/main/kotlin/helpers/json/Deserializer.kt#L30
39. Inheritance
39
fun eval(expr: Node): Unit = when (expr) {
is ValueNode -> println(expr.value) // smart case
is ObjectNode -> println(expr.props)
is ArrayNode -> expr.elements.forEach { eval(it) }
is EmptyNode -> print("empty")
// the `else` clause is not required
}
40. Properties and Fields
40
class State(val name: String)
class Address {
var name: String = "Holmes, Sherlock"
var state: State? = null
}
// used as
val address = Address()
println("${address.name} at ${address.state?.name}")
// note the safe navigation operator with nullable types
41. Properties and Fields
41
class MyClass {
lateinit var subject: TestSubject
@Setup fun setup() {
subject = TestSubject()
}
@Test fun test() {
subject.method() // dereference directly
}
}
43. Interfaces
43
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<A>.foo()
super<B>.foo()
}
override fun bar() {
super.bar()
}
}
50. Functions
50
infix fun Int.shl(x: Int): Int { /* ... */ }
// calling the function using the infix notation
1 shl 2
// is the same as
1.shl(2)
51. Functions
51
fun dfs(graph: Graph) {
fun dfs(current: Vertex, visited: MutableSet<Vertex>) {
if (!visited.add(current)) return
for (v in current.neighbors)
dfs(v, visited)
}
dfs(graph.vertices[0], HashSet())
}
53. Functions
● Classes and objects can extend functions
53
object Identity : (Int) -> Int {
override fun invoke(p1: Int) = p1
}
// called as
Identity(10)
54. Functions
● Lambda with receiver
54
operator fun Config.invoke(block: Config.() -> Unit) {
block.invoke(this)
}
58. Functions
58
fun <T> map(x: String, op: (String) -> T): T {
return op(x)
}
// used as
map("John Smith", fun(n: String): Int {
return n.length
})
59. Functions
59
fun <T> map(x: String, op: (String) -> T): T {
return op(x)
}
// used as
map("John Smith", { it.length })
60. Functions
60
fun <T> map(x: String, op: (String) -> T): T {
return op(x)
}
// used as
map("John Smith") { it.length }
61. Functions
61
fun <E> List<E>.test(op: (e: E) -> Boolean): List<E> {
val ret = arrayListOf<E>()
for (element in this) {
if (op(element)) ret += element
}
return ret
}
// used as
employees.test { it.age > 25 }
62. Functions
● fold is one of most important functional operators
62
fun <T, R> Collection<T>.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
}
63. fold (a.k.a reduce): how it works
63source: http://perugini.cps.udayton.edu/teaching/books/PL/www/lecture_notes/currying.html
70. Write your test cases in Kotlin
70
@Test
fun `Test getContentType for image pdf byte stream`() {
val pdfBytes = byteArrayOf(0x25, 0x50, 0x44, 0x46, 0x2d, 0x31, 0x2e, 0x34) // %PDF-1.4
val contentType = StreamUtil.
getContentType(ByteArrayInputStream(pngPdfBytes), "abc.png") //give invalid name
assertThat(contentType).isEqualTo("application/pdf")
}
71. Test Spring Apps
71
@Test
fun `test calling translateToCategories will calculate the agent category correctly`() {
// setup
val agentRepository = mock(AgentRepository::class.java)
val agentCategoryRepository = mock(AgentCategoryRepository::class.java)
whenever(agentRepository.findAllById(any()))
.thenReturn(listOf(createAgentOfExperience(10), createAgentOfExperience(5)))
whenever(agentCategoryRepository.findAll()).thenReturn(dbLookup())
val carrierService = CarrierService(agentRepository, agentCategoryRepository) // SUT
// when
val translatedList: List<Long> = carrierService.translateToCategories()
// then
assertThat(translatedList).asList().containsExactlyInAnyOrder(CAT_5, CAT_6)
}
75. 1. Strong vs Weak types
75
// Kotlin (strong typed)
fun main() {
val x: Float = 10.5f
val y: Int = x // compilation error
println("y = $y")
}
// C (weak typed)
#include <stdio.h>
int main() {
float x = 10.5;
int y = x;
printf("y = %dn", y); // prints 10
}
Iterate over Int by adding iterator() function and then implement next and hasNext for the iterator object (which is the int object in this case as now int is an iterator)
Var args and spread operator
Default args
Default args
infix
Functions inside functions
Operator overloading (invoke operator)
Operator overloading (invoke operator)
currying
Currying and partial function
When last parameter is a function
When last parameter is a function
When last parameter is a function
When last parameter is a function: real world example