A study note based on Kotlin Docs.

1 Getting Started

1.1 Basic Syntax

package and import should be at the top of the source file. You can import classes, top-level functions and properties, enum constants.

fun main() {...} is the program entry point.

Sample code

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
// function with two parameters and return types
fun sum(a: Int, b: Int): Int {
  return a + b
}

// with inferred return type
fun sum(a: Int, b: Int) = a + b

// no meaningful return
fun printSum(a: Int, b: Int): Unit { print("${a + b}") }
fun printSum(a: Int, b: Int) { print("${a + b}") }

// read-only variables
val a: Int = 1
val b = 2 // inferred type
val c: int
c = 3

// reassignable variables
var x = 5
x += 1

// string templates
val message = "a is $a"
val message2 = "${message1.replace("is", "was")}"

// conditional expression
fun maxOf(a: Int, b: Int) = if (a > b) a else b

// Nullalbe
var x: String? = null

// type check and implicit tyep casting for immutable local variable property
if (message is String) {
  return message.length
}

// when expression

val result = when(obj) {
  1 -> "one"
  "hello" -> "greeting"
  is Long -> "long"
  in 0..9 -> "digital"
  !is String -> "Not a string"
  else -> "unknow"
}

// ranges
if (a in 1..10 step 2) {...}

// collections
val items = listof("banana", "apple")
for (item in items) {...}

// lambda
items
  .filter { it.startsWith("a")}
  .sortedby { it }
  .map { it.toUpperCase() }
  .forEach { println(it) }

1.2 Idioms

A data class Customer(val name: String, val: email: string) provides

  • getter and setter (for var) for each property
  • equals()
  • hashCode()
  • toString()
  • copy()
  • component1(), component2(), ... for all properties

Kotlin supports default function parameters. Ranges can use 1..10 step 2, 1 until 10, 10 downTo 1.

Read-only list: listOf(1, 2, 3) Read-only map: mapOf("a" to 1, "b" to 2, "c" to 3) Lazy property: val p: String by lazy { // compute the string } Extension functions: fun String.extensionFun(){...} Singleton: object Resource {...} Not null shorthand: files?.size Not null and else shorthand: files?.size ?: "empty" If null execute: files ?: throw IllegalStateException("empty") Execute if not null: files?.let {...}

Use with to call multiple methods on an object instance.

Use apply to configure object properties.

use use method to try with resoruces.

Nullable boolean:

1
2
3
4
5
6
val b: Boolean? = ...
if (b == true) {
    ...
} else {
    // `b` is false or null
}

Swap variables: a = b.also { b = a }

use TODO("task1") for incompleted code.

1.3 Coding Conventions

Use Kotlin style guide and enable Editor | Kotlin | Style issues | File is not formatted according to project settings.

Directory structure follows the package structure except that the common root package is omitted. If a project has Java files, follow the Java structure.

Filename should be same as the class name or can use different name if there are multiple classes. Use PascalCase for file names.

Use PacalCase for class and interface names. The class layout is in the following order: properties and initializer blocks, secondary contructors, method declarations, and companion object. Use relation, not public/private as to organize code. Overloads should be next to each other.

Use camelCase for package names – don’t use underscores.

Use camelCase for names of function, properties and local variables. Factory function use PascalCase.

Only in test, use method names with spaces enclosed in backticks, or name with underscores.

Constants (const or toplevel val) use all uppoercase words separated by underscores.

Use the named argument syntax when a method takes multiple parameters of the same primitive type, or for parameters of Boolean type.

Prefer using higher-order functions (filter, map etc.) to loops. Exception: forEach (prefer using a regular for loop instead, unless the receiver of forEach is nullable or forEach is used as part of a longer call chain).

Every time you have a function that works primarily on an object, consider making it an extension function accepting that object as a receiver.

2 Basic Types

Everything is an object. Kotlin provides numbers (integer and float-point). Use underscores to make large number more readable. Nullable numbers are boxed. Use toX method to convert types.

Division is integer division. Use double to get true division.

For Array class, the [] operation stands for calls to member functions get() and set(). Arrays in Kotlin are invariant.

Kotlin also has specialized classes to represent arrays of primitive types without boxing overhead: ByteArray, ShortArray, IntArray and so on.

Strings are immutable. Elements of a string are characters that can be accessed by the indexing operation: s[i]. A string can be iterated over with a for-loop. Raw string is delimited by a triple quote ("""). You can remove leading whitespace with trimMargin() function. By default | is used as margin prefix, but you can choose another character and pass it as a parameter, like trimMargin(">").