Vous êtes sur la page 1sur 154

Table

of Contents
1.1
1.2
1.3
1 Kotlin 1.4
1.1 Kotlin 1.4.1
1.2 Kotlin 1.4.2
1.3 Kotlin 1.4.3
1.4 Kotlin 1.4.4
1.5 Kotlin 1.4.5
1.6 1.4.6
2 Kotlin 1.5
2.1 1.5.1
2.2 1.5.2
2.3 `when` 1.5.3
2.4 : whilefor 1.5.4
2.5 Kotlin 1.5.5
2.6 1.5.6
3 1.6
3.1 Kotlin 1.6.1
3.2 1.6.2
3.3 1.6.3
3.4 : vararginfix 1.6.4
3.5 1.6.5
3.6 1.6.6
3.7 1.6.7
4 1.7
4.1 1.7.1
4.2 1.7.2
4.3 1.7.3
4.4 object 1.7.4

1
4.5 1.7.5
5 lambda 1.8
5.1 lambda 1.8.1
5.2 API 1.8.2
5.3 : 1.8.3
5.4 Java 1.8.4
5.5 lambda: withapply 1.8.5
5.6 1.8.6
6 Kotlin 1.9
6.1 1.9.1
6.2 1.9.2
6.3 1.9.3
6.4 1.9.4
7 1.10
7.1 1.10.1
7.2 1.10.2
7.3 1.10.3
7.4 1.10.4
7.5 1.10.5
7.6 1.10.6
8 : lambda 1.11
8.1 1.11.1
8.2 : lambda 1.11.2
8.3 1.11.3
8.4 1.11.4
9 1.12
9.1 1.12.1
9.2 : 1.12.2
9.3 : 1.12.3
9.4 1.12.4
10 1.13
10.1 1.13.1
10.2 : Kotlin 1.13.2
10.3 1.13.3

2
11 DSL 1.14
11.1 APIDSL 1.14.1
11.2 API: DSLlambda 1.14.2
11.3 invoke 1.14.3
11.4 Kotlin DSL 1.14.4
11.5 1.14.5
A: Kotlin 1.15
B: Kotlin 1.16
C: Kotlin 1.17

MEAPKotlin
Java--KotlinKotlin
JavaAndroid
JavaKotlinKotlin
KotlinJava

kotlinAndroid

Kotlin
Kotlin1.0
MEAP

--Dmitry Jemerov Svetlana Isakova

1 . Kotlin

2 . Kotlin

3 .

4 .

5 . lambda

6 . Kotlin

Kotlin
7 .

8 . lambda

9 .

10 .

11 . DSL Construction

A. Kotlin
B. Kotlin
C. Kotlin



http://www.broadview.com.cn/book/4877

GitHuber:eggersoncereplygefangshuai

7
1 Kotlin

Kotlin

Kotlin

Android

Kotlin
Kotlin

8
1.1 Kotlin

Kotlin Kotlin Java


Java Java
Android Kotlin
Java Java
Kotlin Person Person
Person
Kotlin

https://try.kotl.in/
Run

package ch01.ATasteOfKotlin

data class Person(val name: String, // 1


val age: Int? = null) // 2 (Int?)

fun main(args: Array<String>) { // 3


val persons = listOf(Person("Alice"),
Person("Bob", age = 29)) // 4

val oldest = persons.maxBy { it.age ?: 0 } // 5 lambdaelvis


println("The oldest is: $oldest") // 6
}

// The oldest is: Person(name=Bob, age=29) // 7 `toString`

: name age age null (


)Alice null
maxBy lambda
it age null
?: 0Alice0Bob
Kotlin

9
1.2 Kotlin

Kotlin
Kotlin

1.2.1 AndroidJava

KotlinJava
JavaJava
Java
Kotlin

Kotlin

web
Android

KotlinIntel Multi-OS iOS


KotlinJavaFXKotlin
JavaKotlinJavascriptKotlin
KotlinJavaScriptJetBrains
Kotlin
Kotlinkotlin

Kotlin
Kotlin

1.2.2
Java Kotin

JVMGroovyJRuby

Java
Kotlin

var x = 1

10
1.2 Kotlin

Kotlin
Int

-
-
-

- IDE

Kotlin

Kotlin
JavaJavaKotlinKotlin

Kotlin(nullable type)

Kotlin(functional types)
Kotlin

1.2.3
Java

-

-
-

lambda

11
1.2 Kotlin

fun findAlice() = findPerson { it.name == "Alice" } // 1 findPerson()



fun findBob() = findPerson { it.name == "Bob" } // 2


Java
Java8
JavaKotlin


lambda

API API

Kotlin

JavaKotlin

1.2.4
Kotlin
KotlinApache 2GitHub
KotlinIntelliJ IDEA Android Studio
EclipseIntelliJ IDEA
KotlinKotlin

12
1.3 Kotlin

KotlinAndroid
Kotlin

1.3.1 Kotlin

HTMLweb
HTTPJSON API
RPC

Java

KotlinJava
KotlinKotlinKotlin
Java

Kotlin

HTML

fun renderPersonList(persons: Collection<Person>) =


createHTML().table { // 1
for (person in persons) { // 2
tr { // 1
td { +person.name } // 1
td { +person.age } // 1
}
}
}

// 1 HTML
// 2 Kotlin

HTMLKotlin
HTML
KotlinDSL
Exposed SQLDSL
Kotlin

13
1.3 Kotlin

object CountryTable : IdTable() { // 1


val name = varchar("name", 250).uniqueIndex()
val iso = varchar("iso", 2).uniqueIndex()
}

class Country(id: EntityID) : Entity(id) { // 2


var name: String by CountryTable.name
var iso: String by CountryTable.iso
}

val russia = Country.find { // 3 Kotlin


CountryTable.iso.eq("ru")
}.first()

println(russia.name)

11

1.3.2 Kotlin Android

Kotlin

KotlinAndroidAndroid

Anko
KotlinAndroid APIKotlin
Anko
KotlinAndroid Activity
Android

verticalLayout {
val name = editText() // 1
button("Say Hello") { // 2
onClick { toast("Hello, ${name.text}!") } // 3 API
}
}

KotlinAndroid
Unfortunately, Process Has Stopped
NullPointerException Kotlin
Java
NullPointerException ,Kotlin

14
1.3 Kotlin

KotlinJava6
Kotlin
Android
KotlinKotlinJava
Kotlin
lambdaKotlin
lambda

KotlinJavaKotlin--Kotlin
JVM

15
1.4 Kotlin

Kotlin

1.4.1
Kotlin

JetBrainsKotlin
Kotlin

Kotlin

Kotlin
Java
Kotlin
Kotlin
Kotlin
IDE
KotlinIntelliJ IDEA

KotlinIDE

1.4.2

Kotlin
JavagettersetterKotlin

16
1.4 Kotlin

Kotlin
Kotlinlambda


Kotlin
Kotlinlambda

Kotlin
Kotlin

1.4.3

KotlinJava
JVM
JVMKotlin
Java

KotlinJava
Kotlin NullPointerException Kotlin
NullPointerExcepption

val s: String? = null // 1


val s2: String = "" // 2

Kotlin

Kotlin ClassCastException

Java

17
1.4 Kotlin

Kotlin:
Kotlin

if (value is String) // 1
println(value.toUpperCase()) // 2

1.4.4
Kotlin
APIKotlin
JavaJavaKotlinJava
JVMKotlinJava
KotlinKotlinJava
JavaKotlin
JavaKotlinJava-Kotlin

KotlinJavaKotlin
Java
KotlinXREF ID_xx Java API
KotlinKotlinAPI
KotlinJavaKotlin
IDE

JavaKotlin

KotlinJava

Kotlin
Kotlin

18
1.5 Kotlin

JavaKotlinKotlin

Kotlin

1.5.1 Kotlin
Kotlin .kt Kotlin .class
Java .class
kotlinc java

kotlinc <source file or directory> -include-runtime -d <jar name>


java -jar <jar name>

Kotlin1.1

KotlinKotlin KotlinKotlin
Java API
MavenGradleAnt
KotlinA
KotlinJavaMaveGradl
Kotlin

1.5.2 IntelliJ IDEAAndroid Studio


KotlinIntelliJ IDEA Kotlin
IntelliJ IDEAKotlin
IntelliJ IDEA 15Kotlin
IntelliJ IDEAIntelliJ IDEA

19
1.5 Kotlin

Kotlin
Android StudioKotlin
JetBrainsKotlin

1.5.3 shell
KotlinshellREPLREPL
KotlinREPL
kotlinc IntelliJ IDEA

1.5.4 Eclipse
EclipseIDEKotlinKotlinEclipse
IDEEclipse
Help > Eclipse Marketplace Kotlin

