Kotlin, beyond the basics

Kotlin, beyond the basics

Talk given at 360AnDev (https://360andev.com/) 2018 in Denver Colorado, USA.

Video: https://www.youtube.com/watch?v=Ot2DOKztu38

Features 3 important topics for intermediate Kotlin developers - adapting to the functional programming paradigm, learning more about functions and lambdas, and learning about Kotlin-Java interoperability

9ab0b3b080e75e0c03a0c643333f8b93?s=128

Segun Famisa

July 20, 2018
Tweet

Transcript

  1. Kotlin, beyond the basics

  2. segunfamisa segunfamisa.com

  3. Intro

  4. Imperative vs Functional Programming

  5. Imperative vs Functional Programming Functions in Kotlin - lambdas, stdlib

    functions, etc
  6. Imperative vs Functional Programming Functions in Kotlin - lambdas, stdlib

    functions, etc Java & Kotlin Interop
  7. Imperative vs Functional programming

  8. Functional == actions are composed into functions and usually reads

    as “what is done” Imperative == structured in steps of execution and usually reads as “how it’s done” Imperative == structured in steps of execution and usually reads as “how it’s done”
  9. Functional == actions are composed into functions and usually reads

    as “what is done” Imperative == structured in steps of execution and usually reads as “how it’s done” Functional == actions are composed into functions and usually reads as “what is done” Imperative == structured in steps of execution and usually reads as “how it’s done”
  10. // Java - print even numbers for (int i =

    start; i < end; i++) { if (i % 2 == 0) { System.out.println(i); } }
  11. // Java - print even numbers for (int i =

    start; i < end; i++) { if (i % 2 == 0) { System.out.println(i); } } // Kotlin - print even numbers (start until end) .filter { it % 2 == 0 } .map { println(it) }
  12. Imperative Functional

  13. Imperative Functional Immutability isn’t encouraged at language level Encourages immutability

  14. Imperative Functional Immutability isn’t encouraged at language level Encourages immutability

    Instances of classes, structures, objects are first class citizens Functions are first class citizens
  15. Imperative Functional Immutability isn’t encouraged at language level Encourages immutability

    Instances of classes, structures, objects are first class citizens Functions are first class citizens Loops, method calls, conditionals Function calls
  16. Imperative Functional Immutability isn’t encouraged at language level Encourages immutability

    Instances of classes, structures, objects are first class citizens Functions are first class citizens Loops, method calls, conditionals Function calls Side-effects allowed in functions Pure functions
  17. functions in Kotlin

  18. Functions are first class citizens

  19. Functions are first class citizens They can: • be stored

    in a variable - just like other types
  20. Functions are first class citizens They can: • be stored

    in a variable - just like other types • take another function as parameter
  21. Functions are first class citizens They can: • be stored

    in a variable - just like other types • take another function as parameter • return a function
  22. Functions are first class citizens They can: • be stored

    in a variable - just like other types • take another function as parameter • return a function a.k.a higher order functions
  23. Lambdas & higher order functions

  24. Lambdas & higher order functions fun atLeastAndroidP(action: () -> Unit)

    { ... }
  25. Lambdas & higher order functions fun atLeastAndroidP(action: () -> Unit)

    { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) { action() } }
  26. Lambdas & higher order functions // Usage: atLeastAndroidP { //

    do something on Android P } fun atLeastAndroidP(action: () -> Unit) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) { action() } }
  27. Lambdas & higher order functions fun atLeastAndroidP(action: () -> Unit)

    { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) { action() } } Lambda // Usage: atLeastAndroidP { // do something on Android P }
  28. Lambdas & higher order functions fun atLeastAndroidP(action: () -> Unit)

    { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) { action() } } Higher order function // Usage: atLeastAndroidP { // do something on Android P }
  29. Lambdas & higher order functions // Usage: atLeastAndroidP { //

    do something on Android P } fun atLeastAndroidP(action: () -> Unit) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) { action() } }
  30. Lambdas & higher order functions // Usage: atLeastAndroidP { //

    do something on Android P } fun atLeastAndroidP(action: () -> Unit) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) { action() } } Tip: Take a look at the generated code to understand what’s happening under the hood
  31. Lambdas & higher order functions // Generated Java code public

    final void atLeastAndroidP(@NotNull Function0 action) { if (VERSION.SDK_INT > 28) { action.invoke(); } } fun atLeastAndroidP(action: () -> Unit) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) { action() } }
  32. Lambdas & higher order functions // Generated Java code public

    final void atLeastAndroidP(@NotNull Function0 action) { if (VERSION.SDK_INT > 28) { action.invoke(); } } Every lambda is an object! Not great for performance fun atLeastAndroidP(action: () -> Unit) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) { action() } }
  33. () -> Unit Function0<Unit> (Int) -> Boolean Function1<Int,Boolean> (Int, String)

    -> Boolean Function2<Int, String, Boolean> Every lambda corresponds to a FunctionN interface - where N is the number of params in the lambda
  34. Lambdas & higher order functions // FunctionN interfaces used by

    Kotlin interface Function0<out R> : Function<R> interface Function1<in P1, out R> : Function<R> interface Function2<in P1, in P2, out R> : Function<R> ... interface Function22<in P1, in P2...in P22, out R> : Function<R> { /** Invokes the function with the specified arguments. */ public operator fun invoke(p1: P1, p2: P2...p22: P22): R }
  35. Improving lambdas’ performance - the inline keyword // Kotlin fun

    atLeastAndroidP(action: () -> Unit) {...}
  36. Improving lambdas’ performance - the inline keyword // Kotlin inline

    fun atLeastAndroidP(action: () -> Unit) {...}
  37. Improving lambdas’ performance - the inline keyword // Kotlin inline

    fun atLeastAndroidP(action: () -> Unit) {...} // Usage: fun doSomethingOnP() { atLeastAndroidP { println("I'm on Android P") } }
  38. Improving lambdas’ performance - the inline keyword // Kotlin inline

    fun atLeastAndroidP(action: () -> Unit) {...} // Usage: fun doSomethingOnP() { atLeastAndroidP { println("I'm on Android P") } } // Generated Java code public final void doSomethingOnP() { if (VERSION.SDK_INT > 28) { String var0 = "I'm on Android P"; System.out.println(var0); } }
  39. Improving lambdas’ performance - the inline keyword // Kotlin inline

    fun atLeastAndroidP(action: () -> Unit) {...} // Usage: fun doSomethingOnP() { atLeastAndroidP { println("I'm on Android P") } } // Generated Java code public final void doSomethingOnP() { if (VERSION.SDK_INT > 28) { String var0 = "I'm on Android P"; System.out.println(var0); } } Method body is copied to the call site
  40. Other good-to-know concepts when working with lambdas:

  41. noinline keyword - used to mark lambdas in an inline

    function that we don’t want to inline Other good-to-know concepts when working with lambdas:
  42. noinline keyword - used to mark lambdas in an inline

    function that we don’t want to inline Other good-to-know concepts when working with lambdas: inline fun atLeastAndroidP(action: () -> Unit, noinline fallback: () -> Unit) { if (Build.VERSION.SDK_INT > Build.VERSION_CODES.P) { action() } else { fallback() } }
  43. noinline keyword - used to mark other lambda params in

    an inline function that we don’t want to inline Other good-to-know concepts when working with lambdas: inline fun atLeastAndroidP(action: () -> Unit, noinline fallback: () -> Unit) { if (Build.VERSION.SDK_INT > Build.VERSION_CODES.P) { action() } else { fallback() } } the `fallback` lambda is not inlined
  44. non-local returns - typically non-local returns are not allowed within

    lambdas unless the function is inlined. Other good-to-know concepts when working with lambdas:
  45. non-local returns - typically non-local returns are not allowed within

    lambdas unless the function is inlined. fun useNormalLambda() { normalLambda { ... return@normalLambda // works fine (local return) } } Other good-to-know concepts when working with lambdas:
  46. non-local returns - typically non-local returns are not allowed within

    lambdas unless the function is inlined. fun useNormalLambda() { normalLambda { ... return@normalLambda // works fine (local return) return // compile error (non-local return) } } Other good-to-know concepts when working with lambdas:
  47. non-local returns - typically non-local returns are not allowed within

    lambdas unless the function is inlined. Other good-to-know concepts when working with lambdas: fun useNormalLambda() { normalLambda { ... return@normalLambda // works fine (local return) return // compile error (non-local return } } fun useInlineLambda() { inlineLambda { return // works fine. Returns from useInlineLambda } }
  48. crossinline keyword - used when the lambdas are not used

    directly in the inline function Other good-to-know concepts when working with lambdas:
  49. crossinline keyword - used when the lambdas are not used

    directly in the inline function Other good-to-know concepts when working with lambdas: inline fun View.waitForLayout(crossinline action: () -> Unit) = with(viewTreeObserver) { addOnGlobalLayoutListener(object : ViewTreeObserver.OnGlobalLayoutListener { override fun onGlobalLayout() { this@waitForLayout.viewTreeObserver.removeOnGlobalLayoutListener(this) action() } }) }
  50. crossinline keyword - used when the lambdas are not used

    directly in the inline function Other good-to-know concepts when working with lambdas: inline fun View.waitForLayout(crossinline action: () -> Unit) = with(viewTreeObserver) { addOnGlobalLayoutListener(object : ViewTreeObserver.OnGlobalLayoutListener { override fun onGlobalLayout() { this@waitForLayout.viewTreeObserver.removeOnGlobalLayoutListener(this) action() } }) } Non-local returns are not allowed within the lambda
  51. Standard library functions let, run, apply, also

  52. Standard library functions Some of these functions are also referred

    to as Scoping functions
  53. let - Standard.kt public inline fun <T, R> T.let(block: (T)

    -> R): R = block(this)
  54. let - Standard.kt public inline fun <T, R> T.let(block: (T)

    -> R): R = block(this) Lambda function
  55. let - Standard.kt public inline fun <T, R> T.let(block: (T)

    -> R): R = block(this) Receiver
  56. let - Standard.kt public inline fun <T, R> T.let(block: (T)

    -> R): R = block(this) // Sample usage client?.email ?.let { mailer.sendMessage(it, message) }
  57. let - Standard.kt // Sample usage client?.email ?.let { mailer.sendMessage(it,

    message) } public inline fun <T, R> T.let(block: (T) -> R): R = block(this)
  58. let - Standard.kt // Sample usage client?.email ?.let { mailer.sendMessage(it,

    message) } // Or client?.email ?.let { email -> mailer.sendMessage(email, message) } public inline fun <T, R> T.let(block: (T) -> R): R = block(this)
  59. run - Standard.kt public inline fun <T, R> T.run(block: T.()

    -> R): R = block() Runs the block of code and returns the last line in the lambda
  60. run - Standard.kt public inline fun <T, R> T.run(block: T.()

    -> R): R = block() Receiver
  61. run - Standard.kt public inline fun <T, R> T.run(block: T.()

    -> R): R = block() Function literal with receiver
  62. run - Standard.kt public inline fun <T, R> T.run(block: T.()

    -> R): R = block() // Sample usage fun performTransformation(input: String) : String {...} val transformedName = name.run { println("Transforming name...") val transformedString = performTransformation(this) transformedString }
  63. run - Standard.kt public inline fun <T, R> T.run(block: T.()

    -> R): R = block() // Sample usage fun performTransformation(input: String) : String {...} val transformedName = name.run { println("Transforming name...") val transformedString = performTransformation(this) transformedString }
  64. run - Standard.kt public inline fun <T, R> T.run(block: T.()

    -> R): R = block() // Sample usage fun performTransformation(input: String) : String {...} val transformedName = name.run { println("Transforming name...") val transformedString = performTransformation(this) transformedString }
  65. run - Standard.kt public inline fun <T, R> T.run(block: T.()

    -> R): R = block() // Sample usage fun performTransformation(input: String) : String {...} val transformedName = name.run { println("Transforming name...") val transformedString = performTransformation(this) transformedString } Receiver is accessed as “this”, and exposes the inner members of the receiver class
  66. run - Standard.kt public inline fun <T, R> T.run(block: T.()

    -> R): R = block() // Sample usage fun performTransformation(input: String) : String {...} val transformedName = name.run { println("Transforming name...") val transformedString = performTransformation(this) transformedString } transformedString is returned from the lambda
  67. also - Standard.kt inline fun <T> T.also(block: (T) -> Unit):

    T { block(this); return this }
  68. also - Standard.kt inline fun <T> T.also(block: (T) -> Unit):

    T { block(this); return this } // Sample usage val dev = Developer().also { it.name = "Segun" it.lovesCatVideos = true it.stack = "Android" }
  69. also - Standard.kt inline fun <T> T.also(block: (T) -> Unit):

    T { block(this); return this } The receiver is accessed as “it” // Sample usage val dev = Developer().also { it.name = "Segun" it.lovesCatVideos = true it.stack = "Android" }
  70. also - Standard.kt inline fun <T> T.also(block: (T) -> Unit):

    T { block(this); return this } // Sample usage val dev = Developer().also { it.name = "Segun" it.lovesCatVideos = true it.stack = "Android" } // OR val dev = Developer().also { developer -> developer.name = "Segun" developer.lovesCatVideos = true developer.stack = "Android" }
  71. apply - Standard.kt inline fun <T> T.apply(block: T.() -> Unit):

    T { block(); return this }
  72. apply - Standard.kt inline fun <T> T.apply(block: T.() -> Unit):

    T { block(); return this } // Sample usage val dev = Developer().apply { this.name = "Segun" this.lovesCatVideos = true this.stack = "Android" }
  73. apply - Standard.kt inline fun <T> T.apply(block: T.() -> Unit):

    T { block(); return this } // Sample usage val dev = Developer().apply { this.name = "Segun" this.lovesCatVideos = true this.stack = "Android" } Exposes the receiver as “this”
  74. Things to consider

  75. Things to consider • Avoid overusing these scoping functions -

    readability can degrade quickly
  76. Things to consider • Avoid overusing these scoping functions -

    readability can degrade quickly • Consider renaming it to something better when possible
  77. Things to consider • Avoid overusing these scoping functions -

    readability can degrade quickly • Consider renaming it to something better when possible • More stdlib functions ◦ takeIf, takeUnless, with, etc
  78. stdlib functions in action

  79. // Java code public void sendMessageToClient( @Nullable Client client, @Nullable

    String message, @NotNull Mailer mailer ) { if (client == null || message == null) return; PersonalInfo personalInfo = client.getPersonalInfo(); if (personalInfo == null) return; String email = personalInfo.getEmail(); if (email == null) return; mailer.sendMessage(email, message); } stdlib functions in action
  80. // Java code public void sendMessageToClient( @Nullable Client client, @Nullable

    String message, @NotNull Mailer mailer ) { if (client == null || message == null) return; PersonalInfo personalInfo = client.getPersonalInfo(); if (personalInfo == null) return; String email = personalInfo.getEmail(); if (email == null) return; mailer.sendMessage(email, message); } // Kotlin equivalent fun sendMessageToClient( client: Client?, message: String?, mailer: Mailer ) { client?.takeIf { message != null } ?.personalInfo ?.email ?.let { email -> mailer.sendMessage(email, message!!) } } stdlib functions in action
  81. // Java code public void sendMessageToClient( @Nullable Client client, @Nullable

    String message, @NotNull Mailer mailer ) { if (client == null || message == null) return; PersonalInfo personalInfo = client.getPersonalInfo(); if (personalInfo == null) return; String email = personalInfo.getEmail(); if (email == null) return; mailer.sendMessage(email, message); } // Kotlin equivalent fun sendMessageToClient( client: Client?, message: String?, mailer: Mailer ) { client?.takeIf { message != null } ?.personalInfo ?.email ?.let { email -> mailer.sendMessage(email, message!!) } } stdlib functions in action
  82. // Java code public void sendMessageToClient( @Nullable Client client, @Nullable

    String message, @NotNull Mailer mailer ) { if (client == null || message == null) return; PersonalInfo personalInfo = client.getPersonalInfo(); if (personalInfo == null) return; String email = personalInfo.getEmail(); if (email == null) return; mailer.sendMessage(email, message); } // Kotlin equivalent fun sendMessageToClient( client: Client?, message: String?, mailer: Mailer ) { client?.takeIf { message != null } ?.personalInfo ?.email ?.let { email -> mailer.sendMessage(email, message!!) } } stdlib functions in action
  83. // Java code public void sendMessageToClient( @Nullable Client client, @Nullable

    String message, @NotNull Mailer mailer ) { if (client == null || message == null) return; PersonalInfo personalInfo = client.getPersonalInfo(); if (personalInfo == null) return; String email = personalInfo.getEmail(); if (email == null) return; mailer.sendMessage(email, message); } // Kotlin equivalent fun sendMessageToClient( client: Client?, message: String?, mailer: Mailer ) { client?.takeIf { message != null } ?.personalInfo ?.email ?.let { email -> mailer.sendMessage(email, message!!) } } stdlib functions in action Functional, readable, concise
  84. Java & Kotlin Interoperability ...a tale of 2 islands

  85. Java & Kotlin Interoperability Important because: • Android APIs are

    written in Java
  86. Java & Kotlin Interoperability Important because: • Android APIs are

    written in Java • Kotlin & Java may be mixed in the same codebase
  87. - nullability Java & Kotlin Interoperability

  88. String! String? What do these mean when you think about

    nullability & types? String Pop
  89. String! String? String Non-nullable type Nullable type Platform type Kotlin

    compiler has no idea whether it’s nullable or not
  90. types are very important when considering interoperability between Java &

    Kotlin
  91. String String? String or

  92. // Calling Java from Kotlin // Compiles fine. Safe in

    runtime val nameLength = myObject.name.length // Java @NotNull public String getName() { return "Segun"; } ...
  93. // Calling Java from Kotlin // Compiler error. Need safe

    access val nameLength = myObject.name.length // Java @Nullable public String getName() { return null; } ...
  94. // Calling Java from Kotlin // Compiler error. Need safe

    access val nameLength = myObject.name.length // Compiles fine. Safe in runtime val nameLength = myObject.name?.length // Java @Nullable public String getName() { return null; } ...
  95. // Calling Java from Kotlin // Compiles fine. NPE in

    runtime val nameLength = myObject.name.length // Java public String getName() { return null; } ...
  96. // Java public String getName() { return null; } ...

    // Calling Java from Kotlin // Compiles fine. NPE in runtime val nameLength = myObject.name.length // Compiles fine. Safe in runtime val nameLength = myObject.name?.length
  97. @Nullable String getName() {..} Kotlin compiler treats as nullable “?”

    @NotNull String getName() {..} Kotlin compiler treats as non-nullable String getName() {..} Kotlin compiler has no clue. Treats as platform type
  98. - calling Kotlin from Java Java & Kotlin Interoperability

  99. Kotlin package-level functions

  100. Kotlin package-level functions Functions can be defined in a file

    directly without being in any class or object. // InteropDemo.kt fun getName() = "Segun"
  101. Kotlin package-level functions Functions can be defined in a file

    directly without being in any class or object. // InteropDemo.kt fun getName() = "Segun" // Calling from Java InteropDemoKt.getName();
  102. Kotlin package-level functions @JvmName annotation helps to tell Kotlin compiler

    what the generated Java class name should be when consumed from Java
  103. Kotlin package-level functions // InteropDemo.kt @file:JvmName("InteropDemo") fun getName() = "Segun"

    @JvmName annotation helps to tell Kotlin compiler what the generated Java class name should be when consumed from Java
  104. Kotlin package-level functions // InteropDemo.kt @file:JvmName("InteropDemo") fun getName() = "Segun"

    // Calling from Java InteropDemo.getName(); @JvmName annotation helps to tell Kotlin compiler what the generated Java class name should be when consumed from Java
  105. @JvmName The annotation can also be applied to functions

  106. @JvmName // Kotlin code @JvmName("getInteropName") fun getName() = "Segun" The

    annotation can also be applied to functions
  107. @JvmName // Kotlin code @JvmName("getInteropName") fun getName() = "Segun" //

    Consumed from Java demo.getInteropName(); The annotation can also be applied to functions
  108. @JvmName The annotation can also be applied to functions //

    Kotlin code @JvmName("getInteropName") fun getName() = "Segun" // Consumed from Java demo.getInteropName(); // Consumed from Kotlin demo.getName()
  109. @JvmStatic Kotlin does not have static methods. Instead, it has

    objects, companion objects
  110. @JvmStatic // Kotlin Object object StringUtils { fun upperCase(text: String)

    = text.toUpperCase() }
  111. @JvmStatic // Kotlin Object object StringUtils { fun upperCase(text: String)

    = text.toUpperCase() } // Calling from Java String upperCaseName = StringUtils.INSTANCE.upperCase("Segun");
  112. @JvmStatic // Kotlin Object object StringUtils { + @JvmStatic fun

    upperCase(text: String) = text.toUpperCase() } // Calling from Java String upperCaseName = StringUtils.INSTANCE.upperCase("Segun");
  113. @JvmStatic // Kotlin Object object StringUtils { + @JvmStatic fun

    upperCase(text: String) = text.toUpperCase() } // Calling from Java String upperCaseName = StringUtils.INSTANCE.upperCase("Segun"); String upperCaseName = StringUtils.upperCase("Segun");
  114. @JvmStatic - Static providers in Dagger Specially useful when working

    with Dagger static Providers on Android
  115. @Module abstract class RepositoryModule { @Binds abstract fun bindRepo(repository: Repository):

    IRepository companion object { // static provider @Provides fun provideApiService: ApiService = ... } } @JvmStatic - Static providers in Dagger
  116. @Module abstract class RepositoryModule { @Binds abstract fun bindRepo(repository: Repository):

    IRepository companion object { // static provider @Provides fun provideApiService: ApiService = ... } } Won’t compile. Dagger error. Why? @JvmStatic - Static providers in Dagger
  117. @JvmStatic - Static providers in Dagger // Generated Java class

    @Module public abstract class RepositoryModule { ... @Binds @NotNull public abstract IRepository bindRepo(@NotNull Repository var1); public static final class Companion { @Provides @NotNull public final ApiService providesApiService() {...} } }
  118. @JvmStatic - Static providers in Dagger // Generated Java class

    @Module public abstract class RepositoryModule { ... @Binds @NotNull public abstract IRepository bindRepo(@NotNull Repository var1); public static final class Companion { @Provides @NotNull public final ApiService providesApiService() {...} } } No @Module
  119. @JvmStatic - Static providers in Dagger // Generated Java class

    @Module public abstract class RepositoryModule { ... @Binds @NotNull public abstract IRepository bindRepo(@NotNull Repository var1); public static final class Companion { @Provides @NotNull public final ApiService providesApiService() {...} } } No @Module @Provides method is generated as a member of the Companion class
  120. @JvmStatic - Static providers in Dagger // Generated Java class

    @Module public abstract class RepositoryModule { ... @Binds @NotNull public abstract IRepository bindRepo(@NotNull Repository var1); public static final class Companion { @Provides @NotNull public final ApiService providesApiService() {...} } } No @Module @Provides method is generated as a member of the Companion class Dagger is unable to provide this dependency
  121. @JvmStatic - Static providers in Dagger @Module abstract class RepositoryModule

    { @Binds abstract fun bindRepo(repository: Repository): IRepository + @Module companion object { // static provider @Provides + @JvmStatic fun provideApiService: ApiService = ... } } Fixed by adding @Module and @JvmStatic annotations
  122. @JvmStatic - Static providers in Dagger Fixed by adding @Module

    and @JvmStatic annotations // Generated Java class with fixes @Module public abstract class RepositoryModule { @Binds public abstract IRepository bindRepos(@NotNull Repository var1); @Provides @JvmStatic public static final ApiService providesApiService() {...} @Module public static final class Companion { @Provides @JvmStatic public final ApiService providesApiService() {...} ... } } Kotlin compiler generates a static method within the RepositoryModule class
  123. @JvmStatic - Static providers in Dagger Fixed by adding @Module

    and @JvmStatic annotations // Generated Java class with fixes @Module public abstract class RepositoryModule { @Binds public abstract IRepository bindRepos(@NotNull Repository var1); @Provides @JvmStatic public static final ApiService providesApiService() {...} @Module public static final class Companion { @Provides @JvmStatic public final ApiService providesApiService() {...} ... } } Dagger will see this module, but generated code will not be used. RepositoryModule.Companion module isn’t registered
  124. @JvmOverloads

  125. @JvmOverloads // Kotlin class with default values class Point(val x:

    Int = 0, val y: Int = 0)
  126. @JvmOverloads // Kotlin class with default values class Point(val x:

    Int = 0, val y: Int = 0) // Calling from Java Point p1 = new Point(); Point p2 = new Point(1, 3);
  127. @JvmOverloads // Kotlin class with default values class Point(val x:

    Int = 0, val y: Int = 0) // Calling from Java Point p1 = new Point(); Point p2 = new Point(1, 3); Specify none or all params
  128. @JvmOverloads // Kotlin class with default values class Point @JvmOverloads

    constructor(val x: Int = 0, val y: Int = 0)
  129. @JvmOverloads // Kotlin class with default values class Point @JvmOverloads

    constructor(val x: Int = 0, val y: Int = 0) // Generated Java code public final class Point { // Overloaded constructors public Point() {...} public Point(int x) {...} public Point(int x, int y) {...} }
  130. @JvmOverloads // Calling from Java Point p1 = new Point();

    Point p2 = new Point(1); Point p3 = new Point(1, 3); // Kotlin class with default values class Point @JvmOverloads constructor(val x: Int = 0, val y: Int = 0) // Generated Java code public final class Point { // Overloaded constructors public Point() {...} public Point(int x) {...} public Point(int x, int y) {...} }
  131. @JvmOverloads Also works on other functions that are not constructors

  132. @Jvm* annotations There are more: @JvmField @JvmSuppressWildcards @JvmMultifileClass... etc

  133. Resources KotlinConf videos #Kotlin on twitter Kotlinweekly.net kotlinlang.org

  134. Thank you segunfamisa segunfamisa.com