Upgrade to Pro — share decks privately, control downloads, hide ads and more …

[GDG] Kotlin and why you should love it

[GDG] Kotlin and why you should love it

Slides of the talk I gave at GDG Turin on the 7/7/2017

Roberto Orgiu

July 04, 2017
Tweet

More Decks by Roberto Orgiu

Other Decks in Technology

Transcript

  1. WHAT IS KOTLIN? > Compatible with JVM (and moar) >

    Made by Jetbrains > More expressive > Safer > Functional > Uses Extension Functions @_tiwiz
  2. NULLABLE VS NONNULL > They are different types > Compile

    time error if you assign null to a non null variable > No more NullPointerException ! @_tiwiz
  3. NULLABLE VS NONNULL > val name: String = null ❌

    > val name: String = "Roberto" ✔ > val name: String? = null ✔ @_tiwiz
  4. NULLABLE VS NONNULL (INTEROPERABILITY) > Calling Java from Kotlin ➡

    Nullable > Unless it's annotated with @NonNull / @NotNull @_tiwiz
  5. SMART CAST void function(Object something) { if(something instanceof String) {

    String s = (String) something; println(s.substring(0, 3)) } } @_tiwiz
  6. SMART CAST fun function(something: Any) { if(something is String) {

    println(something.substring(0, 3)) } } @_tiwiz
  7. DECLARING A CLASS class Person (name : String, surname :

    String?) { init { //code common to every constructor } } @_tiwiz
  8. DECLARING A CLASS class Person (name : String, surname :

    String?) { constructor(name: String){ this(name, null) } init { //code common to every constructor } } @_tiwiz
  9. DECLARING A CLASS class Person (name : String, surname :

    String? = null) { init { //code common to every constructor } } @_tiwiz
  10. CREATING AN INSTANCE > val p = Person("Pippo") > val

    p2 = Person("Pippo", "Goofy") @_tiwiz
  11. CALLING A METHOD ON A NULLABLE TYPE val p =

    Person("Pippo") val fifthCharOfSurname: Char? = p.surname?.charAt(4) //this is nullable type fifthCharOfSurname?.doSomething() //executed only if not null @_tiwiz
  12. NULLABLE TYPES IN JAVA Person p = new Person("Pippo", null);

    String surname = p.getSurname(); if (surname != null) { Char fifthCharOfSurname = surname.charAt(4); if (fifthChar != null) { fifthCharOfSurname.doSomething(); } } @_tiwiz
  13. STRING TEMPLATES val s1 = "Hello, $who" val s2 =

    "Hello, ${person.name}" @_tiwiz
  14. VARIABLES > No implicit conversion: everything must be converted >

    Chars are not Ints, but we can convert them > Bitwise: | is or, & is and > Type can be inferred > Strings can be accessed as arrays @_tiwiz
  15. VARIABLES val a = 42 a = 43 // No

    can do! var b = "hello" b = "ciao" // Yeah can do var c : Context = this @_tiwiz
  16. VARIABLES class Person { var name : String = ""

    get() = field.toUppercase() set(value) { field = "Name: $value" } } @_tiwiz
  17. when val type = when(fido) { is Dog -> "Dog"

    is Cat -> "Cat" else -> error("I only know about dogs and cats") } @_tiwiz
  18. EXTENSION METHODS and how they are converted in Java static

    void bark(Dog dog) { ... } ExtensionKt.bark(pluto) ExtensionKt.bark(fido) @_tiwiz
  19. INLINE FUNCTIONS they will be substituted by their code during

    compilation, instead of doing the real call to a function. inline fun <T> with(t: T, body: T.() -> Unit) { t.body() } @_tiwiz
  20. HOW TO MAKE AN INLINE FUNCTION inline fun ifIsLollipop(code :

    () -> Unit) { if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { code() } } @_tiwiz
  21. LAMBDAS WITH RECEIVERS The ability to call methods of a

    different object in the body of a lambda without any additional qualifiers — Kotlin in Action @_tiwiz
  22. with fun alphabet(): String { val result = StringBuilder() for

    (letter in 'A'..'Z') { result.append(letter) } result.append("\nNow I know the alphabet!") return result.toString() } @_tiwiz
  23. with fun alphabet(): String { val stringBuilder = StringBuilder() return

    with(stringBuilder) { for (letter in 'A'..'Z') { this.append(letter) } append("\nNow I know the alphabet!") this.toString() } } @_tiwiz
  24. with fun alphabet() = with(StringBuilder()) { for (letter in 'A'..'Z')

    { append(letter) } append("\nNow I know the alphabet!") toString() } @_tiwiz
  25. apply fun alphabet() = StringBuilder().apply { for (letter in 'A'..'Z')

    { append(letter) } append("\nNow I know the alphabet!") }.toString() @_tiwiz
  26. with VS apply Declaration Return type with Function value of

    the lambda apply Extension method this @_tiwiz
  27. with VS apply inline fun <T, R> with(receiver: T, block:

    T.() -> R): R = receiver.block() inline fun <T> T.apply(block: T.() -> Unit): T { block() return this } @_tiwiz
  28. let VS run inline fun <T, R> T.run(block: T.() ->

    R): R = block() inline fun <T, R> T.let(block: (T) -> R): R = block(this) @_tiwiz
  29. DESTRUCTURING DECLARATION val mickey = Person("Mickey", "Mouse") val (name, lastName)

    = mickey MEANS val name = mickey.component1() val lastName = mickey.component2() @_tiwiz
  30. LOCAL FUNCTIONS Functions can be nested inside a containing function

    And they have access to all parameters and variables of the enclosing function @_tiwiz
  31. LOCAL FUNCTIONS fun containing(a : Int) { fun nested() {

    return a + 2 } val b = nested() } @_tiwiz
  32. SEALED CLASSES sealed class Expr data class Const(val number: Double)

    : Expr() data class Sum(val e1: Expr, val e2: Expr) : Expr() object NotANumber : Expr() @_tiwiz
  33. SEALED CLASSES fun eval(expr: Expr): Double = when(expr) { is

    Const -> expr.number is Sum -> eval(expr.e1) + eval(expr.e2) NotANumber -> Double.NaN } @_tiwiz
  34. COMPANION object class MyClass { companion object Factory { fun

    create(): MyClass = MyClass() } } val instance = MyClass.create() @_tiwiz
  35. object init > object declarations are initialized lazily, when accessed

    for the first time > object expressions are executed (and initialized) immediately, where they are used > a companion object is initialized when the corresponding class is loaded (resolved), matching the semantics of a Java static initializer @_tiwiz
  36. interface Base { fun print() } class BaseImpl(val x: Int)

    : Base { override fun print() { print(x) } } @_tiwiz
  37. class Derived(b: Base) : Base by b { override fun

    print() { print("abc") } } @_tiwiz
  38. lazy - THIS... val lazyValue: String by lazy { println("computed!")

    "Hello" } println(lazyValue) println(lazyValue) @_tiwiz
  39. Delegates.observable() - THIS ... class User { var name: String

    by Delegates.observable("<no name>") { prop, old, new -> println("$old -> $new") } } fun main(args: Array<String>) { val user = User() user.name = "first" user.name = "second" } @_tiwiz
  40. map DELEGATE class User(map: Map<String, Any?>) { val name: String

    by map val age: Int by map } val user = User(mapOf( "name" to "John Doe", "age" to 25 )) @_tiwiz
  41. COLLECTIONS: MUTABLE VS IMMUTABLE val list = listOf(1, 2, 3)

    //immutable list of ints val list = mutableListOf(1, 2, 3) //mutable list of ints @_tiwiz
  42. COLLECTIONS: MUTABLE VS IMMUTABLE > Mutable: you can insert, update

    and remove > Default: you can only query (contains, get, indexOf...) > MutableList / List > MutableSet / Set > MutableMap / Map @_tiwiz
  43. COLLECTIONS: IMMUTABILITY val list = listOf(1, 2, 3) val doubles

    = list.map { it * 2 } val pairs = list.filter { it % 2 == 0 } > doubles is a completely new list > The original list is never touched @_tiwiz
  44. SUGGESTED READ KOTLIN IN ACTION by Dmitry Jemerov & Svetlana

    Isakova manning.com/books/kotlin-in- action @_tiwiz