1.5.5
Kotlin(https://try.kotl.in )
Kotlin
KotlinKotlin

1.5.6 Java-Kotlin

JavaKotlin
Kotlin
JavaKotlin
KotlinKotlin

KotlinJava
Kotlin
KotlinKotlin

IntelliJ IDEAJavaKotlin
JavaKotlinEclipse

20
1.5 Kotlin

21
1.6

Kotlin
kotlin

KotlinJava
HTML
KotlinAndroidAndroid API
AndroidKotlin
KotlinIDE
Kotlin
NullPointerException ,
Java

22
2 Kotlin

Kotlin
KotlinJava

Kotlin
Kotlin

23
2.1

KotlinKotlin

2.1.1 Hello, World!


Hello,worldKotlin

fun main(args: Array<String>) {


println("Hello, world!")
}

fun Kotlin



JavaKotlin
println System.out.println Kotlin
Java println

2.1.2

fun max(a: Int, b: Int): Int {


return if (a > b) a else b
}

>>> println(max(1, 2))


2

24
2.1

2.1 Kotlin

NOTE
Kotlin if

Java(statement)Kotlin


JavaKotlin

return

fun max(a: Int, b: Int): Int = if (a > b) a else b

TIPIntelliJ IDEA Tip


IntelliJ IDEA """
"

Kotlin
if, when, try
when
max

fun max(a: Int, b: Int) = if (a > b) a else b

25
2.1

max

fun max(a: Int, b: Int) = if (a > b) a else b

Kotlin

return

2.1.3
JavaKotlinKotlin
Kotlin

val question = "The Ultimate question of Life, the Universe, and Everything"
val answer = 42

val answer: Int = 42

,42, Int

Double

val yearsTocompute = 7.5e6 // 7.5 * 106 = 7500000.0

XREF ID_

val answer: Int


answer = 42

26
2.1

val() val
Javafinal
var() Java
(final)

Kotlin val val


var

val

val message: String


if ( canPerformOperation()) {
message = "Success"
// ... perform the operation
}
else {
message = "Failed"
}

val

val languages = arraylistOf("Java") // 1


languages.add("Kotlin") // 2

var

var answer = 42
answer = "no answer" //

String Int

XREF ID_

2.1.4

27
2.1

XREF ID_

2.1.4
Hello WorldKotlin

fun main(args: Array<String>) {


val name = if (args.size > 0) args[0] else "Kotlin"
println("Hello, $name!") // "Hello, Kotlin","Hello, Bob""Bob"

}

name
Kotlin
$ Java("Hello, " + name + "!")

$ println("\$x")
$x x

fun main(args: Array<String>) {


if (args.size > 0) {
println("Hello, ${args[0]}!") // `${}`args
}
}

fun main(args: Array<String>) {


println("Hello, ${if (args.size > 0) args[0] else "someone"}!")
}

JavaKotlin

28
2.1

29
2.2

Kotlin

JavaBean Person name

/* Java */
public class Person {
private final String name;

public Person(String name) {


this.name = name;
}

public String getName() {


return name;
}
}

Java
Kotlin
1.5.6Java-KotlinKotlin
Java Person Kotlin

class Person(val name: String)

JVM

JavaKotlin
JavaKotlin public Kotlin public

2.2.1
Java

Person

Java
Kotlin
val var val
var :

30
2.2

class Person(
val name: String, // 1
var isMarried: Boolean // 2
)

Person Java
Java
Kotlin
Java Person

/* Java */
>>> Person person = new Person("Bob", true);
>>> System.out.println(person.getName());
Bob
>>> System.out.println(person.isMarried());
true

Person JavaKotlinKotlin name


JavagetName()
is Java
isMarried()
Kotlin

>>> val person = Person("Bob", true) // 1


>>> println(person.name) // 2
Bob
>>> println(person.isMarried) // 2
true

// 1 new
// 2

Java person.setMarried(false)
Kotlin person.isMarried = false

31
2.2

TIPProperties of Java classes


JavaKotlinJavaKotlin
val / var
Java getName() setName()
name isMarried() setMarried() Kotlin
isMarried


class Rectangle(val height: Int, val width: Int) {


val isSquare: Boolean
get() { //
return height == width
}
}

isSquare

get() = height ==width

>>> val rectangle = Rectangle(41, 43)


>>> println(rectangle.isSquare)
false

Java isSquare()

32
2.2

Java-to-Kotlin
Kotlin

2.2.3 Kotlin
Java Kotlin
Java Kotlin package

Java import

package geometry.shapes // 1

import java.util.Random // 2 Java

class Rectangle(val height: Int, val width: Int) {


val isSquare: Boolean
get() = height == width
}

fun createRandomRectangle(): Rectangle {


val random = Random()
return Rectangle(random.nextInt(), random.nextInt())
}

Kotlin import

package geometry.example

import geometry.shapes.createRandomRectangle // 1

fun main(args: Array<String>) {


println(createRandomRectangle().isSquare) // 2 true
}

.*
import
geometry.shapes.*

Java

33
2.2

shapes
shapes 2.2 geometry Java
createRandomRectangle
RectangleUtil

2.2 Java
Kotlin
Kotlin
shapes.kt geometry.shapes
geometry shapes
2.3

2.3

Java
Java Kotlin

Kotlin
Kotlin

34
2.3 `when`

when Java switch

2.3.1

enum class Color {


RED, ORANGE, YELLOW, GREEN, BLUE, INDIGO, VIOLET
}

Kotlin Java enum class


Java enum Kotlin enum (soft keyword)
class
class class
clazz aClass
Java

enum class Color(


val r: Int, val g: Int, val b: Int // 1
) {
RED(255, 0, 0), ORANGE(255, 265, 0), // 2
YELLOW(255, 255, 0), GREEN(0, 255, 0), BLUE(0, 0, 255),

INDIGO(75, 0, 130), VIOLET(238, 130, 238); // 3 ;

fun rgb() = (r * 256 + g) * 256 + b // 4


}
>>> println(Color.BLUE.rgb())
255

Kotlin

2.3.2 when

35
2.3 `when`

"Richard Of York
Gave Battle In Vain!"
Java switch
Kotlin when
if when
when

fun getMnmonic(color: Color) = // 1 when


when (color) { // 2
Color.RED -> "Richard"
Color.ORANGE -> "Of"
Color.YELLOW -> "York"
Color.GREEN -> "Grave"
Color.BLUE -> "Battle"
Color.INDIGO -> "In"
Color.VIOLET -> "Vain"
}

>>> println(getMnemonic(Color.BLUE))
Battle

color Java break


Java break bug

fun getWarmth(color: Color) = when(color) {


Color.RED, Color.ORANGGE, Color.YELLOW -> "warm"
Color.GREEN -> "neutral"
Color.BLUE, Color.INDIGO, Color.VIOLET -> "cold"
}

>>> println(getWarmth(Color.ORANGE))
warm

Color

36
2.3 `when`

import ch02.colors.Color // 1 Color


import ch02.colors.Color.* // 2

fun getWarmth(color: Color) = when(color) {

RED, ORANGE, YELLOW -> "warm" // 3


GREEN -> "neutral"
BLUE, INDIGO, VIOLET -> "cold"
}

2.3.3 when
Kotlin when Java switch

switch when

fun mix(c1: Color, c2: Color) =


when (setOf(c1, c2)) { // 1 when

setOf(RED, YELLOW) -> ORANGE // 2
setOf(YELLOW, BLUE) -> GREEN
setOf(BLUE, VIOLET) -> INDIGO

else -> throw Exception("Dirty color") // 3

>>> println(mix(BLUE, YELLOW))


GREEN

c1c2 RED YELLOW () ORANGE


Kotlin
setOf set
setOf(c1, c2) setOf(RED, YELLOW)
c1 RED c2 YELLOW
when
setOf(c1, c2) setOf(RED, YELLOW)
else

37
2.3 `when`

when

2.3.4 when

Set

when

fun mixOptimized(c1: Color c2: Color) =

when { // when
(c1 == RED && c2 == YELLOW) ||
(c1 == YELLOW && c2 == RED) ->
ORANGE

(c1 == YELLOW && c2 == BLUE) ||


(c1 == BLUE && c2 == YELLOW) ->
GREEN

(c1 == BLUE && c2 == VIOLET) ||


(c1 == VIOLET && c2 == BLUE) ->
INDIGO

else -> throw Exception("Dirty color")


}

>>> println(mixOptimized(BLUE, YELLOW))


GREEN

when mixOptimized
mix

when smart casts

2.3.5

38
2.3 `when`

(1 + 2) + 4

Sum Num Num Sum


sum
Expr Num Sum Expr

interface Expr
class Num(val value: Int) : Expr // 1 Expr

class Sum(val left: Expr, val right: Expr) : Expr // 2 ExprN


umSum

Sum Expr left right Num

Sum 1 + 2 + 4 Sum(Sum(Num(1),
Num(2)), Num(4)) 2.4

2.4 Sum(Sum(Num(1), Num(2)), Num(4))

>>> eval(Sum(Sum(Num(1), Num(2)), Num(4)))


7

39
2.3 `when`

Expr

Java Kotlin
Java if
Kotlin

fun eval(e: Expr): Int {


if (e is Num) {
val n = e as Num // 1 Num
return n.value
}
if (e is Sum) {
return eval(e.right) + eval(e.left) // 2 e
}
throw IllegalArgumentException("Unknown expression")
}
>>> println(eval(Sum(Sum(Num(1), Num(2)), Num(4))))
7

Kotlin is C#
is Java instanceof Java

instanceof
Kotlin

(smart cast)
eval e Num
Num Num value
e.value Sum right left
e.right e.left IDE2.5

2.5 IDE

is
val

40
2.3 `when`

as

val n = e as Num

eval Kotlin

2.3.6 when if
Kotlin if Java if

if Java: if (a > b)
Java a > b ? a : b KotlinJava if
eval return
if

fun eval(e: Expr): Int =


if (e is Num) {
e.value
} else if (e is Sum) {
eval(e.right) + eval(e.left)
} else {
throw IllegalArgumentException("Unknown expression")
}
>>> println(eval(Sum(Num(1), Num(2))))
3

if if

when

fun eval(e: Expr): Int =


when (e) {
is Num -> // 1 when
e.value // 2
is Sum -> // 1 when
eval(e.right) + eval(e.left) // 2
else ->
throw IllegalArgumentException("Unknown expression")
}

41
2.3 `when`

when

when when if
Num Sum
Kotlin eval
when if

2.3.7 if when
if when

fun evalWithLogging(e: Expr): Int =


when (e) {
is Num -> {
println("num: ${e.value}")
e.value // 1 eNum
}
is Sum -> {
val left = evalWithLogging(e.left)
val right = evalWithLogging(e.right)
println("sum: $left + $right")

left + right // 2 eSum


}
else -> throw IllegalArgumentException("Unknown expression")
}

evalWithLogging

>>> println(evalWithLogging(Sum(Sum(Num(1), Num(2)), Num(4))))


num: 1
num: 2
sum: 1 + 2
num: 4
sum: 3 + 4
7

trycatch
5lambda2.2.1

42
2.3 `when`

return
Kotlin

43
2.4 : whilefor

Kotlin Java while


Java for
Java for-each C# for <item> in <elements>
Java

2.4.1 while
Kotlin while do-while Java

while (condition) { // 1 while


/*...*/
}

do {
/*...*/
} while (condition) // 2

Kotlin

for

2.4.2
Kotlin Java for

Kotlin ranges

..

val oneToTen = 1..10

Kotlin

(progression)
Fizz-Buzz
fizz3

44
2.4 : whilefor

buzz535"FizzBuzz"
1100 when

fun fizzBuzz(i: Int) = when {


i % 15 == 0 -> "FizzBuzz " // 1 i15FizzBuzzJava%

i % 3 == 0 -> "Fizz " // 2 i3Fizz


i % 5 == 0 -> "Buzz " // 3 i5Buzz
else -> "$i " // 4
}
>>> for (i in 1..100) { // 5 1..100
... print(fizzBuzz(i))
... }
}
1 2 Fizz 4 Buzz Fizz 7

100

>>> for (i in 100 downTo 1 step 2) {


... print(fizzBuzz(i))
... }
Buzz 98 Fizz 94 92 FizzBuzz 88

(step)
100 downTo 1
-1 step 2
-2
.. ..

util for (x in 0 until size) for (x in 0..size-


1) Working

with paris: infix calls and destructuring declarations


downTo, step until FizzBuzz
for

2.4.2

45
2.4 : whilefor

for .. in Java

val binaryReps = TreeMap<Char, String>() // 1 TreeMap

for (c in 'A'..'F') { // 2 AF
val binary = Integer.toBinaryString(c.toInt()) // 3 ASCII
binaryReps[c] = binary // 4 c
}
for ((letter, binary) in binaryReps) { // 5

println("$letter = $binary")
}

..

A F
unpack for letter
binary Destructuring declarations and loops

map[key] map[key] = value


get() put() binaryReps[c] = binary Java binaryReps.put(c,
binary)

A = 1000001 D = 1000100
B = 1000010 E = 1000101
C = 1000011 F = 1000110

item

val list = arrayListOf("10", "11", "1001")


for ((index, element) in list.withIndex()) { //
println("$index: $element")
}

46
2.4 : whilefor

0: 10
1: 11
2: 1001

withIndex
in in

2.4.4 in
in !in
in

fun isLetter(c: Char) = c in 'a'..'z' || c in 'A'..'Z'


fun isNotDigit(c: Char) = c !in '0'..'9'
>>> println(isLetter('q'))
true
>>> println(isNotDigit('x'))
true

range

c in 'a'..'z' // 1 a c && c z

in !in when

fun recognize(c: Char) = when (c) {


in '0'..'9' -> "It's a digit!" // 1 09
in 'a'..'z', in 'A'..'Z' -> "It's a letter!" // 2
else -> "I don't know"
}
>>> println(recognize('8'))
It's a digit!

47
2.4 : whilefor

java.lang.Comparabble

"Java""Kotlin"
in

>>> println("Kotlin" in "Java".."Scala") // "Java".."Kotlin""Kotlin".."Scala"


true

String Comparable
in

>>> println("Kotlin" in setOf("Java", "Scala")) // "Kotlin"


in
false

Java

48
2.5 Kotlin

KotlinJava

KotlinJava

if (percentage !in 0..100) {


throw IllegalArgumentException(
"A percentage value must be between 0 and 100: $percentage")
}

new JavaKotlin
throw ;

val percentage =
if (number in 0..100)
number
else
throw IllegalArgumentException( // throw
"A percentage value must be between 0 and 100: $number")

percentage
number
The nothing type throw

2.5.1 try , catch finally


Java catch try finally

null

49
2.5 Kotlin

fun readNumber(reader: BufferedReader): Int? { // 1


try {
val line = reader.readLine()
return Integer.parseInt(line)
}
catch (e: NumberFormatException) { // 2
return null
}
finally { // 3 finallyJava
reader.close()
}
}
>>> val reader = BufferedReader(StringReader("239"))
>>> println(readNumber(reader))
239

(Kotlin)Java throws Java


throws IOException
IOException checked exceptionJava


JVMKotlin
Java
Java

NumberFormatException Java

BufferedReader.close() IOException
close()
Java 7 try-with-resources Kotlin
lambdas for
resource management

2.5.2 try
JavaKotlin
finally

50
2.5 Kotlin

fun readNumber(reader: BufferedReader) {


val number = try {
Integer.parseInt(reader.readLine()) // 1 try
} catch (e: NumberFormatException) {
return
}

println(number)
}
>>> val reader = BufferedReader(StringReader("not a number"))
>>> readNumber(reader) // 2

Kotlin try if when


if
try
catch return catch
catch

fun readNumber(reader: BufferedReader) {


val number = try {
Integer.parseInt(reader.readLine()) // 1
} catch (e: NumberFormatException) {
null// 2 null
}

println(number)
}
>>> val reader = BufferedReader(StringReader("not a number"))
>>> readNumber(reader)
null// 3 ''null"

try try
catch
NumberFormatException null
JavaKotlin

51
2.6

fun val var

$ ${ }

-Kotlin
if
when Java switch



for, while do-while Java for


1..5 Kotlin for
in !in

KotlinJavaKotlin

52
3



JavaKotlin

JavaKotlinKotlin
Kotlin
JavaKotlin
Kotlin
Kotlin
Kotlin

53
3.1 Kotlin

when
setOf

val set = setOf(1, 7, 53)

val list = listOf(1, 7, 53)


val map = mapOf(1 to "one", 7 to "seven", 53 to "fifty-three")

to

>>> println(set.javaClass) // 1 javaClassKotlinJavagetClass()


class java.util.HashSet
>>> println(list.javaClass)
class java.util.ArrayList
>>> println(map.javaClass)
class java.util.HashMap

KotlinJavaJavaKotlin
Java Kotlin
JavaKotlinJavaKotlin
Java KotlinJava
Kotlin

>>> val strings = listOf("first", "second", "fourteenth")

>>> println(strings.last())
fourteenth

>>> val numbers = setOf(1, 14, 2)

>>> println(numbers.max())
14

54
3.1 Kotlin

Java

Javacolleions
JavaKotlin Java
last max

55
3.2

Java toString

>>> val list = listOf(1, 2, 3)


>>> println(list) // 1 toString()
[1, 2, 3]

(1; 2; 3) JavaGuavaApache
CommonsKotlin
Kotlin
Kotlin
joinToString StringBuilder

fun <T> joinToString(


collection: Collection<T>,
separator: String,
prefix: String,
postfix: String
): String {

val result = StringBuilder(prefix)

for ((index, element) in collection.withIndex()) {


if (index > 0) result.append(separator) // 1
result.append(element)
}

result.append(postfix)
return result.toString()
}

Java
9

>>> val list = listOf(1, 2, 3)


>>> println(joinToString(list, "; ", "(", ")"))
(1; 2; 3)

56
3.2

3.2.1

joinToString()

joinToString(collection, " ", " ", ".")

IDE
Java

String

/* Java */
joinToString(collection, /* separator */ " ", /* prefix */ " ",
/* postfix */ ".");

Kotlin

joinToString(collection, separator = " ", prefix = " ", postfix = ".")

Kotlin

TIP

IntelliJ IDEA

WARNING

JavaJDK
AndroidJava8.class
KotlinJava6.

57
3.2

3.2.2
Java java.lang.Thread
API

7 http://mng.bz/1vKt
Kotlin
joinToString

fun <T> joinToString(


collection: Collection<T>,
separator: String = ", ", // 1
prefix: String = "",
postfix: String = ""
): String

>>> joinToString(list, ", ", "", "")


1, 2, 3
>>> joinToString(list)
1, 2, 3
>>> joinToString(list, "; ")
1; 2; 3

>>> joinToString(list, prefix = "# ")


# 1, 2, 3

58
3.2

NOTEJava JavaJava
Kotlin
JavaJava @JvmOverloads
Java
@JvmOverloads joinToString()

/* Java */
String joinToString(Collection<T> collection, String separator,
String prefix, String postfix);
String joinToString(Collection<T> collection, String separator,
String prefix);
String joinToString(Collection<T> collection, String separator);
String joinToString(Collection<T> collection);

Kotlin

3.2.3 (top-level)
Java

API
JDK
Collections Util
Kotlin

joinToString strings
join.kt

package strings
fun joinToString(...): String { ... }

JVM
Kotlin
Java

59
3.2

Java

/* Java */
package strings;
public class JoinKt { // join.kt
public static String joinToString(...) { ... }
}

Kotlin
Java

/* Java */
import strings.JoinKt;
...
JoinKt.joinToString(list, ", ", "", "");

SIDEBAR Kotlin
@JvmName

@file:JvmName("StringFunctions") // 1
package strings // 2
fun joinToString(...): String { ... }

/* Java */
import strings.StringFunctions;
StringFunctions.joinToString(list, ", ", "", "");

TOP-LEVEL PROPERTIES

var

60
3.2

var opCount = 0 // 1
fun performOperation() {
opCount++ // 2
// ...
}
fun reportOperationCount() {
println("Operation performed $opCount times") // 3
}

Top-level properties

val UNIX_LINE_SEPARATOR = "\n"

val
/JavaJava public
static final const

String

const val UNIX_LINE_SEPARATOR = "\n"

Java

/* Java */
public static final String UNIX_LINE_SEPARATOR = "\n";

joinToString

61
3.3

KotlinKotlinJDKAndroid
JavaKotlinJava
KotlinAPIKotlin

package strings
fun String.lastChar(): Char = this.get(this.length - 1)

receiver type
receiver object3.1

3.1

>>> println("Kotlin".lastChar())
n

String "Kotlin"
String String
String Java
KotlinJVMGroovyJava
this

package strings
fun String.lastChar(): Char = get(length - 1) // 1 "this"

62
3.3

3.3.1

Kotlin

import strings.lastChar
val c = "Kotlin".lastChar()

import strings.*
val c = "Kotlin".lastChar()

as

import strings.lastChar as last


val c = "Kotlin".last()

as

3.3.2 Java

Java

java
StringUtil.kt

/* Java */
char c = StringUtilKt.lastChar("Java");

63
3.3

Java
lastChar " lastChar "Kotlin
Java

3.3.3
joinToString Kotlin

fun <T> Collection<T>.joinToString( // 1 Collection<T>


separator: String = ", ", // 2
prefix: String = "", // 2
postfix: String = "" //2
): String {
val result = StringBuilder(prefix)
for ((index, element) in this.withIndex()) { // 3 "this":T
if (index > 0) result.append(separator)
result.append(element)
}
result.append(postfix)
return result.toString()
}

joinToString

>>> val list = arrayListOf(1, 2, 3)


>>> println(list.joinToString(" "))
1 2 3

join

64
3.3

fun Collection<String>.join(
separator: String = ", ",
prefix: String = "",
postfix: String = ""
) = joinToString(separator, prefix, postfix)

>>> println(listOf("one", "two", "eight").join(" "))


one two eight

>!> listOf(1, 2, 8).join()


Error: Type mismatch: inferred type is List<Int> but Collection<String>
was expected.

overridden

3.3.4 overriding
Kotlin
View Button Button click

open class View {


open fun click() = println("View clicked")
}
class Button: View() { // 1 ButtonView
override fun click() = println("Button clicked")
}

View Button
Button View click()
Button Button

>>> val view: View = Button()


>>> view.click() // 1 Button//AU:TT
Button clicked

3.2

65
3.3

3.2


View Button showOff

fun View.showOff() = println("I'm a view!")


fun Button.showOff() = println("I'm a button!")

>>> val view: View = Button()


>>> view.showOff() // 1
I'm a view!

View showOff
Button Java
Java

/* Java */
>>> View view = new Button();
>>> ExtensionsKt.showOff(view); // 1 showOffextensions.kt
I'm a view!

Kotlin


API

66
3.3

3.3.5 Extension properties


API
Java

lastChar

val String.lastChar: Char


get() = get(length - 1)

getter

StringBuilder var
StringBuilder

var StringBuilder.lastChar: Char


get() = get(length - 1) // 1
set(value: Char) { // 2
this.setCharAt(length - 1, value)
}

>>> println("Kotlin".lastChar)
n
>>> val sb = StringBuilder("Kotlin?")
>>> sb.lastChar = '!'
>>> println(sb)
Kotlin!

Java
StringUtilKt.getLastChar("Java")

67
3.4 : vararginfix

Kotlin

vararg


(Destructuring)

3.4.2 JavaAPI
KotlinJavaAPI

>>> val strings: List<String> = listOf("first", "second", "fourteenth")


>>> strings.last()
fourteenth
>>> val numbers: Collection<Int> = setOf(1, 14, 2)
>>> numbers.max()
14

KotlinJava
last max last
String lastChar List
max Int

fun <T> List<T>.last(): T { /* returns the last element */ }


fun Collection<Int>.max(): Int { /* finding a maximum in a collection */ }

Kotlin
Kotlin--
IDE
IDE

3.4.2 Varargs:

68
3.4 : vararginfix

val list = listOf(2, 3, 5, 7, 11)

fun listOf<T>(vararg values: T): List<T> { ... }

Java
KotlinJava
vararg KotlinJava
Java
Kotlinunpack the array
spread operator *

fun main(args: Array<String>) {


val list = listOf("args: ", *args) // 1 (unpack)
println(list)
}

Java
Kotlin
infix call

3.4.3 pairs
mapOf()

val map = mapOf(1 to "one", 7 to "seven", 53 to "fifty-three")

to infix call

69
3.4 : vararginfix

1.to("one") // 1
1 to "one" // 2

infix to

infix fun Any.to(other: Any) = Pair(this, other)

to Pair Pair Kotlin

Pair to

val (number, name) = 1 to "one"

(destructuring declaration)3.3

3.3 to

key value
joinToString()
withIndex()

for ((index, element) in collection.withIndex()) {


println("$index: $element")
}

70
3.4 : vararginfix

7.4 to
1
to "one" , "one" to 1 , list to list.size() mapOf

fun <K, V> mapOf(vararg values: Pair<K, V>): Map<K, V>

listOf, mapOf
Kotlin

71
3.5

KotlinJavaKotlin
JavaJavaKotlin
Kotlin
Java
APIKotlin

3.5.1
String split Stack
OverflowJava split
"12.345-6.A".split(".") [12, 345-6, A] Java
split
.
Kotlin
split ( split ) Regex
String

>>> println("12.345-6.A".split("\\.|-".toRegex())) // 1
[12, 345, 6, A]

KotlinJava

APIJavaAPIKotlin
toRegex
Kotlin split

>>> println("12.345-6.A".split(".", "-")) // 1


[12, 345, 6, A]

72
3.5

"12.345-6.A".split('.', '-')
Java

3.5.2 (triple-quoted
strings)

Kotlin
3.4

fun parsePath(path: String) {


val directory = path.substringBeforeLast("/")
val fullName = path.substringAfterLast("/")
val fileName = fullName.substringBeforeLast(".")
val extension = fullName.substringAfterLast(".")
println("Dir: $directory, name: $fileName, ext: $extension")
}
>>> parsePath("/Users/yole/kotlin-book/chapter.adoc")
Dir: /Users/yole/kotlin-book, name: chapter, ext: adoc

3.4 substringBeforeLast substringAfterLast


Kotlin

Kotlin

fun parsePathRegexp(path: String) {


val regex = """(.+)/(.+)\.(.+)""".toRegex()
val matchResult = regex.matchEntire(path)
if (matchResult != null) {
val (directory, filename, extension) = matchResult.destructured
println("Dir: $directory, name: $filename, ext: $extension")
}
}

73
3.5

\.
\\. 3.5

3.5

.
(.+)

parsePathRegexp
null
destructured
7.4

3.5.3

ASCII

val kotlinLogo = """| //


.|//
.|/ \"""
>>> println(kotlinLogo.trimMargin("."))
| //
|//
|/ \

trimMargin()

\n \
windows "C:\\Users\\yole\\kotlin-book" """C:\Users\yole\kotlin-
book"""

val price = """${'$'}99.9""" ASCII

74
3.5

--
HTML
trimMargin

NOTE API
-- Pimp my Library
KotlinJavaAnko
JetBrainsAndroid APIKotlinKotln-friendly
Spring
Kotlin

KotlinAPI
local
functions

75
3.6

Dont Repeat Yourself, DRYJava


IDE

Kotlin

class User(val id: Int, val name: String, val address: String)
fun saveUser(user: User) {
if (user.name.isEmpty()) {
throw IllegalArgumentException(
"Cannot save user ${user.id}: Name is empty")
}

if (user.address.isEmpty()) { // 1
throw IllegalArgumentException(
"Cannot save user ${user.id}: Address is empty")
}

// Save user to the database


}
>>> saveUser(User(1, "", ""))
java.lang.IllegalArgumentException: Cannot save user 1: Name is empty

76
3.6

class User(val id: Int, val name: String, val address: String)
fun saveUser(user: User) {

fun validate(user: User, // 1


value: String,
fieldName: String) {
if (value.isEmpty()) {
throw IllegalArgumentException(
"Cannot save user ${user.id}: $fieldName is empty")
}
}

validate(user, user.name, "Name") // 2


validate(user, user.address, "Address")

// Save user to the database


}

User User

User

class User(val id: Int, val name: String, val address: String)

fun saveUser(user: User) {

fun validate(value: String, fieldName: String) { // 1 saveUserus


er

if (value.isEmpty()) {
throw IllegalArgumentException(
"Can't save user ${user.id}: " + // 2
"$fieldName is empty")
}
}

validate(user.name, "Name")
validate(user.address, "Address")

// Save user to the database


}

>>> saveUser(User(1, "", ""))


java.lang.IllegalArgumentException: Cannot save user 1: Name is empty

User

77
3.6

class User(val id: Int, val name: String, val address: String)

fun User.validateBeforeSave() {
fun validate(value: String, fieldName: String) {
if (value.isEmpty()) {
throw IllegalArgumentException(
"Can't save user $id: empty $fieldName") // 1 User
}
}

validate(name, "Name")
validate(address, "Address")
}

fun saveUser(user: User) {

user.validateBeforeSave() // 2

// Save user to the database


}

User
UserUser
API


User.validateBeforeSave() saveUser()

78
3.7

KotlinAPIJava





API


Java

79
4




object

Kotlin2

KotlinJava
JavaKotlin
final public
Kotlin

Kotlin
data
Kotlin
object (singleton objects)
companion objects(Java)
Kotlin

80
4.1

4.1
Java,KotlinKotlinJava
sealed

4.1.1 Kotlin
KotlinJava 8
Java 8
Kotlin interface class :

interface Clickable {
fun click()
}

click()

class Button : Clickable {


override fun click() = println("I was clicked")
}

KotlinJava extends implements


override Java @Override
JavaKotlin override

override Java
8 default Kotlin
Clickable

interface Clickable {
fun click() // 1
fun showOff() = println("I'm clickable!") // 2
}

81
4.1

click() showOff()

showOff

interface Focusable {
fun setFocus(b: Boolean) =
println("I ${if (b) "got" else "lost"} focus.")

fun showOff() = println("I'm focusable!")


}

showOff
showOff

NOTE Button public open fun showOff() showOff


Kotlin

class Button : Clickable, Focusable {


override fun click() = println("I was clicked")

override fun showOff() { // 1



super<Clickable>.showOff() // 2 super
super<Focusable>.showOff()
}
}

Button showOff()

Java super
Java super
Clickable.super.showOff() Kotlin
super<Clickable>.showOff()

NOTE override fun showOff() = super<Clickable>.showOff()

82
4.1

fun main(args: Array<String>) {


val button = Button()
button.showOff() // 1
button.setFocus(true) // 2
button.click() // 3
}

setFocus Focusable Button

SIDEBAR Java Kotlin 1.0Java 6




JavaKotlin
KotlinJava 8Java 8
KotlinJava

Kotlin

4.1.2 open final abstract


final
Java
final


JavaJoshua BlochEffective Java

final KotlinJava
Kotlin final
open open

83
4.1

open class RichButton : Clickable { // 1

fun disable() {} // 2 *final*

open fun animate() {} // 3

override fun click() {} // 4


}

open

final

open class RichButton : Clickable {


final override fun click() {} // 1 `final``final`

}

SIDEBAR final
when
val final
(override)
final
KotlinJava
abstract

open

abstract class Animated { // 1

abstract fun animate() // 2

open fun stopAnimating() { // 3



}

fun animateTwice() { // 3
}
}

4.1 Kotlin

84
4.1

4.1


final
open
abstract

override
final

final, open abstract


open final
abstract

TIP Tip Java

4.1.3

KotlinJava
public, protected private
public Java
package-private KotlinKotlin
Kotlin
internal ''Kotlin
IntelliJ IDEAEclipseMavenGradleAnt
internal
Java
JavaKotlin
private
4.2

4.2 Kotlin

85
4.1


public()
internal
protected
private

giveSpeech

internal open class TalkativeButton : Focusable {


private fun yell() = println("Hey!")
protected fun whisper() = println("Let's talk!")
}

fun TalkativeButton.giveSpeech() { // 1 'public''internal'Tal


kativeButton

yell() // 2 'yell':TalkativeButton'protected'

whisper() // 3 'whisper':'TalkativeButton''private'

yell'private',whisper'protected'

Kotlin public giveSpeech TalkativeButton (


internal )

internal public JavaKotlin protected


Java protected Kotlin
Kotlin protected

86
4.1

SIDEBARJava JavaKotlin public,


protected private JavaKotlin

Java private
package-private Java
internal Java package-private

internal public KotlinJava
JavaKotlin
Java internal
JavaJava
internal internal Java
Java

KotlinJavaKotlin
Kotlin

4.1.4
JavaKotlin
Kotlin

View
Serializable State
View getCurrentState restoreState

interface State: Serializable

interface View {
fun getCurrentState(): State
fun restoreState(state: State) {}
}

Button Java
Kotlin

87
4.1

/* Java */
public class Button implements View {
@Override
public State getCurrentState() {
return new ButtonState();
}

@Override
public void restoreState(State state) { /*...*/ }
public class ButtonState implements State { /*...*/ }
}

State Button ButtonState


getCurrentState
ButtonState
java.io.NotSerializableException: Button
ButtonState state Button
Java
ButtonState Button
ButtonState Button
ButtonState ButtonState static
Kotlin

class Button : View {


override fun getCurrentState(): State = ButtonState()

override fun restoreState(state: State) { /*...*/ }

class ButtonState : State { /*...*/ } // 1 Java


}

KotlinJava
innner 4.3JavaKotlin
4.1

4.3 JavaKotlin

BA Java Kotlin

A A
A A

88
4.1

4.1

KotlinJava this@Outer Inner Outer

class Outer {
inner class Inner {
fun getOuterReference(): Outer = this@Outer
}
}

JavaKotlin
Kotlin

4.1.5
when Expr Num
Sum when
else

interface Expr
class Num(val value: Int) : Expr
class Sum(val left: Expr, val right: Expr) : Expr

fun eval(e: Expr): Int =


when (e) {
is Num -> e.value
is Sum -> eval(e.right) + eval(e.left)

else -> // 1 else


throw IllegalArgumentException("Unknown expression")
}

whenKotlin

89
4.1

bug
Kotlin(sealed)sealed

sealed class Expr { // 1

class Num(val value: Int) : Expr() // 2


class Sum(val left: Expr, val right: Expr) : Expr()
}

fun eval(e: Expr): Int =

when (e) { // 3 "when"""else"


is Expr.Num -> e.value
is Expr.Sum -> eval(e.right) + eval(e.left)
}

