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

Kotlin is fun

Sponsored · Your Podcast. Everywhere. Effortlessly. Share. Educate. Inspire. Entertain. You do you. We'll handle the rest. →

Kotlin is fun

Each year Kotlin has been gaining on popularity in the software community. Its modern syntax and mechanisms allow to write simpler, more reliable and testable code.

This is an introductory talk which covers basics of the language and shows how one can leverage power of the language in their daily coding.

Avatar for SikoraMichal

SikoraMichal

July 19, 2017

Other Decks in Programming

Transcript

  1. Syntax Kotlin Java fun isPositive(a: Int): Boolean { return a

    > 0 } public boolean isPositive(final int a) { return a > 0; }
  2. Syntax Kotlin Java fun isPositive(a: Int): Boolean { return a

    > 0 } public boolean isPositive(final int a) { return a > 0; }
  3. Syntax Kotlin Java fun isPositive(a: Int): Boolean { return a

    > 0 } public boolean isPositive(final int a) { return a > 0; }
  4. Syntax Kotlin Java fun isPositive(a: Int): Boolean { return a

    > 0 } public boolean isPositive(final int a) { return a > 0; }
  5. Syntax Kotlin Java fun isPositive(a: Int): Boolean { return a

    > 0 } public boolean isPositive(final int a) { return a > 0; }
  6. Syntax Kotlin Java fun isPositive(a: Int): Boolean { return a

    > 0 } public boolean isPositive(final int a) { return a > 0; }
  7. Syntax Kotlin Java fun isPositive(a: Int): Boolean { return a

    > 0 } public boolean isPositive(final int a) { return a > 0; }
  8. Syntax Kotlin Java fun isPositive(a: Int) = a > 0

    public boolean isPositive(final int a) { return a > 0; }
  9. Default parameters fun highlightText(text: String, offset: Int, length: Int) val

    text = "Reksio" highlightText(text, 0, text.length)
  10. Default parameters fun highlightText(text: String, offset: Int = 0, length:

    Int = text.length) val text = "Reksio" highlightText(text, 0, text.length)
  11. Default parameters fun highlightText(text: String, offset: Int = 0, length:

    Int = text.length) val text = "Reksio" highlightText(text, 0, text.length)
  12. Default parameters fun highlightText(text: String, offset: Int = 0, length:

    Int = text.length) val text = "Reksio" highlightText(text)
  13. Named parameters fun someFancyMethod(isExternalCall: Boolean, isUserGoat: Boolean, isMyBankSafe: Boolean, isItHotOutside:

    Boolean, isItMonday: Boolean) someFancyMethod( isItHotOutside = false, isItMonday = true, isMyBankSafe = true, isUserGoat = true, isExternalCall = false)
  14. Named parameters fun highlightText(text: String, offset: Int = 0, length:

    Int = text.length) val text = "Reksio" highlightText(text, length = 4)
  15. when expression fun isZero(number: Int): Boolean { when (number) {

    0 -> return true else -> return false } }
  16. when expression fun isZero(number: Int): Boolean { when (number) {

    0 -> return true else -> return false } }
  17. when expression fun estimate(number: Int) = when (number) { 0

    -> "Nothing" 1, 2, 3, 4, 5 -> "Low" in 6..10 -> "Medium" else -> if (number < 0) "Negative" else "High" }
  18. if expression fun estimate(number: Int) = when (number) { 0

    -> "Nothing" 1, 2, 3, 4, 5 -> "Low" in 6..10 -> "Medium" else -> if (number < 0) "Negative" else "High" }
  19. Smart casting fun doSomething(item: Any) = when (item) { is

    String -> item.toUpperCase() is Int -> (item * 2).toString() is Boolean -> booleanAsString(item) else -> "" }
  20. Properties Kotlin Java class UserKt(var name: String, var age: Int)

    public class UserJava { private String name; private int age; public UserJava(String name, int age) { this.name = name; this.age = age; } public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } }
  21. Properties Kotlin Java class UserKt(var name: String, var age: Int)

    public class UserJava { private String name; private int age; public UserJava(String name, int age) { this.name = name; this.age = age; } public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } } val user = UserJava("Reksio", 50) user.age = 51 val age = user.age UserKt user = new UserKt("Reksio", 50); user.setAge(51); int user = user.getAge();
  22. Data classes class User(val name: String, val age: Int) val

    user = User("Reksio", 50) user.toString() // com.example.User@6f2b958e
  23. Data classes data class User(val name: String, val age: Int)

    val user = User("Reksio", 50) user.toString() // User(name=Reksio,age=50)
  24. Data classes data class User(val name: String, val age: Int)

    val user = User("Reksio", 50) user.toString() // User(name=Reksio,age=50) val user2 = user.copy(age = 51)
  25. Data classes public class User { @NonNull private final String

    name; private final int age; public User(@NonNull String name, int age) { this.name = name; this.age = age; } @NonNull public String getName() { return name; } public int getAge() { return age; } @Override public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; User user = (User) o; if (age != user.age) return false; return name.equals(user.name); } @Override public int hashCode() { int result = name.hashCode(); result = 31 * result + age; return result; } @Override public String toString() { return "User{" + "name='" + name + '\'' + ", age=" + age + '}'; } } data class User(val name: String, val age: Int)
  26. Sealed classes sealed class LoginUiModel { object Pending : LoginUiModel()

    data class Success(val username: String) : LoginUiModel() data class Error(val code: Int) : LoginUiModel() }
  27. Sealed classes fun renderPending() fun renderSuccess(model: LoginUiModel.Success) fun renderUiModel(model: LoginUiModel)

    = when (model) { is LoginUiModel.Pending -> renderPending() is LoginUiModel.Success -> renderSuccess(model) }
  28. Sealed classes fun renderUiModel(model: LoginUiModel) = when (model) { is

    LoginUiModel.Pending -> renderPending() is LoginUiModel.Success -> renderSuccess(model) } fun renderPending() fun renderSuccess(model: LoginUiModel.Success) when expresion must be exhaustive, add neccessary 'Error' branch or 'else' branch instead
  29. Sealed classes fun renderUiModel(model: LoginUiModel) = when (model) { is

    LoginUiModel.Pending -> renderPending() is LoginUiModel.Success -> renderSuccess(model) else -> renderError(model as LoginUiModel.Error) } fun renderPending() fun renderSuccess(model: LoginUiModel.Success) fun renderError(model: LoginUiModel.Error)
  30. Sealed classes fun renderPending() fun renderSuccess(model: LoginUiModel.Success) fun renderError(model: LoginUiModel.Error)

    fun renderUiModel(model: LoginUiModel) = when (model) { is LoginUiModel.Pending -> renderPending() is LoginUiModel.Success -> renderSuccess(model) is LoginUiModel.Error -> renderError(model) }
  31. Null safety var name = "Reksio" name = null null

    can not be a value of a non-null type String
  32. Extension functions fun isPositive(a: Int) = a > 0 val

    a = 1 if (isPositive(a)) { // Do something }
  33. Extension functions fun Int.isPositive() = this > 0 val a

    = 1 if (a.isPositive()) { // Do something }
  34. Lambdas val lambda1: (String) -> Unit = { text ->

    println(text) } val lambda2: (String) -> Boolean = { text -> text.isEmpty() } val lambda3: (Int, Int) -> Int = { x, y -> x + y }
  35. Lambdas val lambda1: (String) -> Unit = { text ->

    println(text) } val lambda2: (String) -> Boolean = { text -> text.isEmpty() } val lambda3: (Int, Int) -> Int = { x, y -> x + y }
  36. Lambdas val lambda1: (String) -> Unit = { text ->

    println(text) } val lambda2: (String) -> Boolean = { text -> text.isEmpty() } val lambda3: (Int, Int) -> Int = { x, y -> x + y }
  37. Lambdas val lambda1: (String) -> Unit = { println(it) }

    val lambda2: (String) -> Boolean = { it.isEmpty() } val lambda3: (Int, Int) -> Int = { x, y -> x + y }
  38. Lambdas val lambda1: (String) -> Unit = { println(it) }

    val lambda2: (String) -> Boolean = { it.isEmpty() } val lambda3: (Int, Int) -> Int = { x, y -> x + y } val a = lambda3(2, 5)
  39. Higher-Order Functions fun String.isValid(validator: (String) -> Boolean) = validator(this) val

    noDigits: (String) -> Boolean = { !it.contains("\\d".toRegex()) } val allCapital: (String) -> Boolean = { it.matches("^[^a-z]*\$".toRegex()) } val peselNumber: (String) -> Boolean = { checkPesel(it) }
  40. Higher-Order Functions fun String.isValid(validator: (String) -> Boolean) = validator(this) val

    noDigits: (String) -> Boolean = { !it.contains("\\d".toRegex()) } val allCapital: (String) -> Boolean = { it.matches("^[^a-z]*\$".toRegex()) } val peselNumber: (String) -> Boolean = { checkPesel(it) } "Reksio".isValid(noDigits) "PL".isValid(allCapital) "88061423471".isValid(peselNumber)
  41. Higher-Order Functions fun String.isValid(validator: (String) -> Boolean) = validator(this) val

    noDigits: (String) -> Boolean = { !it.contains("\\d".toRegex()) } val allCapital: (String) -> Boolean = { it.matches("^[^a-z]*\$".toRegex()) } val peselNumber: (String) -> Boolean = { checkPesel(it) } "Reksio".isValid(noDigits) "PL".isValid(allCapital) "88061423471".isValid(peselNumber) "1945".isValid({ it.matches("\\d{4}".toRegex()) })
  42. Higher-Order Functions fun String.isValid(validator: (String) -> Boolean) = validator(this) val

    noDigits: (String) -> Boolean = { !it.contains("\\d".toRegex()) } val allCapital: (String) -> Boolean = { it.matches("^[^a-z]*\$".toRegex()) } val peselNumber: (String) -> Boolean = { checkPesel(it) } "Reksio".isValid(noDigits) "PL".isValid(allCapital) "88061423471".isValid(peselNumber) "1945".isValid({ it.matches("\\d{4}".toRegex()) })
  43. Higher-Order Functions fun String.isValid(validator: (String) -> Boolean) = validator(this) val

    noDigits: (String) -> Boolean = { !it.contains("\\d".toRegex()) } val allCapital: (String) -> Boolean = { it.matches("^[^a-z]*\$".toRegex()) } val peselNumber: (String) -> Boolean = { checkPesel(it) } "Reksio".isValid(noDigits) "PL".isValid(allCapital) "88061423471".isValid(peselNumber) "1945".isValid() { it.matches("\\d{4}".toRegex()) }
  44. Higher-Order Functions fun String.isValid(validator: (String) -> Boolean) = validator(this) val

    noDigits: (String) -> Boolean = { !it.contains("\\d".toRegex()) } val allCapital: (String) -> Boolean = { it.matches("^[^a-z]*\$".toRegex()) } val peselNumber: (String) -> Boolean = { checkPesel(it) } "Reksio".isValid(noDigits) "PL".isValid(allCapital) "88061423471".isValid(peselNumber) "1945".isValid() { it.matches("\\d{4}".toRegex()) }
  45. Higher-Order Functions fun String.isValid(validator: (String) -> Boolean) = validator(this) val

    noDigits: (String) -> Boolean = { !it.contains("\\d".toRegex()) } val allCapital: (String) -> Boolean = { it.matches("^[^a-z]*\$".toRegex()) } val peselNumber: (String) -> Boolean = { checkPesel(it) } "Reksio".isValid(noDigits) "PL".isValid(allCapital) "88061423471".isValid(peselNumber) "1945".isValid { it.matches("\\d{4}".toRegex()) }
  46. Higher-Order Functions fun <T, R> List<T>.map(func: (T) -> R): List<R>

    { val result = ArrayList<R>() for (element in this) { result.add(func(element)) } return result }
  47. Higher-Order Functions fun <T, R> List<T>.map(func: (T) -> R): List<R>

    { val result = ArrayList<R>() for (element in this) { result.add(func(element)) } return result } val names = listOf("Reksio", "Burek", "Falafel") val nameLengths = names.map { it.length } // [6, 5, 7]
  48. Higher-Order Functions inline fun <T, R> List<T>.map(func: (T) -> R):

    List<R> + val names = listOf("Reksio", "Burek", "Falafel") val nameLengths = names.map { it.length }
  49. Higher-Order Functions inline fun <T, R> List<T>.map(func: (T) -> R):

    List<R> + val names = listOf("Reksio", "Burek", "Falafel") val nameLengths = names.map { it.length } = val names = listOf("Reksio", "Burek", "Falafel") val nameLengths: List<Int> val result = ArrayList<Int>() for (name in names) { result.add(name.length) } nameLengths = result
  50. Higher-Order Functions val names = listOf("Reksio", "Burek", "Falafel", "") val

    twoBiggestNonEmptyNameLengths = names .filter(String::isNotEmpty) // ["Reksio", "Burek", "Falafel"]
  51. Higher-Order Functions val names = listOf("Reksio", "Burek", "Falafel", "") val

    twoBiggestNonEmptyNameLengths = names .filter(String::isNotEmpty) // ["Reksio", "Burek", "Falafel"] .map { it.length } // [6, 5, 7]
  52. Higher-Order Functions val names = listOf("Reksio", "Burek", "Falafel", "") val

    twoBiggestNonEmptyNameLengths = names .filter(String::isNotEmpty) // ["Reksio", "Burek", "Falafel"] .map { it.length } // [6, 5, 7] .sorted() // [5, 6, 7]
  53. Higher-Order Functions val names = listOf("Reksio", "Burek", "Falafel", "") val

    twoBiggestNonEmptyNameLengths = names .filter(String::isNotEmpty) // ["Reksio", "Burek", "Falafel"] .map { it.length } // [6, 5, 7] .sorted() // [5, 6, 7] .takeLast(2) // [6, 7]
  54. Lambdas With Receivers val preferences: SharedPreferences preferences.edit() .putString("Dog", "Burek") .putBoolean("isGoodBoy",

    true) .remove("Owner") .apply() preferences.edit { putString("Dog", "Burek") putBoolean("isGoodBoy", true) remove("Owner") }
  55. Lambdas With Receivers inline fun SharedPreferences.edit(action: (SharedPreferences.Editor) -> Unit) {

    val editor = edit() action(editor) editor.apply() } preferences.edit { editor -> editor.putString("Dog", "Burek") .putBoolean("isGoodBoy", true) .remove("Owner") }
  56. Lambdas With Receivers inline fun SharedPreferences.edit(action: (SharedPreferences.Editor) -> Unit) {

    val editor = edit() action(editor) editor.apply() } preferences.edit { it.putString("Dog", "Burek") .putBoolean("isGoodBoy", true) .remove("Owner") }
  57. Lambdas With Receivers inline fun SharedPreferences.edit(action: (SharedPreferences.Editor) -> Unit) {

    val editor = edit() action(editor) editor.apply() } preferences.edit { it.putString("Dog", "Burek") .putBoolean("isGoodBoy", true) .remove("Owner") }
  58. Lambdas With Receivers inline fun SharedPreferences.edit(action: SharedPreferences.Editor.() -> Unit) {

    val editor = edit() editor.action() editor.apply() } preferences.edit { this.putString("Dog", "Burek") .putBoolean("isGoodBoy", true) .remove("Owner") }
  59. Lambdas With Receivers inline fun SharedPreferences.edit(action: SharedPreferences.Editor.() -> Unit) {

    val editor = edit() editor.action() editor.apply() } preferences.edit { this.putString("Dog", "Burek") this.putBoolean("isGoodBoy", true) this.remove("Owner") }
  60. Lambdas With Receivers inline fun SharedPreferences.edit(action: SharedPreferences.Editor.() -> Unit) {

    val editor = edit() editor.action() editor.apply() } preferences.edit { this.putString("Dog", "Burek") this.putBoolean("isGoodBoy", true) this.remove("Owner") }
  61. Lambdas With Receivers inline fun SharedPreferences.edit(action: SharedPreferences.Editor.() -> Unit) {

    val editor = edit() editor.action() editor.apply() } preferences.edit { putString("Dog", "Burek") putBoolean("isGoodBoy", true) remove("Owner") }
  62. Lambdas With Receivers html { head("Page title") { meta {

    httpEquiv = "Content-type" content = "text/html; charset=iso-8859-2" } meta { name = "Author" content = "Cygnus" } } body { h1("Heading") p("Paragraph") } }
  63. Lambdas With Receivers login { username("Burek") password("") } submit {

    isInvalidPassword() } login { username("Burek") password("haslo") } submit { isWelcomeScreen() }
  64. Resources • Website and documentation: https://kotlinlang.org/ • Online course: https://try.kotlinlang.org/

    • Podcast: http://talkingkotlin.com/ • Slack: http://slack.kotlinlang.org/ • Reddit: https://www.reddit.com/r/Kotlin/ • Kotlin conference: https://kotlinconf.com/ • Twitter: @kotlin, @intelliyole, @hhariri, @JakeWharton, @RunChristinaRun • Plenty of materials on YouTube, Medium, etc.