View
11
Download
0
Category
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)
Gradle & Kotlin
Writing Gradle build scripts and plugins in Kotlin
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