when
sealed open 4.2

4.2

Expr
KotlinJava
when

NOTE sealed
Kotlin

Kotlin

class Num(val value: Int) : Expr()

90
4.1

Expr()
Kotlin

91
4.2

JavaKotlin
primary constructor
secondary constructor
initializer blocks

4.2.1

class User(val nickname: String)

class User constructor(_nickname: String) { // 1

val nickname: String

init { // 2
nickname = _nickname
}
}

Kotlin constructor init constructor


init initializer

_nickname
this Java
this.nickname = nickname
nickname constructor

92
4.2

class User(_nickname: String) { // 1


val nickname = _nickname // 2
}

val
val

class User(val nickname: String) // 1 "val"

User

class User(val nickname: String,


val isSubscribed: Boolean = true) // 1

new

>>> val alice = User("Alice") // 1 isSubscribed"true"


>>> println(alice.isSubscribed)
true

>>> val bob = User("Bob", isSubscribed = false) // 2


>>> println(bob.isSubscribed)
false

AliceBob

NOTE

Kotlin

open class User(val nickname: String) { ... }


class TwitterUser(nickname: String) : User(nickname) { ... }

93
4.2

open class Button // 1

class Secretive private constructor() {} // 1

class Secretive {
private constructor()
}

Secretive

SIDEBAR Java
Kotlin
3.2.3
4.4.1

