Upload
others
View
34
Download
0
Embed Size (px)
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
Annotate your Java types in KotlinType behaves like
regular Java type
@Nullable
@NotNull Type
Type?
Type
Type
@ParametersAreNonnullByDefault
@MyNonnullApiType/Type?
class Optional<T>(val value: T) { fun isPresent() = value != null fun get() = value ?: throw NoSuchElementException("No value present") }
Nullable types ≠ Optional
expressive
you can avoid any repetition
you can make the code look nicer
you can create API looking like DSL
expressive
Extension Functions
fun String.lastChar() = get(length - 1)
this can be omitted
Extension Functionsfun String.lastChar() = this.get(this.length - 1)
import com.example.util.lastCharimport com.example.util.*
Extension Functions
val c: Char = "abc".lastChar()
fun String.lastChar() = get(length - 1)
fun String.lastChar() = get(length - 1)
Calling Extension Functions from Java code
StringExtensions.kt
char c = StringExtensionsKt.lastChar("abc");JavaClass.java
import static StringExtensionsKt.lastChar; char c = lastChar("abc");
No. Because it’s a regular static method under the hood.
fun String.lastChar() = get(length - 1)
Extension Functions
Is it possible to call a private member of String here?
Extensions for Android Toast.makeText(this, "Thank you!”, Toast.LENGTH_SHORT).show()
Activity
extension function on Activity
toast("Thank you!")
this.toast("Thank you!")
this.startActivity<NewActivity>(“ANSWER" to 42)
val intent = Intent(this, NewActivity::class.java) intent.putExtra("ANSWER", 42) startActivity(intent)
Extensions for Android
infix fun <A, B> A.to(that: B) = Pair(this, that)
"ANSWER".to(42)
"hot" to RED
mapOf(0 to "zero", 1 to "one")
The to extension function
Lambdas
Lambdas
button.addActionListener { println("Hi") }
{ employee: Employee -> employee.city == City.PRAGUE }
What’s an average age of employees
working in Prague?
Working with collections with Lambdasval employees: List<Employee>
employees.filter { it.city == City.PRAGUE }.map { it.age }.average()
data class Employee( val city: City, val age: Int )
What’s an average age of employees
working in Prague?
Working with collections with Lambdasval employees: List<Employee>
data class Employee( val city: City, val age: Int )
extension functions
employees.filter { it.city == City.PRAGUE }.map { it.age }.average()
Kotlin library: extensions on collections
• filter • map • reduce
• count • find • any
• flatMap • groupBy • …
Under the Hood
No performance overheadLambdas can be inlined
Extension Function & Lambda
Lambda with receiver
val sb = StringBuilder()with (sb) { appendln("Alphabet: ") for (c in 'a'..'z') { append(c) } toString()}
The with function
with is a function
val sb = StringBuilder()sb.appendln("Alphabet: ") for (c in 'a'..'z') { sb.append(c)} sb.toString()
lambda is its
second argument
val sb = StringBuilder()with (sb) { this.appendln(“Alphabet: ") for (c in 'a'..'z') { this.append(c) } this.toString()}
val sb = StringBuilder()with (sb, { -> this.appendln(“Alphabet: ") for (c in 'a'..'z') { this.append(c) } this.toString()})
lambda is its
second argument
Lambda with receiverwith is a function
this is an implicit receiver
in the lambda
val sb = StringBuilder()with (sb) { appendln("Alphabet: ") for (c in 'a'..'z') { append(c) } toString()}
this can be omitted
with (sb) { appendln("Alphabet: ") ...}
inline fun <T, R> with( receiver: T, block: T.() -> R ): R = receiver.block()
The with function declaration
Lambda with receiver
val sb = StringBuilder()with (sb) { appendln("Alphabet: ") for (c in 'a'..'z') { this.append(c) }}
lambda with implicit this
html { table { for (product in products) { tr { td { text(product.description) } td { text(product.price) } td { text(product.popularity) } } } } }
HTML Builderslambdas with receiver
val db: SQLiteDatabase = … db.beginTransaction()try { db.delete("users", "first_name = ?", arrayOf("Jake")) db.setTransactionSuccessful()} finally { db.endTransaction()}
db.inTransaction { delete("users", "first_name = ?", arrayOf("Jake"))}
Avoiding Duplication
db.beginTransaction()try { db.delete("users", "first_name = ?", arrayOf("Jake")) db.setTransactionSuccessful()} finally { db.endTransaction()}
db.inTransaction { delete("users", "first_name = ?", arrayOf("Jake"))}
Inline functionsis declared as
inline function
generated bytecode is similar to
ANKO-DSLDSL for dynamic layouts
Alertsfun Activity.showAreYouSureAlert(process: () -> Unit) { alert(title = "Are you sure?", message = "Are you really sure?") { positiveButton("Yes") { process() } negativeButton("No") { } }.show()}
Are you sure?
Are you really sure?
No Yes
customView { verticalLayout { val email = editText { hint = "Email" } val password = editText { hint = "Password" transformationMethod = PasswordTransformationMethod.getInstance() } positiveButton("Log In") { logIn(email.text, password.text) } }}
Password
Log In
Custom layouts
kotlinlang.org
Gradle & Kotlin
Writing Gradle build scripts and plugins in Kotlin
try.kotlinlang.org
Kotlin Koans
Have a nice Kotlin!