You can do better with Kotlin...Android Studio is based on IntelliJ IDEA just another library for...
Transcript of You can do better with Kotlin...Android Studio is based on IntelliJ IDEA just another library for...
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!