Kotlin
Kotlin

4.2.2
KotlinJavaJava
Kotlin

TIP

94
4.2

Java
Android View Kotlin

open class View {

constructor(ctx: Context) { // 1
// some code
}

constructor(ctx: Context, attr: AttributeSet) { // 1


// some code
}
}

constructor

class MyButton : View {


constructor(ctx: Context)
: super(ctx) { // 1
// ...
}

constructor(ctx: Context, attr: AttributeSet)


: super(ctx, attr) { // 1
// ...
}
}

super()
4.3

95
4.2

4.3

Java this()

class MyButton : View {


constructor(ctx: Context): this(ctx, MY_STYLE) { // 1
// ...
}

constructor(ctx: Context, attr: AttributeSet): super(ctx, attr) {


// ...
}
}

MyButton
4.4 super()

Java

4.4.2

4.2.3
Kotlin

interface User {
val nickname: String
}

96
4.2

User nickname
getter

PrivateUser SubscribingUser
FacebookUser FacebookID

class PrivateUser(override val nickname: String) : User // 1

class SubscribingUser(val email: String) : User {


override val nickname: String
get() = email.substringBefore('@') // 2 getter

}

class FacebookUser(val accountId: Int) : User {


override val nickname = getFacebookName(accountId) // 3

}

