Svetlana Isakova
You can do better with Kotlin Svetlana Isakova Kotlin Programming - - PowerPoint PPT Presentation
You can do better with Kotlin Svetlana Isakova Kotlin Programming - - PowerPoint PPT Presentation
You can do better with Kotlin Svetlana Isakova Kotlin Programming Language - modern - pragmatic - Android-friendly Official on Android Not only Android Pragmatic - tooling - Java interop From has good tooling - completion - navigation -
- 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.name person.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 Kotlin
val 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 @MyNonnullApi
Type/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
Motivation
time consuming
- peration
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# way
async Task ProcessImage(String url) { var image = await LoadImage(url); SetImage(image); }
Kotlin way
fun 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 instructions
Multiple threads:
- can be executed concurrently
- share resources such as memory
Coroutine: coroutines:
Coroutine = “lightweight thread”
Thread Coroutine
Coroutine
computation that can be suspended
computation thread
Coroutine
computation that can be suspended
Why suspend?
Asynchronous computations: how?
New thread for every computation
simple & straightforward, but too expensive
Executor
- fixed number
- f 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 function computation 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 computation
fun loadImageAsync() = async { /* do the work */ }
loadImageAsync
suspending call
fun 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 computation
fun 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
1
loadImageAsync 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 thread
1 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")
- verlay(first.await(), second.await())
}
Two asynchronous computations
- verlayAsync
- verlayAsync
- verlayAsync
Programming with suspend functions
Q: Can I define my custom suspend functions? A: Yes.
Example: simple consecutive logic
fun 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/await
fun 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 functions
suspend 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 CompletableFuture
fun 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 RxJava
fun 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
Kotlin coroutines 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 . T h e K
- t
l i n c
- d
e i s c
- m
p i l e d t
- :
a ) J a v a s
- u
r c e c
- d
e b ) J a v a b y t e c
- d
e 2 . D
- e
s t h e f
- l
l
- w
i n g c
- d
e c
- m
p i l e ? I f n
- t
, w h a t ’ s t h e e r r
- r
? v a r s t r i n g = 1 s t r i n g = " a " 3 . D
- e
s t h e f
- l
l
- w
i n g c
- d
e c
- m
p i l e ? I f n
- t
, w h a t ’ s t h e e r r
- r
? v a l l a n g u a g e s = l i s t O f ( " J a v a " ) l a n g u a g e s . a d d ( " K
- t
l i n " ) 4 . W h a t w i l l b e p r i n t e d ? _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ p r i n t l n ( l i s t O f ( ' a ' , ' b ' , ' c ' ) . j
- i
n T
- S
t r i n g ( s e p a r a t
- r
= " " , p r e f i x = " ( " , p
- s
t f i x = " ) " ) ) 5 . W h a t w i l l b e p r i n t e d ( a
- r
b ) ? f u n f
- (
) : S t r i n g { p r i n t l n ( " C a l c u l a t i n g f
- .
. . " ) r e t u r n " f
- "
} f u n m a i n ( a r g s : A r r a y < S t r i n g > ) { p r i n t l n ( " F i r s t $ { f
- (
) } , s e c
- n
d $ { f
- (
) } " ) } C a l c u l a t i n g f
- .
. . F i r s t f
- ,
s e c
- n
d f
- C
a l c u l a t i n g f
- .
. . C a l c u l a t i n g f
- .
. . F i r s t f
- ,
s e c
- n
d f
- "
S c a l a " ) _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ " S c a l a " ) ) _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
___________________________________________ ____________________________