[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

6923bdeb363961b064d2cdb6329982d6?s=128

Roberto Orgiu

July 04, 2017
Tweet

Transcript

  1. KOTLIN AND WHY YOU SHOULD LOVE IT @_tiwiz

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

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

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

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

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

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

    println(something.substring(0, 3)) } } @_tiwiz
  8. if you need explicit casting... pluto as Dog @_tiwiz

  9. DECLARING A CLASS class Person { ... } @_tiwiz

  10. DECLARING A CLASS class Person (name : String, surname :

    String?) @_tiwiz
  11. DECLARING A CLASS class Person (name : String, surname :

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

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

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

    p2 = Person("Pippo", "Goofy") @_tiwiz
  15. 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
  16. 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
  17. INHERITANCE class Person (name : String, surname : String) :

    Animal (name) { ... } @_tiwiz
  18. INTERFACES interface OnClickListener { fun onClick(v : View) } @_tiwiz

  19. INTERFACES AND DEFAULT METHODS interface OnClickListener { fun onClick(v :

    View) = println("I've been clicked") } @_tiwiz
  20. FUNCTIONS fun onCreate(savedInstanceState: Bundle?) { ... } @_tiwiz

  21. FUNCTIONS fun add(x : Int, y : Int) : Int

    { return x + y } @_tiwiz
  22. FUNCTIONS fun add(x : Int, y : Int) : Int

    = x + y @_tiwiz
  23. FUNCTIONS fun add(x : Int, y : Int) = x

    + y @_tiwiz
  24. FUNCTIONS fun add(x : Int = 1, y : Int

    = 2) = x + y @_tiwiz
  25. STRING TEMPLATES val s1 = "Hello, $who" val s2 =

    "Hello, ${person.name}" @_tiwiz
  26. 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
  27. VARIABLES IMMUTABLE VS MUTABLE @_tiwiz

  28. VARIABLES val VS var @_tiwiz

  29. VARIABLES val a = 42 a = 43 // No

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

    get() = field.toUppercase() set(value) { field = "Name: $value" } } @_tiwiz
  31. CONTROL FLOW @_tiwiz

  32. everything returns something @_tiwiz

  33. if val max = if (a > b) a else

    b @_tiwiz
  34. fun resultBasedOnCondition(condition: Boolean) { return if (condition) "A" else "B"

    } @_tiwiz
  35. when val type = when(fido) { is Dog -> "Dog"

    is Cat -> "Cat" else -> error("I only know about dogs and cats") } @_tiwiz
  36. DATA CLASSES data class Person (val name : String, val

    lastName : String) @_tiwiz
  37. DATA CLASSES GIVE US > equals() > hashCode() > copy()

    @_tiwiz
  38. EXTENSION METHODS //file Extension.kt fun Dog.bark() { ... } pluto.bark()

    fido.bark() @_tiwiz
  39. EXTENSION METHODS and how they are converted in Java static

    void bark(Dog dog) { ... } ExtensionKt.bark(pluto) ExtensionKt.bark(fido) @_tiwiz
  40. EXTENSION METHODS CAN BE DECLARED AS LOCAL FUNCTIONS @_tiwiz

  41. LAMBDAS @_tiwiz

  42. LAMBDAS ANONYMOUS FUNCTIONS FOR EVERYONE @_tiwiz

  43. JAVA view.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) {

    doSomething(); } }); @_tiwiz
  44. KOTLIN view.setOnClickListener(object : OnClickListener() { override fun onClick(v : View)

    { doSomething() } }) @_tiwiz
  45. KOTLIN WITH LAMBDAS view.setOnClickListener({ view -> doSomething() }) @_tiwiz

  46. KOTLIN WITH LAMBDAS view.setOnClickListener({ doSomething() }) @_tiwiz

  47. KOTLIN WITH LAMBDAS view.setOnClickListener() { doSomething() } @_tiwiz

  48. KOTLIN WITH LAMBDAS view.setOnClickListener { doSomething() } @_tiwiz

  49. INLINE FUNCTIONS @_tiwiz

  50. 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
  51. HOW TO MAKE AN INLINE FUNCTION inline fun ifIsLollipop(code :

    () -> Unit) { if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { code() } } @_tiwiz
  52. THEN ifIsLollipop { window.setStatusBarColor(Color.BLACK) } @_tiwiz

  53. 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
  54. 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
  55. 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
  56. with fun alphabet() = with(StringBuilder()) { for (letter in 'A'..'Z')

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

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

    the lambda apply Extension method this @_tiwiz
  59. 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
  60. 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
  61. DESTRUCTURING DECLARATION val mickey = Person("Mickey", "Mouse") val (name, lastName)

    = mickey @_tiwiz
  62. DESTRUCTURING DECLARATION val mickey = Person("Mickey", "Mouse") val (name, lastName)

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

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

    return a + 2 } val b = nested() } @_tiwiz
  65. 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
  66. 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
  67. SINGLETON AKA object DECLARATIONS @_tiwiz

  68. object DataProviderManager { fun register(provider: Provider) { // ... }

    } @_tiwiz
  69. THIS IS NOT THE ONLY USE OF object @_tiwiz

  70. object EXPRESSIONS textView.addTextChangedListener(object : TextWatcher{ override fun afterTextChanged(...) {} override

    fun beforeTextChanged(...) {} override fun onTextChanged(...) {} }) @_tiwiz
  71. COMPANION object class MyClass { companion object Factory { fun

    create(): MyClass = MyClass() } } val instance = MyClass.create() @_tiwiz
  72. COMPANION object class MyClass { companion object { } }

    val x = MyClass.Companion @_tiwiz
  73. 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
  74. DELEGATION @_tiwiz

  75. interface Base { fun print() } class BaseImpl(val x: Int)

    : Base { override fun print() { print(x) } } @_tiwiz
  76. val b = BaseImpl(10) @_tiwiz

  77. class Derived(b: Base) : Base by b @_tiwiz

  78. val b = BaseImpl(10) Derived(b).print() This prints 10 @_tiwiz

  79. class Derived(b: Base) : Base by b { override fun

    print() { print("abc") } } @_tiwiz
  80. val b = BaseImpl(10) Derived(b).print() This prints abc @_tiwiz

  81. STANDARD DELEGATES @_tiwiz

  82. lazy - THIS... val lazyValue: String by lazy { println("computed!")

    "Hello" } println(lazyValue) println(lazyValue) @_tiwiz
  83. lazy - ... WILL PRINT computed! Hello Hello @_tiwiz

  84. 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
  85. Delegates.observable() - ... WILL PRINT <no name> -> first first

    -> second @_tiwiz
  86. THE HANDLER WILL BE CALLED AFTER THE VALUE HAS BEEN

    SET @_tiwiz
  87. Delegates.vetoable() @_tiwiz

  88. 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
  89. 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
  90. 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
  91. 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
  92. COLLECTIONS: OPERATIONS > filter > map > any, none, all

    > firstOrNull @_tiwiz
  93. More info at kotlinlang.org @_tiwiz

  94. SUGGESTED READ KOTLIN FOR ANDROID DEVELOPERS by Antonio Leiva leanpub.com/kotlin-for-

    android-developers @_tiwiz
  95. SUGGESTED READ KOTLIN IN ACTION by Dmitry Jemerov & Svetlana

    Isakova manning.com/books/kotlin-in- action @_tiwiz
  96. SLIDES bit.ly/gdg-kotlin @_tiwiz

  97. THANKS! @_tiwiz