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. The source code can be in any directory, no need to match the package name.

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
62
63
64
65
66
// function with two parameters and return types
fun sum(a: Int, b: Int): Int {
  return a + b
}

// single-expression function 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 // type required when initializer is not provided
c = 3

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

/* block comments can be nested
/* nested comments */ and outside */

// string templates
val a = 1
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
// use !is to check is not
if (message is String && message.length > 0) {
  return message.length
}

// when expression can use value, range, type

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

// ranges, in and !in
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 (include 10), 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

In Editor | Code Style | Kotlin, click Set from... and choose Kotlin style guide. In Editor | Inspections | Kotlin | Style issues, enable 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 for compile time values or toplevel val for runtime values) use all uppercase words separated by underscores like CONST_NAME.

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.

Char literals use single quotes 1, a. Built-in operations include ||, && and !.

Boolen has two values: true and false.

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(">").