- Differences from Java/C#.
- Tricky
- Kotlin can run without a class (only a main function).
- No ?: operator
- Support nullable: Int?
- Int? cast to Int
- parameters in fun are defined with val by default.
- Int 32 bit,
- Long 64 bit, var a = 30L
- Float 32 bit, var b = 4.5F
- Double 64 bit,
- Short 16 bit,
- Byte 8 bit,
- Boolean true/false
type conversions
- toByte(): Byte
- toShort(): Short
- toInt(): Int
- toLong(): Long
- toFloat(): Float
- toDouble(): Double
- toChar(): Char
is
!is
asvar for variable val for constant variable
val a: Int = 1 // immediate assignment
val b = 2 // `Int` type is inferredval p: String by lazy {
// compute the string
}var a = 1
val s1 = "a is $a"
val s2 = "${s1.replace("is", "was")}, but now is $a"val files = File("Test").listFiles()
println(files?.size ?: "empty")val emails = ... // might be empty
val mainEmail = emails.firstOrNull() ?: ""val value = ...
value?.let {
... // execute this block if not null
}fun maxOf(a: Int, b: Int) = if (a > b) a else bfun foo(param: Int) {
val result = if (param == 1) {
"one"
} else if (param == 2) {
"two"
} else {
"three"
}
}like foreach
val items = listOf("apple", "banana", "kiwifruit")
for (item in items) {
println(item)
}get index
val items = listOf("apple", "banana", "kiwifruit")
for (index in items.indices) {
println("item at $index is ${items[index]}")
}while is same as C#/Java
when
fun describe(obj: Any): String =
when (obj) {
1 -> "One"
"Hello" -> "Greeting"
is Long -> "Long"
!is String -> "Not a string"
else -> "Unknown"
}for (i in 1..100) { ... } // closed range: includes 100
for (i in 1 until 100) { ... } // half-open range: does not include 100
for (x in 2..10 step 2) { ... }
for (x in 10 downTo 1) { ... }
if (x in 1..10) { ... }fun sum(a: Int, b: Int): Int {
return a + b
}fun sum(a: Int, b: Int) = a + bfun dfs(graph: Graph) {
fun dfs(current: Vertex, visited: Set<Vertex>) {
if (!visited.add(current)) return
for (v in current.neighbors)
dfs(v, visited)
}
dfs(graph.vertices[0], HashSet())
}val eps = 1E-10 // "good enough", could be 10^-15
tailrec fun findFixPoint(x: Double = 1.0): Double
= if (Math.abs(x - Math.cos(x)) < eps) x else findFixPoint(Math.cos(x))class Person constructor(firstName: String) { ... }
class Person constructor(val firstName: String, val lastName: String, var age: Int) { ... }class InitOrderDemo(name: String) {
val firstProperty = "First property: $name".also(::println)
init {
println("First initializer block that prints ${name}")
}If has primary constructor, each secondary constructor needs to delegate to the primary constructor.
class Person(val name: String) {
constructor(name: String, parent: Person) : this(name) {
parent.children.add(this)
}
}open class Base(p: Int)
class Derived(p: Int) : Base(p)open class Base {
open fun v() { ... }
fun nv() { ... }
}
class Derived() : Base() {
override fun v() { ... }
}class Person constructor(val firstName: String, val lastName: String, var age: Int) {
var counter = 0 // Note: the initializer assigns the backing field directly
get() = 2
set(value) {
if (value >= 0) field = value
}
}fun MutableList<Int>.swap(index1: Int, index2: Int) {
val tmp = this[index1] // 'this' corresponds to the list
this[index1] = this[index2]
this[index2] = tmp
}
val l = mutableListOf(1, 2, 3)
l.swap(0, 2) // 'this' inside 'swap()' will hold the value of 'l'create DTO with getter/setter/equals/hashCode etc. automaticlly.
data class Customer(val name: String, val email: String)enum class Direction {
NORTH,
SOUTH,
WEST,
EAST
}
enum class ProtocolState {
WAITING {
override fun signal() = TALKING
},
TALKING {
override fun signal() = WAITING
};
abstract fun signal(): ProtocolState
}//list
val list = listOf("a", "b", "c") //Read-only list
println("Third element: ${list.get(2)}")
println("Fourth element: ${list[3]}")
println("Index of element \"two\" ${list.indexOf("two")}")
//map
val map = mapOf("a" to 1, "b" to 2, "c" to 3) //Read-only map
println(map["key"]); //Accessing a map
map["key"] = value; //set a map- Transformations
- Mapping
- Zipping
- Association
- Flattening
- joinToString
- joinTo
- Filtering
- by predicate
- Partitioning
- Testing predicates
- plus and minus operators
- Grouping
- Retrieving collection parts
- Slice
- Take and drop
- Chunked
- Windowed
- Retrieving single elements
- by position
- by condition
- Random element
- Checking existence
- Ordering
- Natural order
- Custom orders
- Reverse order
- Random order
- Aggregate operations
- min, max
- average
- sum()
- count()
- Fold and reduce
val numbers = mutableListOf(1, 2, 3, 4)
numbers.add(5)
numbers.remove(3) - Retrieving elements by index
- elementAt(), first(), last()
- getOrElse()
- getOrNull()
- Retrieving list parts: numbers.subList(3, 6)
- Finding element positions: numbers.indexOf(2)
- Binary search in sorted lists: numbers.binarySearch("two")
- Sorting
- union()
- intersect()
- subtract()
- Retrieving keys and values: [key]
- Filtering
- plus and minus operators
- add element: put(key, value)
- Removing entries: remove("one"), remove("one", 4)
for ((k, v) in map) {
println("$k -> $v")
}Creating a singleton
object Resource {
fun f1(){
}
val name = "Name"
}class MyClass {
companion object Factory {
fun create(): MyClass = MyClass()
}
}var a = 1
var b = 2
a = b.also { b = a }- Structural equality: "=="
- a?.equals(b) ?: (b === null)
- Referential equality (two references point to the same object): "==="
- Floating point numbers equality
val l: Int = if (b != null) b.length else -1can be
val l = b?.length ?: -1val l = b!!.lengththis will return a non-null value of b (e.g., a String in our example) or throw an NPE if b is null
Annotations are means of attaching metadata to code. To declare an annotation:
annotation class Fancyexecute a block of code within the context of an object.
- let, can be used to invoke one or more functions on results of call chains. "::"
Person("Alice", 20, "Amsterdam").let {
println(it)
it.moveTo("London")
it.incrementAge()
println(it)
}- run, useful when your lambda contains both the object initialization and the computation of the return value.
val service = MultiportService("https://example.kotlinlang.org", 80)
val result = service.run {
port = 8080
query(prepareRequest() + " to port $port")
}- with, alling functions on the context object without providing the lambda result. In the code, with can be read as “with this object, do the following.”
val numbers = mutableListOf("one", "two", "three")
with(numbers) {
println("'with' is called with argument $this")
println("It contains $size elements")
}- apply, common case for apply is the object configuration. Such calls can be read as “apply the following assignments to the object.”
val adam = Person("Adam").apply {
age = 32
city = "London"
}- also, is good for performing some actions that take the context object as an argument. Use also for additional actions that don't alter the object, such as logging or printing debug information. Usually, you can remove the calls of also from the call chain without breaking the program logic. When you see also in the code, you can read it as “and also do the following”.
val numbers = mutableListOf("one", "two", "three")
numbers
.also { println("The list elements before adding new one: $it") }
.add("four")- takeIf
- takeUnless
- apply and also return the context object.
- let, run, with return the lambda result.