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

A Builder's Intro to Kotlin (Gradle Summit 2017)

A Builder's Intro to Kotlin (Gradle Summit 2017)

Kotlin's popularity has been exploding in the past year. From last year's announcement that Gradle would support it as a build language, to its adoption on large platforms like Android and Spring, to its general applicability for writing IDE and build system plugins, it's hard to find an area that isn't adopting the language in some form.

This talk will be an introduction to the language in the context of Gradle. After covering the language syntax and features and their benefits, we'll look at why it's great for authoring Gradle plugins. Finally, we'll set the stage for Gradle's Kotlin build script support for which there are other full talks at the conference.

Video: https://youtu.be/UAec6OpJiA8

54879f243e5b72eedb2d379bed6fda27?s=128

Jake Wharton
PRO

June 22, 2017
Tweet

Transcript

  1. Jake Wharton A Builder's Intro to Kotlin

  2. Kotlin?

  3. None
  4. None
  5. None
  6. None
  7. None
  8. None
  9. None
  10. None
  11. None
  12. None
  13. None
  14. None
  15. Why Kotlin?

  16. Plugin Author

  17. Plugin Author Buildscript Author

  18. Plugin Author Buildscript Author App Developer

  19. val firstName: String = "Jake"
 val lastName: String? = null

  20. val firstName: String = "Jake"
 val lastName: String? = null

  21. val firstName: String = "Jake"
 val lastName: String? = null

  22. val firstName: String = "Jake"
 val lastName: String? = null

  23. val firstName: String = "Jake"
 val lastName: String? = null

  24. val firstName = "Jake"
 val lastName: String? = null

  25. class User {
 public String getName() {
 // ...
 }


    public void setName(String name) {
 // ...
 }
 } // ^^^ Java
  26. class User {
 public String getName() {
 // ...
 }X


    public void setName(String name) {
 // ...
 }Y
 }Z // ^^^ Java vvv Kotlin val user = User()
 println("Name is " + user.name)
  27. class User {
 public String getName() {
 // ...
 }X


    public void setName(String name) {
 // ...
 }Y
 }Z // ^^^ Java vvv Kotlin val user = User()
 println("Name is " + user.name)X
  28. class User {
 public String getName() {
 // ...
 }X


    public void setName(String name) {
 // ...
 }Y
 }Z // ^^^ Java vvv Kotlin val user = User()
 println("Name is ${user.name}")X
  29. class User {
 public String getName() {
 // ...
 }X


    public void setName(String name) {
 // ...
 }Y
 }Z // ^^^ Java vvv Kotlin val user = User()
 println("Name is $user")X
  30. class User {
 public String getName() {
 // ...
 }X


    public void setName(String name) {
 // ...
 }Y
 }Z // ^^^ Java vvv Kotlin val user = User()
 println("Name is $user")X
  31. class User {
 var name = "Jake"
 } // ^^^

    Kotlin
  32. class User {
 var name = "Jake"
 } // ^^^

    Kotlin vvv Java User user = new User(); System.out.println("Name is " + user.getName());
  33. class User {
 var name = "Jake"
 } // ^^^

    Kotlin vvv Java User user = new User(); System.out.println("Name is " + user.getName());
  34. class User {
 var name = "Jake"
 } // ^^^

    Kotlin vvv Java User user = new User(); System.out.println("Name is " + user.getName()); user.setName("Jane");
  35. class User {
 var name = "Jake"
 } // ^^^

    Kotlin vvv Java User user = new User(); System.out.println("Name is " + user.getName()); user.setName("Jane");
  36. val user = User()

  37. val user = User()
 user = User()

  38. val user = User()
 user = User()
 
 var currentUser

    = User()
 currentUser = User()
  39. fun Date.isTuesday(): Boolean {
 return day == 2
 }

  40. fun Date.isTuesday(): Boolean {
 return day == 2
 } val

    epoch = Date(1970, 0, 0)
 if (epoch.isTuesday()) {
 println("The epoch was a Tuesday.")
 } else {
 println("The epoch was not a Tuesday.")
 }
  41. fun Date.isTuesday(): Boolean {
 return day == 2
 } val

    epoch = Date(1970, 0, 0)
 if (epoch.isTuesday()) {
 println("The epoch was a Tuesday.")
 } else {
 println("The epoch was not a Tuesday.")
 }
  42. fun Date.isTuesday(): Boolean {
 return day == 2
 } val

    epoch = Date(1970, 0, 0)
 if (epoch.isTuesday()) {
 println("The epoch was a Tuesday.")
 } else {
 println("The epoch was not a Tuesday.")
 } // ^^^ Kotlin vvv Java DateKt.isTuesday(date)
  43. val executor = Executors.newSingleThreadExecutor();
 executor.execute {Bprintln("Background thread!") }X

  44. val executor = Executors.newSingleThreadExecutor(); val foo = Foo()
 executor.execute(foo::printIt) class

    Foo { fun printIt() {B println("Background thread!") }X }
  45. val executor = Executors.newSingleThreadExecutor(); val foo = Foo()
 executor.execute(foo::printIt) class

    Foo { fun printIt() {B println("Background thread!") }X }
  46. fun <T> List<T>.filter(predicate: (T) -> Boolean): List<T> {
 // ...


    }
  47. fun <T> List<T>.filter(predicate: (T) -> Boolean): List<T> {
 // ...


    }
  48. fun <T> List<T>.filter(predicate: (T) -> Boolean): List<T> {
 // ...


    }A val items = listOf(1, 2, 3) val odds = items.filter({ item -> item % 2 != 0 })B
  49. fun <T> List<T>.filter(predicate: (T) -> Boolean): List<T> {
 // ...


    }A val items = listOf(1, 2, 3) val odds = items.filter({ item -> item % 2 != 0 })B
  50. fun <T> List<T>.filter(predicate: (T) -> Boolean): List<T> {
 // ...


    }A val items = listOf(1, 2, 3) val odds = items.filter({ it % 2 != 0 })B
  51. fun <T> List<T>.filter(predicate: (T) -> Boolean): List<T> {
 // ...


    }A val items = listOf(1, 2, 3) val odds = items.filter()B{ it % 2 != 0 }
  52. fun <T> List<T>.filter(predicate: (T) -> Boolean): List<T> {
 // ...


    }A val items = listOf(1, 2, 3) val odds = items.filter { it % 2 != 0 }
  53. fun <T> List<T>.filter(predicate: (T) -> Boolean): List<T> {
 // ...


    }A val items = listOf(1, 2, 3) val oddList = items.filter { it % 2 != 0 } val oddSet = items.filterTo(mutableListOf()) { it % 2 != 0 }
  54. fun <T> List<T>.filter(predicate: (T) -> Boolean): List<T> {
 // ...


    }A val items = listOf(1, 2, 3) val odds = items.filter { it % 2 != 0 }
  55. inline fun <T> List<T>.filter(predicate: (T) -> Boolean): List<T> {
 //

    ...
 }A val items = listOf(1, 2, 3) val odds = items.filter { it % 2 != 0 }
  56. inline fun <T> List<T>.filter(predicate: (T) -> Boolean): List<T> { val

    destination = mutableListOf<T>() for (item in this) { if (predicate(item)) destination.add(item) }B return destination }A val items = listOf(1, 2, 3) val odds = items.filter { it % 2 != 0 } val destination = mutableListOf< >() for (item in ) { if ( item ) destination.add(item) }G destination
  57. inline fun <T> List<T>.filter(predicate: (T) -> Boolean): List<T> { val

    destination = mutableListOf<T>() for (item in this) { if (predicate(item)) destination.add(item) }B return destination }A val items = listOf(1, 2, 3) val destination = mutableListOf<Int>() for (item in items) { if (item % 2 != 0) destination.add(item) }G val odds = destination filter it
  58. fun <T> List<T>.filterIsInstance(c: Class<T>): List<T> {
 val destination = mutableListOf<T>()

    for (item in this) { if (c.isInstance(item)) destination.add(item) } return destination
 }A
  59. fun <T> List<T>.filterIsInstance(c: Class<T>): List<T> {
 val destination = mutableListOf<T>()

    for (item in this) { if (c.isInstance(item)) destination.add(item) }G return destination
 }A
  60. fun <T> List<T>.filterIsInstance(): List<T> {
 val destination = mutableListOf<T>() for

    (item in this) { if (item in T) destination.add(item) }G return destination
 }A c: Class<T>
 c.isInstance( )
  61. fun <T> List<T>.filterIsInstance(): List<T> {
 val destination = mutableListOf<T>() for

    (item in this) { if (item in T) destination.add(item) }G return destination
 }A
  62. inline fun <T> List<T>.filterIsInstance(): List<T> {
 val destination = mutableListOf<T>()

    for (item in this) { if (item in T) destination.add(item) }G return destination
 }A
  63. inline fun <reified T> List<T>.filterIsInstance(): List<T> {
 val destination =

    mutableListOf<T>() for (item in this) { if (item in T) destination.add(item) }G return destination
 }A
  64. inline fun <reified T> List<T>.filterIsInstance(): List<T> {
 val destination =

    mutableListOf<T>() for (item in this) { if (item in T) destination.add(item) }G return destination
 }A
  65. inline fun <reified T> List<T>.filterIsInstance(): List<T> {
 val destination =

    mutableListOf<T>() for (item in this) { if (item in T) destination.add(item) } return destination
 }A val list = listOf(1, 2f, 3, 4f) val ints = list.filterIsInstance<Int>()
  66. inline fun <reified T> List<T>.filterIsInstance(): List<T> {
 val destination =

    mutableListOf<T>() for (item in this) { if (item in T) destination.add(item) } return destination
 }A val list = listOf(1, 2f, 3, 4f) val ints = list.filterIsInstance<Int>() ALOAD 7 # item INSTANCEOF java/lang/Integer IFEQ L8 ALOAD 5 # destination ALOAD 7 # item INVOKEINTERFACE java/util/Collection.add (Ljava/lang/Object;)Z
  67. class User {D
 val name = "Jake"
 }A

  68. class User(name: String) {D
 val name = name
 }A 


    "Jake"
  69. class User(val name: String) {
 }A

  70. class User(val name: String)

  71. class User(val name: String) val jake = User("Jake") println("Hello, $jake!")

  72. class User(val name: String) val jake = User("Jake") println("Hello, $jake!")

    Hello, User@3a71f4dd!
  73. data class User(val name: String) val jake = User("Jake") println("Hello,

    $jake!") Hello, User@3a71f4dd!
  74. @3a71f4dd data class User(val name: String) val jake = User("Jake")

    println("Hello, $jake!") Hello, User(name=Jake)!
  75. data class User(val name: String) val jake = User("Jake") println("Hello,

    $jake!") Hello, User(name=Jake)!
  76. class UserPersisence(db: SqlDatabase) { private val deleteByName = db.createStatement("DELETE FROM

    user WHERE name = ?") fun delete(name: String) { deleteByName.bind(1, name) deleteByName.execute() } }
  77. class UserPersisence(db: SqlDatabase) { private val deleteByName = db.createStatement("DELETE FROM

    user WHERE name = ?") fun delete(name: String) { deleteByName.bind(1, name) deleteByName.execute() }B }A
  78. class UserPersisence(db: SqlDatabase) { private val deleteByName by lazy {

    db.createStatement("DELETE FROM user WHERE name = ?") }C fun delete(name: String) { deleteByName.bind(1, name) deleteByName.execute() }B }A
  79. val deleteByName by lazy { db.createStatement("DELETE FROM user WHERE name

    = ?") }C
  80. val deleteByName by lazy { db.createStatement("DELETE FROM user WHERE name

    = ?") }C var name by Delegates.observable("Jane") { prop, old, new -> println("Name changed from $old to $new") }
  81. val deleteByName by lazy { db.createStatement("DELETE FROM user WHERE name

    = ?") }C var name by Delegates.observable("Jane") { prop, old, new -> println("Name changed from $old to $new") } var address by Delegates.notNull<String>()
  82. val deleteByName by lazy { db.createStatement("DELETE FROM user WHERE name

    = ?") }C var name by Delegates.observable("Jane") { prop, old, new -> println("Name changed from $old to $new") } var address by Delegates.notNull<String>() val nameView by bindView<TextView>(R.id.name)
  83. val deleteByName by lazy { db.createStatement("DELETE FROM user WHERE name

    = ?") }C var name by Delegates.observable("Jane") { prop, old, new -> println("Name changed from $old to $new") } var address by Delegates.notNull<String>() val nameView by bindView<TextView>(R.id.name)
  84. fun main(vararg args: String) = runBlocking<Unit> { val jobs =

    List(100_000) { launch(CommonPool) { delay(1000L) print(".") } } jobs.forEach { it.join() } }
  85. Plugin Author Buildscript Author App Developer

  86. Plugin Author Buildscript Author App Developer

  87. apply plugin: 'org.jetbrains.kotlin.jvm'

  88. apply plugin: 'org.jetbrains.kotlin.jvm' src/ main/ java/ Fizz.java Buzz.java

  89. apply plugin: 'org.jetbrains.kotlin.jvm' src/ main/ java/ Fizz.java Buzz.kt

  90. *.java *.kt

  91. *.java *.kt kotlinc

  92. *.java *.kt kotlinc

  93. *.java *.kt kotlinc javac

  94. *.java *.kt kotlinc javac

  95. *.java *.kt kotlinc javac

  96. kotlin-stdlib *.java *.kt kotlinc javac

  97. kotlin-stdlib *.java *.kt kotlinc javac

  98. kotlin-stdlib *.java *.kt kotlinc javac project(':some-library')

  99. apply plugin: 'org.jetbrains.kotlin.jvm'

  100. apply plugin: 'org.jetbrains.kotlin.jvm' apply plugin: 'org.jetbrains.kotlin.android'

  101. apply plugin: 'org.jetbrains.kotlin.jvm' apply plugin: 'org.jetbrains.kotlin.android' apply plugin: 'kotlin2js'

  102. apply plugin: 'org.jetbrains.kotlin.jvm' apply plugin: 'org.jetbrains.kotlin.android' apply plugin: 'kotlin2js' apply

    plugin: 'konan' # Different classpath dependency
  103. apply plugin: 'org.jetbrains.kotlin.jvm' apply plugin: 'org.jetbrains.kotlin.android' apply plugin: 'kotlin2js' apply

    plugin: 'konan' # Different classpath dependency or apply plugin: 'org.jetbrains.kotlin.platform.common' apply plugin: 'org.jetbrains.kotlin.platform.jvm' apply plugin: 'org.jetbrains.kotlin.platform.js' apply plugin: 'konan' # Different classpath dependency
  104. Plugin Author Buildscript Author App Developer

  105. Plugin Author Buildscript Author App Developer

  106. apply plugin: 'org.jetbrains.kotlin.jvm' apply plugin: 'org.jetbrains.kotlin.kapt' sourceCompatibility = JavaVersion.VERSION_1_8 targetCompatibility

    = JavaVersion.VERSION_1_8 dependencies { compile deps.kotlin.stdLibJre8 compile deps.javaPoet compile deps.autoCommon compileOnly deps.autoService kapt deps.autoService testCompile deps.junit testCompile deps.truth testCompile deps.compileTesting }
  107. apply plugin: 'org.jetbrains.kotlin.jvm' apply plugin: 'org.jetbrains.kotlin.kapt' sourceCompatibility = JavaVersion.VERSION_1_8 targetCompatibility

    = JavaVersion.VERSION_1_8 dependencies { compile deps.kotlin.stdLibJre8 compile deps.javaPoet compile deps.autoCommon compileOnly deps.autoService kapt deps.autoService testCompile deps.junit testCompile deps.truth testCompile deps.compileTesting }
  108. apply(plugin: 'org.jetbrains.kotlin.jvm')X apply plugin: 'org.jetbrains.kotlin.kapt' sourceCompatibility = JavaVersion.VERSION_1_8 targetCompatibility =

    JavaVersion.VERSION_1_8 dependencies { compile deps.kotlin.stdLibJre8 compile deps.javaPoet compile deps.autoCommon compileOnly deps.autoService kapt deps.autoService testCompile deps.junit testCompile deps.truth testCompile deps.compileTesting }
  109. apply(singletonMap('plugin', 'org.jetbrains.kotlin.jvm'))X apply plugin: 'org.jetbrains.kotlin.kapt' sourceCompatibility = JavaVersion.VERSION_1_8 targetCompatibility =

    JavaVersion.VERSION_1_8 dependencies { compile deps.kotlin.stdLibJre8 compile deps.javaPoet compile deps.autoCommon compileOnly deps.autoService kapt deps.autoService testCompile deps.junit testCompile deps.truth testCompile deps.compileTesting }
  110. apply(singletonMap('plugin', 'org.jetbrains.kotlin.jvm'))X apply plugin: 'org.jetbrains.kotlin.kapt' sourceCompatibility = JavaVersion.VERSION_1_8 targetCompatibility =

    JavaVersion.VERSION_1_8 dependencies { compile deps.kotlin.stdLibJre8 compile deps.javaPoet compile deps.autoCommon compileOnly deps.autoService kapt deps.autoService testCompile deps.junit testCompile deps.truth testCompile deps.compileTesting }
  111. apply(singletonMap('plugin', 'org.jetbrains.kotlin.jvm'))X apply plugin: 'org.jetbrains.kotlin.kapt' sourceCompatibility = JavaVersion.VERSION_1_8 targetCompatibility =

    JavaVersion.VERSION_1_8 dependencies { compile deps.kotlin.stdLibJre8 compile deps.javaPoet compile deps.autoCommon compileOnly deps.autoService kapt deps.autoService testCompile deps.junit testCompile deps.truth testCompile deps.compileTesting }
  112. apply(singletonMap('plugin', 'org.jetbrains.kotlin.jvm'))X apply plugin: 'org.jetbrains.kotlin.kapt' sourceCompatibility = JavaVersion.VERSION_1_8 targetCompatibility =

    JavaVersion.VERSION_1_8 dependencies { compile deps.kotlin.stdLibJre8 compile(deps.javaPoet) compile deps.autoCommon compileOnly deps.autoService kapt deps.autoService testCompile deps.junit testCompile deps.truth testCompile deps.compileTesting }
  113. apply(singletonMap('plugin', 'org.jetbrains.kotlin.jvm'))X apply plugin: 'org.jetbrains.kotlin.kapt' sourceCompatibility = JavaVersion.VERSION_1_8 targetCompatibility =

    JavaVersion.VERSION_1_8 dependencies { compile deps.kotlin.stdLibJre8 compile(deps.javaPoet) compile deps.autoCommon compileOnly deps.autoService kapt deps.autoService testCompile deps.junit testCompile deps.truth testCompile deps.compileTesting }
  114. android { // ... testOptions { unitTests.all { systemProperty('robolectric.dependency.repo.id', 'example-nexus')

    systemProperty('robolectric.dependency.repo.url', 'https://nexus.example.com/content/groups/public') } } }
  115. android { // ... testOptions { unitTests.all { systemProperty('robolectric.dependency.repo.id', 'example-nexus')

    systemProperty('robolectric.dependency.repo.url', 'https://nexus.example.com/content/groups/public') } } }
  116. android { // ... testOptions { unitTests.all { systemProperty('robolectric.dependency.repo.id', 'example-nexus')

    systemProperty('robolectric.dependency.repo.url', 'https://nexus.example.com/content/groups/public') }
 
 }
  117. apply plugin: 'org.jetbrains.kotlin.jvm' apply plugin: 'org.jetbrains.kotlin.kapt' sourceCompatibility = JavaVersion.VERSION_1_8 targetCompatibility

    = JavaVersion.VERSION_1_8 dependencies { compile deps.kotlin.stdLibJre8 compile deps.javaPoet compile deps.autoCommon compileOnly deps.autoService kapt deps.autoService testCompile deps.junit testCompile deps.truth testCompile deps.compileTesting }A java build.gradle
  118. apply { plugin('org.jetbrains.kotlin.jvm') plugin('org.jetbrains.kotlin.kapt') } java { sourceCompatibility = JavaVersion.VERSION_1_8

    targetCompatibility = JavaVersion.VERSION_1_8 } dependencies { compile(deps.kotlin.stdLibJre8) compile(deps.javaPoet) compile(deps.autoCommon) compileOnly(deps.autoService) kapt(deps.autoService) testCompile(deps.junit) testCompile(deps.truth) testCompile(deps.compileTesting) }A build.gradle.kts
  119. apply { plugin('org.jetbrains.kotlin.jvm') plugin('org.jetbrains.kotlin.kapt') } java { sourceCompatibility = JavaVersion.VERSION_1_8

    targetCompatibility = JavaVersion.VERSION_1_8 } dependencies { compile(deps.kotlin.stdLibJre8) compile(deps.javaPoet) compile(deps.autoCommon) compileOnly(deps.autoService) kapt(deps.autoService) testCompile(deps.junit) testCompile(deps.truth) testCompile(deps.compileTesting) }A build.gradle.kts
  120. apply { plugin('org.jetbrains.kotlin.jvm') plugin('org.jetbrains.kotlin.kapt') } java { sourceCompatibility = JavaVersion.VERSION_1_8

    targetCompatibility = JavaVersion.VERSION_1_8 } dependencies { compile(deps.kotlin.stdLibJre8) compile(deps.javaPoet) compile(deps.autoCommon) compileOnly(deps.autoService) kapt(deps.autoService) testCompile(deps.junit) testCompile(deps.truth) testCompile(deps.compileTesting) }A build.gradle.kts
  121. apply { plugin('org.jetbrains.kotlin.jvm') plugin('org.jetbrains.kotlin.kapt') } java { sourceCompatibility = JavaVersion.VERSION_1_8

    targetCompatibility = JavaVersion.VERSION_1_8 } dependencies { compile(deps.kotlin.stdLibJre8) compile(deps.javaPoet) compile(deps.autoCommon) compileOnly(deps.autoService) kapt(deps.autoService) testCompile(deps.junit) testCompile(deps.truth) testCompile(deps.compileTesting) }A build.gradle.kts
  122. apply { plugin('org.jetbrains.kotlin.jvm') plugin('org.jetbrains.kotlin.kapt') } java { sourceCompatibility = JavaVersion.VERSION_1_8

    targetCompatibility = JavaVersion.VERSION_1_8 } dependencies { compile(deps.kotlin.stdLibJre8) compile(deps.javaPoet) compile(deps.autoCommon) compileOnly(deps.autoService) kapt(deps.autoService) testCompile(deps.junit) testCompile(deps.truth) testCompile(deps.compileTesting) }A build.gradle.kts
  123. apply { plugin('org.jetbrains.kotlin.jvm') plugin('org.jetbrains.kotlin.kapt') } java { sourceCompatibility = JavaVersion.VERSION_1_8

    targetCompatibility = JavaVersion.VERSION_1_8 } dependencies { compile(deps.kotlin.stdLibJre8) compile(deps.javaPoet) compile(deps.autoCommon) compileOnly(deps.autoService) kapt(deps.autoService) testCompile(deps.junit) testCompile(deps.truth) testCompile(deps.compileTesting) }A build.gradle.kts
  124. None
  125. None
  126. Plugin Author Buildscript Author App Developer

  127. Plugin Author Buildscript Author App Developer

  128. class MyPlugin : Plugin<Project> { override fun apply(project: Project) {

    // ... }B }A
  129. import org.gradle.kotlin.dsl.* class MyPlugin : Plugin<Project> { override fun apply(project:

    Project) { // ... }B }A
  130. kotlin-stdlib *.java *.kt kotlinc javac

  131. kotlin-stdlib *.java *.kt kotlinc javac apply plugin: 'your-gradle-plugin'

  132. None
  133. None
  134. +

  135. jakewharton jakewharton jakewharton twitter.com/ github.com/ .com A Builder's Intro to

    Kotlin