Kotlin
Kotlin is
- cross-platform
- statically typed (type of a variable is known at compile-time instead of at run-time)
- with type inference (has the ability to automatically deduce the type of an expression at compile time)
- general-purpose programming language
- interoperates fully with Java
- (JVM version) depends on the Java Class Library
- can also compile to JavaScript or native code
- as of 2019 Google's preferred language for Android app developers
Links
Kotlin in Wikipedia Kotlin in Wikipedia (German)
IDE
https://github.com/JetBrains/kotlin-eclipse
Functions
main function is the entry point of your code
println("Hello World!")
}
Functions with parameters and a return value
return x + y
}
One liner functions do not need a return type or {}
fun maxOf(a: Int, b: Int) = if (a > b) a else b
Functions can have inner functions
fun test() {
println("Hello World!")
}
test()
}
Function that have functions as parameters
val result = fn(number)
println(result)
}
Functions that return a function as a result
fun add(b: Int) = a + b
return ::add
}
var number = 0
fun makeCounter(): () -> Int {
fun counter() = ++number
return ::counter
}
// examples how to use it
val add2 = makeAdder(2)
println(add2(5)) // gibt 7 aus
val counter = makeCounter()
println(counter()) // 1
println(counter()) // 2
// example calls
callWithInt(42, { x -> x * 2})
callWithInt(42, fun(x: Int) = x * 2)
// if function is last parameter it can be outside the () and it is the default name
callWithInt(42) { it * 2 }
Control flow
If
if (a == 100)
println("X")
else if (a == 130)
println("Y")
else
println("Z")
When / Case / Switch
when (x) {
1 -> print("x == 1")
2 -> print("x == 2")
else -> {
print("Not 1 or 2")
}
}
Variables
var y = 0
val s = "World"
...
if (obj is String) {
// obj is automatically cast to String in this branch
return obj.length
}
Templates
val s1 = "a is $a"
a = 2
val s2 = "${s1.replace("is", "was")}, but now is $a"
Null
Normal variables can not be null
a = null // Compiler error
Add a ? to the type makes them nullable
b = null // ok
But then you need to check that they are not null when you use something from them. That can be annoying.
Imagine you have
and want to get myvalue. But foo, foo.bar and foo.bar.myvalue can be null. You need to write something like this:
if (foo == null || foo.bar == null)
myvalue = null
else
myvalue = foo.bar.myvalue
Short version in Kotlin:
Get the value of foo or if null the else value
Return value of function can be null
Collections
If you have a function that expects parameters and you have an Array, you can use *myArray to automatically use each of the entries of the Array as a parameter of a function.
listOf("1st parameter", "2nd parameter", *args)
}
println(list.map { it * 2 }) // [2, 4, 6, 8, 10]
println(list.filter { it > 2 }) // [3, 4, 5]
println(list.groupBy { it % 2 }) // {1=[1, 3, 5], 0=[2, 4]}
val cities = listOf("Berlin", "Hamburg", "München", "Köln", "Frankfurt")
// First character of the 3 cities with the shortest names
val result = cities
.sortedBy { it.length }
.take(3)
.map { it[0] }
.fold("") { acc, char -> acc + char }
println(result) // KBH
Loops
for (arg in args) {
println(arg)
}
}
val items = listOf("apple", "banana", "kiwifruit")
for (index in items.indices) {
println("item at $index is ${items[index]}")
}
val items = listOf("apple", "banana", "kiwifruit")
var index = 0
while (index < items.size) {
println("item at $index is ${items[index]}")
index++
}
for (x in 1..5) {
print(x)
}
for (x in 1..10 step 2) {
print(x)
}
Classes
You can only derive from a class if it is open
open fun foo() { println("Foo!") }
}
class MyBarClass: MyFooCass {
override fun foo() { println("Bar!") }
}
You can extend classes directly without creating an explicit derived class
fun String.lastChar(): Char = get(length - 1)
println("Kotlin".lastChar())
More complex example (this is the object)
val tmp = this[index1]
this[index1] = this[index2]
this[index2] = tmp
}
Classes can have a primary constructor in the class definition that does not have code but you can use its parameters
val customerKey = name.toUpperCase()
}
Or secondary constructors
var father
constructor(parent: Person) {
father=parent
}
}
Visibility
public | (default): Visible everywhere |
internal | Visible in a module |
protected | Visible in subclasses |
private | Visible in a class |
Data Class
Property only classes
Objects to list of variables
In Kotlin a class can have a function to export some of the object's values. You can use a so called "Destructuring Declaration" to assign multiples variables from one object (this has nothing to do with the concept of destructors for object deletion).
This will do the following and the class need to have the componentX methods:
val age = person.component2()
If you don't need one of the variables you can skip it like this
This also works for functions. Define a data class (it will have the componentX methods automatically), have your function return the data class, done
fun myFunction(): Result {
return Result("Jon", 42)
}
val (name, age) = myFunction()
You can also use it in Lamdas and it will extract its parameters. This would expect for example one object that can be extracted into 2 variables:
The normal syntax for 2 parameters in Lambdas would be
Operator overloading
For each operation there is predefined method name and you also need to add the key word operator before the method.
operator fun inc(): Foo {
...
}
}
List of operator names
a++ | a.inc() |
a-- | a.dec() |
a + b | a.plus(b) |
a - b | a.minus(b) |
a * b | a.times(b) |
a / b | a.div(b) |
a += b | a.plusAssign(b) |
a -= b | a.minusAssign(b) |
a *= b | a.timesAssign(b) |
a /= b | a.divAssign(b) |
a == b | a?.equals(b) ?: (b === null) |
a != b | !(a?.equals(b) ?: (b === null)) |
a > b | a.compareTo(b) > 0 |
a < b | a.compareTo(b) < 0 |
a >= b | a.compareTo(b) >= 0 |
a <= b | a.compareTo(b) <= 0 |
a..b | a.rangeTo(b) |
a in b | b.contains(a) |
a !in b | !b.contains(a) |
a[i] | a.get(i) |
a[i, j] | a.get(i, j) |
Objects as methods
If your class has an operator method
you can call your object like a method even with parameters.