You can do better with Kotlin...Android Studio is based on IntelliJ IDEA just another library for...

Preview:

Citation preview

Svetlana Isakova

You can do better with Kotlin

- modern - pragmatic - Android-friendly

Kotlin Programming Language

Official on Android

Not only Android

Pragmatic

- tooling - Java interop

From

has good tooling

- completion - navigation - refactorings - inspections

can be easily mixed with Java code

*.java

*.class

*.dex

compiled to Java bytecode

*.kt

Kotlin code

Java code

You can have Java & Kotlin code in one project

You can gradually add Kotlin to your existing app

Android-friendly

Android Studio is based on IntelliJ IDEA

just another library for your app

rxjava-2.1.2

kotlin-stdlib-1.1.4 6315

10212

No Kotlin SDK…just JDK + extensions

small runtime jar easy Java interop

Modern

- concise - safe - expressive

concise

public class Person { private final String name; private final int age; public Person(String name, int age) { this.name = name; this.age = age; } public String getName() { return name; } public int getAge() { return age; }}

- equals - hashCode - toString

data

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

public class Person { private final String name; private final int age; public Person(String name, int age) { this.name = name; this.age = age; } public String getName() { return name; } public int getAge() { return age; }}

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

person.nameperson.getName()

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

person.getName()

public class Person { private final String name; private final int age; public Person(String name, int age) { this.name = name; this.age = age; } public String getName() { return name; } public int getAge() { return age; }}

person.name

