you can do better with kotlin - yow! conferences€¦ · you can do better with kotlin-modern...

Post on 31-May-2020

30 Views

Category:

Documents

0 Downloads

Preview:

Click to see full reader

TRANSCRIPT

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

Email

Custom layouts

kotlinlang.org

Gradle & Kotlin

Writing Gradle build scripts and plugins in Kotlin

try.kotlinlang.org

Kotlin Koans

Have a nice Kotlin!

top related