>>> println(PrivateUser("test@kotlinlang.org").nickname)
test@kotlinlang.org
>>> println(SubscribingUser("test@kotlinlang.org").nickname)
test

PrivateUser
User override
SubscribingUser nickname getter
backing fieldgetter
FacebookUser nickname
IDFacebook getFacebookName
Facebook
nickname SubscribingUser FacebookUser
substringBefore
getter FacebookUser
gettersetter

interface User {
val email: String
val nickname: String
get() = email.substringBefore('@') // 1
}

97
4.2

email nickname getter


4.2.4 gettersetter


setter

class User(val name: String) {var address: String = "unspecified"


set(value: String) {
println("""
Address was changed for $name:
"$field" -> "$value".""".trimIndent()) // 1

field = value // 2
}
}

>>> val user = User("Alice")


>>> user.address = "Elsenheimerstrae 47, 80687 Mnchen"
Address was changed for Alice:
"unspecified" -> "Elsenheimerstrae 47, 80687 Mnchen".

user.address = "new value" setter


setter
setter field
gettersetter
getter

field

4.2.5

98
4.2

get set

class LengthCounter {
var counter: Int = 0
private set // 1

fun addWord(word: String) {


counter += word.length}
}
}

API

gettersetter private

>>> val lengthCounter = LengthCounter()