public void updateWeather(int degrees) { String description; Colour colour; if (degrees < 5) { description = "cold"; colour = BLUE; } else if (degrees < 23) { description = "mild"; colour = ORANGE; } else { description = "hot"; colour = RED; } // ...}

enum Colour { BLUE, ORANGE, RED, /*...*/; }

fun updateWeather(degrees: Int) { val description: String val colour: Colour if (degrees < 5) { description = "cold" colour = BLUE } else if (degrees < 23) { description = "mild" colour = ORANGE } else { description = "hot" colour = RED } // ...}

fun updateWeather(degrees: Int) { val (description: String, colour: Colour) = if (degrees < 5) { Pair("cold", BLUE) } else if (degrees < 23) { Pair("mild", ORANGE) } else { Pair("hot", RED) } // ...}

fun updateWeather(degrees: Int) { val (description, colour) = if (degrees < 5) { Pair("cold", BLUE) } else if (degrees < 23) { Pair("mild", ORANGE) } else { Pair("hot", RED) } // ...}

fun updateWeather(degrees: Int) { val (description, colour) = when { degrees < 5 -> Pair("cold", BLUE) degrees < 23 -> Pair("mild", ORANGE) else -> Pair("hot", RED) } // ...}

fun updateWeather(degrees: Int) { val (description, colour) = when { degrees < 5 -> "cold" to BLUE degrees < 23 -> "mild" to ORANGE else -> "hot" to RED } }

val (description, colour) = when { degrees < 5 -> "cold" to BLUE degrees < 23 -> "mild" to ORANGE else -> "hot" to RED}

String description;Colour colour; if (degrees < 5) { description = "cold"; colour = BLUE; } else if (degrees < 23) { description = "mild"; colour = ORANGE; } else { description = "hot"; colour = RED; }

safe

Billion Dollar Mistake

Modern approach: to make NPE

compile-time error, not run-time error

Nullable types in Kotlinval s1: String = "always not null" val s2: String? = null

s1.length ✓

✗s2.length

"can be null or non-null"

null ✗

val s: String?

if (s != null) { s.length}

Dealing with Nullable Types

s?.length

val s: String?

Dealing with Nullable Types

val length = if (s != null) s.length else null

val s: String?

Nullability operators

val length = s?.length

val length = if (s != null) s.length else 0

val s: String?

Nullability operators

val length = s?.length ?: 0

val s: String?

if (s == null) fail() s.length

Control-flow analysis

val s: String?

Making NPE explicit

s!!throws NPE if s is null

s!!.length

Nullable Types Under the Hood

No performance overhead

@Nullable, @NotNull annotations

class Optional<T>(val value: T) { fun isPresent() = value != null fun get() = value ?: throw NoSuchElementException("No value present") }

Nullable types ≠ Optional

Annotate your Java types in Kotlin

Type behaves like regular Java type

@Nullable

@NotNull Type

Type?

Type

Type

@ParametersAreNonnullByDefault

@MyNonnullApiType/Type?

expressive

you can avoid any repetition

you can make the code look nicer

you can create API looking like DSL

expressive

Kotlin Coroutines

Kotlin Coroutines

• the key new feature in Kotlin 1.1 • simplify asynchronous programming

Coroutine

a main routine and a subroutine vs coroutines, which call on each other

• the term from 1960s • was used in “The Art of Computer Programming”

by Donald Knuth

Motivation: async/await

Motivationtime consuming

operation

val image = loadImage(url) setImage(image)

Solution 1: callbacks

loadImageAsync().whenComplete { image -> runOnUiThread { setImage(image) } }

Solution 2: async/await

async(UI) { val image = loadImageAsync(url).await() setImage(image) }

val image = loadImageAsync(url).await() setImage(image)

val image = loadImage(url) setImage(image)

No callbacks!

C# wayasync Task ProcessImage(String url) { var image = await LoadImage(url); SetImage(image); }

Kotlin wayfun processImage() = async { val image = loadImageAsync().await() setImage(image) }

coroutines

async/await

Language

Library

async/await - functions defined in the standard library

Threads & Coroutines

Coroutine is similar to a thread

Thread:• a sequence of instructionsMultiple threads:• can be executed concurrently• share resources such as memory

Coroutine:

coroutines:

Coroutine = “lightweight thread”

Thread

Coroutine

Coroutine

computation that can be suspended

computationthread

Coroutine

computation that can be suspended

Why suspend?

Asynchronous computations:

how?

New thread for every computation

simple & straightforward, but too expensive

Executor

• fixed number of threads

• adding tasks • but: difficult to manage

dependencies

Example: waiting for two asynchronous computations to complete

thenCombine / zip

CompletableFutures / RxJava: managing dependencies

the rest of computation in a callback

Stepping back: what’s wrong with blocking thread?

idle

too expensive

Stepping back: what’s wrong with blocking UI thread?

blocked

user is blocked

UI

1

2

3

• computation that can be suspended

• thread is not blocked!

Coroutines

1

2

3

• computation that can be suspended

• thread is not blocked!

UI

UI

UI

Coroutines

suspend functioncomputation that can be suspended

fun loadImageAsync() = async { /* do the work */ }

fun processImage() = async { val image = loadImageAsync().await() setImage(image) }

Back to image example

async starts new computationfun loadImageAsync() = async { /* do the work */ }

loadImageAsync

suspending callfun processImage() = async {

val image = loadImageAsync().await() setImage(image) }

await suspends computation

fun loadImageAsync(): Deferred<Image> = async { /* do the work */ }

interface Deferred<out T> { suspend fun await(): T }

await is a suspend function

await suspends computationfun processImage() = async {

val image = loadImageAsync().await() setImage(image) }

fun processImage() = async { val deferred = loadImageAsync() val image = deferred.await() setImage(image) }

await suspends computation

await suspends computation

processImage

loadImageAsync

1

fun processImage() = async { val deferred = loadImageAsync() val image = deferred.await() setImage(image) }

await suspends computation

processImage

loadImageAsync

1loadImageAsync

processImage

2

await

fun processImage() = async { val deferred = loadImageAsync() val image = deferred.await() setImage(image) }

await suspends computation

loadImageAsync

processImage

2

loadImageAsync

processImage

3

…and continues it when result is ready

fun processImage() = async { val deferred = loadImageAsync() val image = deferred.await() setImage(image) }

await suspends computation

loadImageAsync

processImage

2

loadImageAsync

processImage

3

…and continues it when result is ready

On which thread?

Q: On which thread can the coroutine be continued?A: You specify that.

Continue in any thread from thread pool

async(CommonPool) { ...}

1

2

3 3

Continue in the UI thread1

2

3

async(UI) { ... }

UI

UI

UI

Custom executor

async(CustomContext) { ...}

You can launch coroutine in the custom executor

1 2 3

fun overlay(first: Image, second: Image): Image

fun overlayAsync() = async(CommonPool) { val first = loadImageAsync("green") val second = loadImageAsync("red") overlay(first.await(), second.await())}

Two asynchronous computations

overlayAsync

overlayAsync

overlayAsync

Programming with suspend functions

Q: Can I define my custom suspend functions?A: Yes.

Example: simple consecutive logicfun login(credentials: Credentials): UserID fun loadUserData(userID: UserID): UserData fun showData(data: UserData)

fun showUserInfo(cred: Credentials) { val userID = login(credentials) val userData = loadUserData(userID) showData(userData) }

Rewrite with async/awaitfun login(credentials: Credentials): Deferred<UserID> fun loadUserData(userID: UserID): Deferred<UserData> fun showData(data: UserData)

fun showUserInfo(credentials: Credentials) = async(CommonPool) { val userID = login(credentials).await() val userData = loadUserData(userID).await() showData(userData) }

Rewrite with suspend functionssuspend fun login(credentials: Credentials): UserID suspend fun loadUserData(userID: UserID): UserData fun showData(data: UserData)

suspend fun showUserInfo(credentials: Credentials) { val userID = login(credentials) val userData = loadUserData(userID) showData(userData) }

RxJava / CompletableFuture vs

Coroutines

Rewrite with CompletableFuturefun loginAsync(credentials: Credentials): CompletableFuture<UserID> fun loadUserDataAsync(userID: UserID): CompletableFuture<UserData> fun showData(data: UserData)

fun showUserInfo(credentials: Credentials) { loginAsync(credentials) .thenCompose { loadUserDataAsync(it) } .thenAccept { showData(it) } }

Rewrite with RxJavafun login(credentials: Credentials): Single<UserID> fun loadUserData(userID: UserID): Single<UserData> fun showData(data: UserData)

fun showUserInfo(credentials: Credentials) { login(credentials) .flatMap { loadUserData(it) } .doOnSuccess { showData(it) } .subscribe() }

“Observables are great, but in many cases they’re kind of overkill.”

somewhere on the Internet

Kotlincoroutines

Reactive Streams

RxJava & coroutines

coroutines

async/await

Language

Library

channels

actors

kotlinx.coroutines

yield

Experimental status of Coroutines

• We want the community to try it! • Migration aids will be provided • Old code will continue to work

via the support library

kotlinx.coroutines

• https://github.com/Kotlin/kotlinx.coroutines/

• Guide to kotlinx.coroutines by example

• by Roman Elizarov (@relizarov)

kotlinlang.org

Gradle & Kotlin

Writing Gradle build scripts and plugins in Kotlin

try.kotlinlang.org

Kotlin Koans

• Basics ◦ j2k converter ◦ functions, variables ◦ control structures (if, when, for, while) ◦ try/catch & exceptions

• Object-oriented programming ◦ classes, interfaces ◦ data classes ◦ objects ◦ class objects ◦ class delegation ◦ extension functions

• Functional programming ◦ lambdas ◦ working with collections in a functional style (filter, map, etc.) ◦ inlining ◦ difference between collections & sequences ◦ anonymous functions (return in lambda vs return in anonymous function)

• Nullability ◦ nullable types ◦ special operators (?., ?:, !!) ◦ let function ◦ lateinit modifier

• Java interoperability ◦ Kotlin type hierarchy (Nothing, Any?, etc.) ◦ correspondence between Kotlin and Java types ◦ platform types for nullability (Int!) ◦ collections hierarchy (read-only / mutable list vs java.util.List) ◦ platform types for collections ((Mutable)List<Int!>) ◦ annotations (@JvmName, @JvmOverloads, @Throws, @JvmStatic)

• Asynchronous programming ◦ async/await ◦ coroutines & suspend functions

• Building DSLs ◦ lambdas with receiver ◦ with, apply, run functions ◦ builders pattern (HTML builders)

• Conventions ◦ operator overloading (a + b, a < b) ◦ others (e in set, map[key], first..last, val (a, b) = pair) ◦ delegated properties (val prop by lazy { ... })

• Generics ◦ reified type parameters ◦ basic intro to covariance / contravariance

1. The Kotlin code is compiled to:

a) Java source code

b) Java byte code

2. Does the following code compile? If not, w

hat’s the error?

var

strin

g = 1

str

ing =

"a"

3. Does the following code compile? If not, w

hat’s the error?

val

langu

ages =

listO

f("Jav

a")

lan

guages

.add("

Kotlin

")

4. What will be printed?

_____

______

_____

p

rintln

(listO

f('a',

'b',

'c').j

oinToS

tring(

separ

ator =

"", p

refix

= "(",

postf

ix = "

)"))

5. What will be printed (a or b)?

f

un foo

(): St

ring {

pri

ntln("

Calcul

ating

foo...

")

ret

urn "f

oo"

}

f

un mai

n(args

: Arra

y<Stri

ng>) {

pri

ntln("

First

${foo(

)}, se

cond $

{foo()

}")

}

a)

Calcul

ating

foo...

First

foo, s

econd

foo

b)

Calcul

ating

foo...

Calcul

ating

foo...

First

foo, s

econd

foo

6. What will be printed?

pri

ntln("

Kotlin

" in "

Java".

."Scal

a")

_

______

______

___

pri

ntln("

Kotlin

" in s

etOf("

Java",

"Scal

a")) _

______

______

___

7. Rewrite the following Java code into Kotlin:

for

(char

c = '

0'; c

< '9';

c++)

{

Sy

stem.o

ut.pri

nt(c);

}

___________________________________________

___________________________________________

___________________________________________

Workshop tomorrow

Have a nice Kotlin!

Recommended