>>> lengthCounter.addWord("Hi!")
>>> print(lengthCounter.counter)
3

LengthCounter "Hi!"3 counter


3

SIDEBAR

lateinit
6
7
JavaKotlinJava
@JvmFielld public
10
const String

10

Kotlin
data -

99
4.2

100
4.3

Java
, equals(),hashCode() toString() Java IDE

Kotlin

Kotlin

4.3.1
JavaKotlin
toString(),equals() hashCoce() Kotlin

Client

class Client(val name: String, val postalCode: Int)

TOSTRING()
KotlinJava

Client@5e9f23b4
toString()

class Client(val name: String, val postalCode: Int) {


override fun toString() = "Client(name=$name, postalCode=$postalCode)"
}

>>> val client1 = Client("Alice", 342562)


>>> println(client1)
Client(name=Alice, postalCode=342562)

equals()

101
4.3

Client

>>> val client1 = Client("Alice", 342562)


>>> val client2 = Client("Alice", 342562)
>>> println(client1 == client2) // 1 Kotlin==
"equals"
false

Client equals

SIDEBAR ==
Java == Java ==
== Java
eauals
Kotlin == equals
equals ==
=== Java ==

Client

class Client(val name: String, val postalCode: Int) {


override fun equals(other: Any?): Boolean { // 1 "Any"java.lang.Object:Kot
lin"Any?"othernull
if (other == null || other !is Client) // 2 otherClient
return false
return name == other.name && // 3
postalCode == other.postalCode
}
override fun toString() = "Client(name=$name, postalCode=$postalCode)"
}

Kotlin is Java instanceof


in 2.4.4 !in !is
is 6
other == null || other !is Client other
!is Client

Kotlin override fun


equals(other: Client) equals

equals

102
4.3

client1 == client2 true


hashCode

HASHCODE()
hashCode eauals

Alice

>>> val processed = setOf(Client("Alice", 342562))


>>> println(processed.contains(Client("Alice", 342562)))
false

Client hashCode hashCode


processed

Client
equals true

hashCode()

class Client(val name: String, val postalCode: Int) {


...
override fun hashCode(): Int = name.hashCode() * 31 + postalCode
}

Kotlin

4.3.3 :

toString,equals hashCode IntelliJ IDEA


IDE
Kotlin data

103
4.3

data class Client(val name: String, val postalCode: Int)

Java

equals()
HashMap hashCode()
toString()

equals hashCode equals()

hashCode()

data
7.4

COPY()

val var
HashMap

Kotlin

copy()

class Client(val name: String, val postalCode: Int) {


...
fun copy(name: String = this.name,
postalCode: Int = this.postalCode) =
Client(name, postalCode)
}

copy()

>>> val bob = Client("Bob", 973293)


>>> println(bob.copy(postalCode = 382555))
Client(name=Bob, postalCode=382555)

104
4.3

data -Kotlin
IDE

4.3.3 by

Kotlin final

IntelliJ IDEAIDE
Collection

class DelegatingCollection<T> : Collection<T> {


private val innerList = arrayListOf<T>()
override val size: Int get() = innerList.size
override fun isEmpty(): Boolean = innerList.isEmpty()
override fun contains(element: T): Boolean = innerList.contains(element)
override fun iterator(): Iterator<T> = innerList.iterator()
override fun containsAll(elements: Collection<T>): Boolean =
innerList.containsAll(elements)
}

Kotlin
by

class DelegatingCollection<T>(
innerList: Collection<T> = ArrayList<T>()
) : Collection<T> by innerList {}

DelegatingCollection

105
4.3

class CountingSet<T>(
val innerSet: MutableCollection<T> = HashSet<T>()
) : MutableCollection<T> by innerSet { // 1 MutableCollectioninnerSet

var objectsAdded = 0

override fun add(element: T): Boolean { // 2


objectsAdded++
return innerSet.add(element)
}

override fun addAll(c: Collection<T>): Boolean {


objectsAdded += c.size
return innerSet.addAll(c)
}
}
>>> val cset = CountingSet<Int>()
>>> cset.addAll(listOf(1, 1, 2))
>>> println("${cset.objectsAdded} objects were added, ${cset.size} remain")
3 objects were added, 2 remain

add addAll MutableCollection



addAll()
add()
API
Kotlin
Kotlin object

106
4.4 object

**

object Kotlin




Java

Kotlin

4.4.1
Java

Kotlin

object Payroll {
val allEmployees = arrayListOf<Person>()

fun calculateSalary() {
for (person in allEmployees) {
...
}
}
}

object

107
4.4 object

Payroll.allEmployees.add(Person(...))
Payroll.calculateSalary()

java.util.Comparator
Comparator
Comparator

object CaseInsensitiveFileComparator : Comparator<File> {


override fun compare(file1: File, file2: File): Int {
return file1.getPath().compareTo(file2.getPath(),
ignoreCase = true)
}
}
>>> println(CaseInsensitiveFileComparator.compare(
... File("/User"), File("/user")))
0

Comparator

>>> val files = listOf(File("/Z"), File("/a"))


>>> println(files.sortedWith(CaseInsensitiveFileComparator))
[/a, /Z]

sortedWith

SIDEBAR




GuiceKotlinJava

108
4.4 object

data class Person(val name: String) {


object NameComparator : Comparator<Person> {
override fun compare(p1: Person, p2: Person): Int =
p1.name.compareTo(p2.name)
}
}
>>> val persons = listOf(Person("Bob"), Person("Alice"))
>>> println(persons.sortedWith(Person.NameComparator))
[Person(name="Alice"), Person(name="Bob")]

SIDEBARJavaKotlin Kotlin
INSTANCE Java
JavaKotlin INSTANCE
/* Java */ CaseInsensitiveFileComparator.INSTANCE.compare(file1, file2);
INSTANCE CaseInsensitiveFileComparator

4.4.2

KotlinJava static Kotlin


KotlinJava
Java

4.5

109
4.4 object

companion

Java

class A {
companion object {
fun bar() {
println("Companion object called")
}
}
}
>>> A.bar()
Companion object called

FacebookUser SubscribingUser
User

class User {
val nickname: String

constructor(email: String) { //
nickname = email.substringBefore('@')
}

constructor(facebookAccountId: Int) { //
nickname = getFacebookName(facebookAccountId)
}
}

User

110
4.4 object

class User(val nickname: String) {


companion object { //

fun newSubscribingUser(email: String) = // email


User(email.substringBefore('@'))

fun newFacebookUser(accountId: Int) = // FacebookID


User(getFacebookName(accountId))
}
}

>>> val subscribingUser = User.newSubscribingUser("bob@gmail.com")


>>> val facebookUser = User.newFacebookUser(4)

>>> println(subscribingUser.nickname)
bob

SubscribingUser FacebookUser

User

4.4.3

web
JSON

111
4.4 object

class Person(val name: String) {


companion object Loader {
fun fromJSON(jsonText: String): Person = ...
}
}
>>> person = Person.Loader.fromJSON("{name: 'Dmitry'}") // fromJSO
N
>>> person.name
Dmitry

>>> person2 = Person.fromJSON("{name: 'Brent'}") // fromJSON


>>> person2.name
Brent

companion object
Loader Companion



Person
JSON JSONFactory
Person

interface JSONFactory<T> {
fun fromJSON(jsonText: String): T
}

class Person(val name: String) {


companion object : JSONFactory<Person> { //
override fun fromJSON(jsonText: String): Person = ...
}
}

Person

fun loadFromJSON<T>(factory: JSONFactory<T>): T {


...
}

loadFromJSON(Person) //

112
4.4 object

Person JSONFactory

SIDEBARKotlin
Java
Companion /* Java */ Person.Companion.fromJSON("...");
Companion
Java @JvmField
static
@JvmField
10 KotlinJava
Java

3.3
Java

C C
fun C.func()
Person

/
Companion

// business logic module


class Person(val firstName: String, val lastName: String) {

companion object { //
}
}

// client/server communication module

fun Person.Companion.fromJSON(json: String): Person { //


...
}
val p = Person.fromJSON(json)

fromJSON


Kotlin object

113
4.4 object

4.4.4
object

anonymous objectsJava
Java----Kotlin

window.addMouseListener(

object : MouseAdapter() { // MouseAdapter


override fun mouseClicked(e: MouseEvent) { // MouseAdapter
// ...
}

override fun mouseEntered(e: MouseEvent) { // MouseAdapter

// ...
}
}
)

val listener = object : MouseAdapter() {


override fun mouseClicked(e: MouseEvent) { ... }
override fun mouseEntered(e: MouseEvent) { ... }
}

JavaKotlin

NOTENote

JavaJava
final

114
4.4 object

fun countClicks(window: Window) {

var clickCount = 0 //

window.addMouseListener(object : MouseAdapter() {
override fun mouseClicked(e: MouseEvent) {
clickCount++ //
}
})
// ...
}

NOTE
Runnable KotlinSAM

5lambdaSAM

Kotlin
lambda

115
4.5

KotlinJava
final public
final open
internal

inner
sealed


field
equals(), hashCode(), toString(), copy(),

Kotlin
Java

KotlinJava

116
5 lambda

lambda


KotlinJava
lambda

Lambda(Lambda expressions)lambda
lambdaKotlin
lambdalambda
lambdalambda
Java--lambda
(receiver)lambda

117
5.1 lambda

``lambdaJava 8
lambdalambdaKotlin

5.1.1 Lambda:

Java

OnClickListener onClick

/* Java */
button.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View view) {
/* actions on click */
}
});

KotlinJava 8
lambda

button.setOnClickListener { /* actions on click */ }

KotlinJava
lambda
lambda

5.1.2 Lambda

118
5.1 lambda

lambda
JavaJava 8
Kotlin
Person

data class Person(val name: String, val age: Int)

lambda
--

fun findTheOldest(people: List<Person>) {

var maxAge = 0 //

var theOldest: Person? = null //


for (person in people) {

if (person.age > maxAge) { //


maxAge = person.age
theOldest = person
}
}
println(theOldest)
}
>>> val people = listOf(Person("Alice", 29), Person("Bob", 31))
>>> findTheOldest(people)
Person(name=Bob, age=31)

Kotlin

>>> val people = listOf(Person("Alice", 29), Person("Bob", 31))


>>> println(people.maxBy { it.age }) //
Person(name=Bob, age=31)

maxBy

{ it.age } lambda
it
Person age lambda

119
5.1 lambda

people.maxBy(Person::age)

JavaJava 8
lambda
lambda

5.1.3 Lambda
lambda

5.1lambda

5.1 Lambda

Kotlinlambda
lambda lambda
:

>>> val sum = { x: Int, y: Int -> x + y }


>>> println(sum(1, 2)) // lambda
3

lambda

>>> { println(42) }()


42

lambda
lambda run :

>>> run { println(42) } // Lambda


42

8.2

120
5.1 lambda

>>> val people = listOf(Person("Alice", 29), Person("Bob", 31))


>>> println(people.maxBy { it.age })
Person(name=Bob, age=31)

people.maxBy({ p: Person -> p.age })

lambda
lambda Person

lambda
Kotlinlambda
lambda

people.maxBy() { p: Person -> p.age }

lambda

people.maxBy { p: Person -> p.age }

lambda

lambda--
lambdalambda

joinToString Kotlin
toString()

>>> val people = listOf(Person("Alice", 29), Person("Bob", 31))


>>> val names = people.joinToString(separator = " ",
... transform = { p: Person -> p.name })
>>> println(names)
Alice Bob

lambda

people.joinToString(" ") { p: Person -> p.name }

121
5.1 lambda

lambda

TIPIntelliJ IDEA
lambda

people.maxBy { p: Person -> p.age } //


people.maxBy { p -> p.age } //

lambda
maxBy Person
maxBy lambda Person
lambda


itlambda

people.maxBy { it.age } // it

NOTE it
lambdalambda
it

lambda

>>> val getAge = { p: Person -> p.age }


>>> people.maxBy(getAge)

lambdalambda

122
5.1 lambda

>>> val sum = { x: Int, y: Int ->


... println("Computing the sum of $x and $y")
... x + y
... }
>>> println(sum(1, 2))
Computing the sum of 1 and 2...
3

lambda

5.1.4

lambda
lambdalambda
forEach
lambda forEach for
lambda

fun printMessagesWithPrefix(messages: Collection<String>, prefix: String) {


messages.forEach { // lambda
println("$prefix $it") // lambda"prefix"
}
}

>>> val errors = listOf("403 Forbidden", "404 Not Found")


>>> printMessagesWithPrefix(errors, "Error:")
Error: 403 Forbidden
Error: 404 Not Found

KotlinJavaKotlin final
lambda

123
5.1 lambda

fun printProblemCounts(responses: Collection<String>) {

var clientErrors = 0 // 1

var serverErrors = 0 // 1
responses.forEach {
if (it.startsWith("4")) {
clientErrors++ // 2
} else if (it.startsWith("5")) {
serverErrors++ // 2
}
}
println("$clientErrors client errors, $serverErrors server errors")
}

>>> val responses = listOf("200 OK", "418 I'm a teapot",


... "500 Internal Server Error")
>>> printProblemCounts(responses)
1 client errors, 1 server errors

// 1 lambda // 2 lambda

JavaKotlinlambda
lambda prefix clientErrors serverErrors
lambda
lambda
lambda

lambda

124
5.1 lambda

SIDEBAR Java

Kotlin

class Ref<T>(var value: T)//


>> val counter = Ref(0)
>> val inc = { counter.value++ } //

Kotlin

var counter = 0
val inc = { counter++ }


valJava
var Ref Ref
lambda

lambda
lambda

fun tryToCountButtonClicks(button: Button): Int {


var clicks = 0
button.onClick { clicks++ }
return clicks
}

onClick clicks
onClick

lambdalambda

5.1.5
lambda
lambda
Java 8
Kotlin ::

125
5.1 lambda

val getAge = Person::age

5.2

lambda

val getAge = { person: Person -> person.age }

lambda

people.maxBy(Person::age)

fun salute() = println("Salute!")


>>> run(::salute) //
Salute!

:: ::salute
run

val action = { person: Person, message: String -> // 1. lambdasendEmail


sendEmail(person, message)
}

val nextAction = ::sendEmail // 2.

126
5.1 lambda

data class Person(val name: String, val age: Int)

>>> val createPerson = ::Person // "Person"


>>> val p = createPerson("Alice", 29)
>>> println(p)
Person("Alice", 29)

fun Person.isAdult() = age >= 21


val predicate = Person::isAdult

isAdult Person
person.isAdult()

SIDEBAR Kotlin 1.0


Kotlin 1.1

>> val p = Person("Dmitry", 34)


>> val personsAgeFunction = Person::age
>> println(personsAgeFunction(p))
34

>> val dmitrysAgeFunction = p::age // 1 Kotlin 1.1


>> println(dmitrysAgeFunction())
34

personsAgeFunction ()
dmitrysAgeFunction ()Kotlin 1.1
{ p.age } p::age

lambda

127
5.2 API

Kotlinfilter
map
Kotlin
lambda

5.2.1 :filtermap
filter map

Person

data class Person(val name: String, val age: Int)

filter

>>> val list = listOf(1, 2, 3, 4)


>>> list.filter { it % 2 == 0 } // 1
[2, 4]

5.3

5.3

30 filter :

>>> val people = listOf(Person("Alice", 29), Person("Bob", 31))


>>> people.filter { it.age > 30 }
[Person("Bob", 31)]

filter map

map

>>> val list = listOf(1, 2, 3, 4)


>>> list.map { it * it }
[1, 4, 9, 16]

128
5.2 API

5.4

5.4 map

map

>>> val people = listOf(Person("Alice", 29), Person("Bob", 31))


>>> people.map { it.name }
[Alice, Bob]

people.map(Person::name)

30

>>> people.filter { it.age > 30 }.map(Person::name)


[Bob]

lambda

people.filter { it.age == people.maxBy(Person::age).age }

100
100

val maxAge = people.maxBy(Person::age).age


people.filter { it.age == maxAge }

lambda

>>> val numbers = mapOf(0 to "zero", 1 to "one")


>>> println(numbers.mapValues { it.value.toUpperCase() })
{0=ZERO, 1=ONE}

129
5.2 API

Kotlin filterKeys mapKeys


filterValues mapValues

5.2.2 all, any, count find :


Kotlin
all any count find
canBeInClub27
27

val canBeInClub27 = { p: Person -> p.age <= 27 }

all

>>> val people = listOf(Person("Alice", 27), Person("Bob", 31))


>>> println(people.all(canBeInClub27))
false

any

>>> println(people.any(canBeInClub27))
true

!all () any

>>> val list = listOf(1, 2, 3)


>>> println(!list.all { it == 3 }) // 1 !"any"

true
>>> println(list.any { it != 3 }) // 2
true

33
any count :

>>> val people = listOf(Person("Alice", 27), Person("Bob", 31))


>>> println(people.count(canBeInClub27))
1

130
5.2 API

SIDEBAR count vs size count


>>> println(people.filter(canBeInClub27).size)
1


count

find

>>> val people = listOf(Person("Alice", 27), Person("Bob", 31))


>>> println(people.find(canBeInClub27))
Person(name=Alice, age=27)

null find firstOrNull


firstOrNull

5.2.3 groupBy :

groupBy

>>> val people = listOf(Person("Alice", 31),


...
Person("Bob", 29), Person("Carol", 31))
>>> println(people.groupBy { it.age })

5.5

5.5 groupBy

131
5.2 API

{29=[Person(name=Bob, age=29)],
31=[Person(name=Alice, age=31), Person(name=Carol, age=31)]}

Map<Int, List<Person>>
mapKeys mapValues

>>> val list = listOf("a", "ab", "b")


>>> println(list.groupBy(String::first))
{a=[a, ab], b=[b]}

first String

5.2.4 flatMapflatten
Book

class Book(val title: String, val authors: List<String>)

books.flatMap { it.authors }.toSet() //

flatMap

5.6

>>> val strings = listOf("abc", "def")


>>> println(strings.flatMap { it.toList() })
[a, b, c, d, e, f]

132
5.2 API

5.6 flatMap

toList() map toList()


flatMap

>>> val books = listOf(Book("Thursday Next", listOf("Jasper Fforde")),


Book("Mort", listOf("Terry Pratchett")),
... Book("Good Omens", listOf("Terry Pratchett",
... "Neal Gaiman")))
>>> println(books.flatMap { it.authors }.toSet())
[Jasper Fforde, Terry Pratchett, Neal Gaiman]

book.authors flatMap
toSet
Terry Pratchett
flatMap
flatten
listOfLists.flatten() Kotlin

133
5.3 :

map filter

people.map(Person::name).filter { it.startsWith("A") }

Kotlin filter map


filter map

people.asSequence() // 1
.map(Person::name) // 2 API
.filter { it.startsWith("A") } // 2
.toList() // 3

A

Kotlin Sequence
Sequence : iterator
Sequence

asSequence

API

NOTE 8.2
Kotlin

5.3.1

134
5.3 :

.7

5.7

>>> listOf(1, 2, 3, 4).asSequence()


... .map { print("map($it) "); it * it }
... .filter { print("filter($it) "); it % 2 == 0 }

map filter

>>> listOf(1, 2, 3, 4).asSequence()


... .map { print("map($it) "); it * it }
... .filter { print("filter($it) "); it % 2 == 0 }
... .toList()
map(1) filter(1) map(2) filter(4) map(3) filter(9) map(4) filter(16)


map
filter map filter


map find

>>> println(listOf(1, 2, 3, 4).asSequence()


.map { it * it }.find { it > 3 })
4

map

5.8

135
5.3 :

5.8

map
3
find() map
find 3

map filter
5.9

>>> val people = listOf(Person("Alice", 29), Person("Bob", 31),


... Person("Charles", 31), Person("Dan", 21))
>>> println(people.asSequence().map(Person::name) // 1 "map"filter
... .filter { it.length < 4 }.toList())
[Bob, Dan]
>>> println(people.asSequence().filter { it.name.length < 4 }
... .map(Person::name).toList()) // 2filtermap
[Bob, Dan]

5.9 filter

map filter

136
5.3 :

SIDEBAR vs Java 8Kotlin


Java 8Java
AndroidKotlinJava 8
KotlinCPU
map() filter() Java

5.3.2
asSequence()
generateSequence()
generateSequence() 100

>>> val naturalNumbers = generateSequence(0) { it + 1 }


>>> val numbersTo100 = naturalNumbers.takeWhile { it <= 100 }

>>> println(numbersTo100.sum()) "sum"


5050

naturalNumbers numbersTo100
( sum )
Java

fun File.isInsideHiddenDirectory() =
generateSequence(this) { it.parentFile }.any { it.isHidden }

>>> val file = File("/Users/svtk/.HiddenDir/a.txt")


>>> println(file.isInsideHiddenDirectory())
true

find any
lambda
Java APIlambda

137
5.4 Java

kotlinKotlinlambdaAPIJava
KotlinKotlinlambdaJava API
Javalambda

button.setOnClickListener { /* actions on click */ } // lambda

Button OnClickListener setOnClickListener

/* Java */
public class Button {
public void setOnClickListener(OnClickListener l) { ... }
}

OnClickListener onClick

/* Java */
public interface OnClickListener {
void onClick(View v);
}

Java 8
setOnClickListener

button.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
...
}
}

Kotlinlambda

button.setOnClickListener { view -> ... }

OnClickListener lambda View onClick


5.10

138
5.4 Java

5.10 lambda

OnClickListener
functional interfacesSAMSAM(single abstract
method)Java API Runnable Callable
KotlinJavalambda
Kotlin

NOTE JavaKotlinlambda
Kotlin
lambdaKotlin8.1.1

lambda

5.4.1 lambdaJava
lambdaJava
lambda

/* Java */
void postponeComputation(int delay, Runnable computation);

Kotlinlambda
Runnable

postponeComputation(1000) { println(42) }

Runnable Runnable
lambda--
run Runnable

139
5.4 Java

postponeComputation(1000, object : Runnable // lambda


{ override fun run() {
println(42)
}
})

lambdalambda

postponeComputation(1000) { println(42) } // `Runnable`

object Runnable

val runnable = Runnable { println(42) } //


fun handleComputation() {
postponeComputation(1000, runnable) // 2 `handleComputation`
}

lambda

Runnable id

fun handleComputation(id: String) // lambdaid


{ postponeComputation(1000) // handleComputationRunnable

{ println(id) }

140
5.4 Java

SIDBARlambda Kotlin1.0lambda
lambdaKotlinJava 8
lambda.class lambda

lambda
HandleComputation$1
lambda

class HandleComputation$1(val id: String) : Runnable


{ override fun run() {
println(id)
}
}
fun handleComputation(id: String) {
postponeComputation(1000, HandleComputation$1(id)) // lambda

}

lambdaJava
Kotlin inline Kotlin
lambda inline
8.2 lambda

5.4.2 SAMlambda

SAMlambda

lambdaSAM

fun createAllDoneRunnable(): Runnable {


return Runnable { println("All done!") }
}

>>> createAllDoneRunnable().run()
All done!

141
5.4 Java

SAMSAM--
lambdalambda
Runnable lambda
SAM
Android Activity.onCreate

val listener = OnClickListener { view ->

val text = when (view.id) { view.id


R.id.button1 -> "First button"
R.id.button2 -> "Second button"
else -> "Unknown button"
}

toast(text) text
}
button1.setOnClickListener(listener)
button2.setOnClickListener(listener)

listener

OnClickListener SAM

SIDEBARlambda/ lambda
this lambbda
lambdalambda this

lambda
this API

SAMlambda
SAM
lambda
lambda

142
5.5 lambda: withapply

Kotlin with apply


11.2.1
Kotlin
Javalambda
lambdalambda(lambdas with receivers)
lambda with

5.5.1 with

Kotlin with
with

fun alphabet(): String {


val result = StringBuilder()
for (letter in 'A'..'Z') {
result.append(letter)
}
result.append("\nNow I know the alphabet!")
return result.toString()
}
>>> println(alphabet())
ABCDEFGHIJKLMNOPQRSTUVWXYZ
Now I know the alphabet!

result
result
with

fun alphabet(): String {


val stringBuilder = StringBuilder()

return with(stringBuilder) { // 1
for (letter in 'A'..'Z') {
this.append(letter) // 2 this
}

append("\nNow I know the alphabet!") // 3 this

this.toString() // 4lambda
}
}

143
5.5 lambda: withapply

144
5.6

lambda
Kotlinlambda it lambda

lambda
::
lambda
filter,map,all,any

lambdaJava
SAM
lambda
lambda
with
apply API

145
6 Kotlin

146
7

147
8 : lambda

148
9

149
10

150
11 DSL

151
A: Kotlin

152
B: Kotlin

153
C: Kotlin

154