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

An Introduction to Kotlin

An Introduction to Kotlin

Kotlin sure has been receiving a lot of buzz lately, is there something to it? Developed by JetBrains, Kotlin has been catching on lately because of its null safety guarantees, functional nature, type inference, full interoperability with Java, cross-platform support, and ease of use with Android and Spring. Is this something you and your team should consider spending time to learn? In this session we will go over what Kotlin is, what problems it solves, and what makes it stand out from other JVM languages. You’ll come away with enough knowledge to decide if this is something you and your team should consider adopting.

Todd Ginsberg

March 11, 2021
Tweet

More Decks by Todd Ginsberg

Other Decks in Programming

Transcript

  1. @ToddGinsberg What’s in a Name? Kotlin Island By Editors of

    Open Street Map - Open Street Map, CC BY-SA
  2. @ToddGinsberg Agenda - What Is Kotlin? - Am I Alone?

    - Syntax & Features - Summary - Questions and Possibly Answers
  3. @ToddGinsberg Who is this Guy? Todd Ginsberg Just moved to

    Raleigh from Chicago Research Architect at Netspend - A payments company in Austin, TX! - We love Kotlin and Java!
  4. @ToddGinsberg What Is Kotlin? Statically typed language, developed by JetBrains

    Released under Apache 2.0 license Designed as a general purpose language
  5. @ToddGinsberg What Is Kotlin? Statically typed language, developed by JetBrains

    Released under Apache 2.0 license Designed as a general purpose language • Targets Java bytecode down to JVM 6
  6. @ToddGinsberg What Is Kotlin? Statically typed language, developed by JetBrains

    Released under Apache 2.0 license Designed as a general purpose language • Targets Java bytecode down to JVM 6 • Targets ECMAScript 5.1
  7. @ToddGinsberg What Is Kotlin? Statically typed language, developed by JetBrains

    Released under Apache 2.0 license Designed as a general purpose language • Targets Java bytecode down to JVM 6 • Targets ECMAScript 5.1 • Targets other native platforms
  8. @ToddGinsberg Major Features 100% Interoperable with Java Designed to avoid

    entire classes of defects Lots of small improvements that add up
  9. @ToddGinsberg Major Features 100% Interoperable with Java Designed to avoid

    entire classes of defects Lots of small improvements that add up Far less code to accomplish the same task in Java - Less cognitive load on developers
  10. @ToddGinsberg Spring Framework Support Kotlin is fully supported since Spring

    Framework 5 Kotlin is an option on start.spring.io
  11. @ToddGinsberg Spring Framework Support Kotlin is fully supported since Spring

    Framework 5 Kotlin is an option on start.spring.io Spring @NotNull annotations == Better Kotlin nullability support
  12. @ToddGinsberg Spring Framework Support Kotlin is fully supported since Spring

    Framework 5 Kotlin is an option on start.spring.io Spring @NotNull annotations == Better Kotlin nullability support Comprehensive Kotlin documentation and examples
  13. @ToddGinsberg Variables and Values var place: String = "Greensboro" place

    = "North Carolina" // OK! val name: String = "Todd"
  14. @ToddGinsberg Variables and Values var place: String = "Greensboro" place

    = "North Carolina" // OK! val name: String = "Todd" name = "Emma" // Compile Error!
  15. @ToddGinsberg Equality val name1 = "EXAMPLE" val name2 = "example"

    // Structural Equality name1 == name2.toUpperCase() // True!
  16. @ToddGinsberg Equality val name1 = "EXAMPLE" val name2 = "example"

    // Structural Equality name1 == name2.toUpperCase() // True! // Referential Equality name1 === name2 // False!
  17. @ToddGinsberg Null Safety // Guaranteed to never be null var

    name: String = "Todd" // May be null var salary: Int? = null
  18. @ToddGinsberg Null-Safe Traversal var city: String? = "Greensboro" // Not

    allowed, might be null! city.toUpperCase() // Safe traversal city?.toUpperCase()
  19. @ToddGinsberg Elvis val lowest : Int? = listOf(1, 2, 3).min()

    val lowest : Int = listOf(1, 2, 3).min() ?: 0
  20. @ToddGinsberg Manual Override val lowest: Int? = listOf(1, 2, 3).min()

    val lowest: Int = listOf(1, 2, 3).min()!! val lowest: Int = emptyList<Int>().min()!!
  21. @ToddGinsberg Manual Override val lowest: Int? = listOf(1, 2, 3).min()

    val lowest: Int = listOf(1, 2, 3).min()!! val lowest: Int = emptyList<Int>().min()!! // NullPointerException!
  22. @ToddGinsberg Expressions - when val result = when (x) {

    0 -> "x is 0” in 1..10 -> "x is between 1 and 10" in someSet -> "x is in someSet" is SomeType -> "x is an instance of SomeType" parseString(s) -> "the same as parseString" else -> "x doesn't match anything" }
  23. @ToddGinsberg Smart Casting when (x) { is Int -> print(x

    % 2 == 0) is String -> print(x.length + 1) is IntArray -> print(x.sum()) }
  24. @ToddGinsberg Smart Casting when (x) { is Int -> print(x

    % 2 == 0) is String -> print(x.length + 1) is IntArray -> print(x.sum()) }
  25. @ToddGinsberg Classes - Inheritance open class Entity : SomeInterface {

    // ... } class Customer : Entity() { // ... }
  26. @ToddGinsberg Properties public class Customer { private String name; public

    String getName() { return name; } public void setName(final String name) { this.name = name; } }
  27. @ToddGinsberg Properties class Customer { var name: String? = null

    } val c = Customer() c.name = "Todd" println("My name is ${c.name}")
  28. @ToddGinsberg Properties class Customer { var name: String? = null

    set(value) { field = value?.toUpperCase() } }
  29. @ToddGinsberg Properties class Customer { var name: String? = null

    private set(value) { field = value?.toUpperCase() } }
  30. @ToddGinsberg Class Delegation // Java class MyJavaImpl implements HugeInterface {

    private final HugeInterface backing; public MyJavaImpl(HugeInterface hi) { backing = hi; } // IMPLEMENT EVERYTHING }
  31. @ToddGinsberg Let’s Write a POJO! public class Person { public

    String firstName; public String lastName; }
  32. @ToddGinsberg Let’s Write a POJO! public class Person { private

    String firstName; private String lastName; public String getFirstName() { return firstName; } public void setFirstName(final String firstName) { this.firstName = firstName; } public String getLastName() { return lastName; } public void setLastName(final String lastName) { this.lastName = lastName; } }
  33. @ToddGinsberg Let’s Write a POJO! public class Person { private

    String firstName; private String lastName; public Person() { } public Person(final String firstName, final String lastName) { this.firstName = firstName; this.lastName = lastName; } public String getFirstName() { return firstName; } public void setFirstName(final String firstName) { this.firstName = firstName; } public String getLastName() { return lastName; } public void setLastName(final String lastName) { this.lastName = lastName; } }
  34. @ToddGinsberg Let’s Write a POJO! import java.util.Objects; public class Person

    { private String firstName; private String lastName; public Person() { } public Person(final String firstName, final String lastName) { this.firstName = firstName; this.lastName = lastName; } public String getFirstName() { return firstName; } public void setFirstName(final String firstName) { this.firstName = firstName; } public String getLastName() { return lastName; } public void setLastName(final String lastName) { this.lastName = lastName; } @Override public boolean equals(final Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; final Person person = (Person) o; return Objects.equals(firstName, person.firstName) && Objects.equals(lastName, person.lastName); } @Override public int hashCode() { return Objects.hash(firstName, lastName); } }
  35. @ToddGinsberg Let’s Write a POJO! import java.util.Objects; public class Person

    { private String firstName; private String lastName; public Person() { } public Person(final String firstName, final String lastName) { this.firstName = firstName; this.lastName = lastName; } public String getFirstName() { return firstName; } public void setFirstName(final String firstName) { this.firstName = firstName; } public String getLastName() { return lastName; } public void setLastName(final String lastName) { this.lastName = lastName; } @Override public boolean equals(final Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; final Person person = (Person) o; return Objects.equals(firstName, person.firstName) && Objects.equals(lastName, person.lastName); } @Override public int hashCode() { return Objects.hash(firstName, lastName); } @Override public String toString() { return "Person{" + "firstName='" + firstName + '\'' + ", lastName='" + lastName + '\'' + '}'; } }
  36. @ToddGinsberg Data Classes to the Rescue! data class Person(val firstName:

    String, val lastName: String) • Getters (and Setters for vars) as Properties
  37. @ToddGinsberg Data Classes to the Rescue! data class Person(val firstName:

    String, val lastName: String) • Getters (and Setters for vars) as Properties • toString()
  38. @ToddGinsberg Data Classes to the Rescue! data class Person(val firstName:

    String, val lastName: String) • Getters (and Setters for vars) as Properties • toString() • hashCode() and equals()
  39. @ToddGinsberg Data Classes to the Rescue! data class Person(val firstName:

    String, val lastName: String) • Getters (and Setters for vars) as Properties • toString() • hashCode() and equals() • And…
  40. @ToddGinsberg Copying Data Classes val me = Person("Todd", "Ginsberg") val

    emma = me.copy(firstName = "Emma") // Person(”Emma", "Ginsberg")
  41. @ToddGinsberg Destructuring Data Classes val me = Person("Todd", "Ginsberg") val

    (first, last) = me // first == Todd // last == Ginsberg
  42. @ToddGinsberg Destructuring Data Classes val listOfPeople = listOf( Person("Todd", "Ginsberg"),

    Person("Emma", "Ginsberg") ) listOfPeople.forEach { (first, last) -> println("Found: $first $last") }
  43. @ToddGinsberg Destructuring Data Classes val listOfPeople = listOf( Person("Todd", "Ginsberg"),

    Person("Emma", "Ginsberg") ) listOfPeople.forEach { (first, _) -> println("Found: $first") }
  44. @ToddGinsberg Destructuring Data Classes val listOfPeople = listOf( Person("Todd", "Ginsberg"),

    Person("Emma", "Ginsberg") ) listOfPeople.forEach { (first, _) -> println("Found: $first") }
  45. @ToddGinsberg FUNctions! fun generateRandomNumber(): Int { return 4 } fun

    generateRandomNumber(): Int = 4 fun generateRandomNumber() = 4
  46. @ToddGinsberg FUNctions - Default Values fun random(offset: Int = 0):

    Int = offset + 4 random() // 4 random(1) // 5
  47. @ToddGinsberg FUNctions - Adding Parameters fun combine(first: Int, second: Int,

    third: Int = 0): Int = first + second + third combine(1, 2) combine(1, 2, 3)
  48. @ToddGinsberg FUNctions - Named Parameters fun combine(first: Int, second: Int):

    Int = first + second combine(first = 1, second = 2) // 3
  49. @ToddGinsberg FUNctions - Named Parameters fun combine(first: Int, second: Int):

    Int = first + second combine(second = 2, first = 1) // 3
  50. @ToddGinsberg Operator Overloading Limited to predefined operators! Expression Translated to

    a + b a.plus(b) a - b a.minus(b) a * b a.times(b) a / b a.div(b) a % b a.rem(b) a..b a.rangeTo(b)
  51. @ToddGinsberg Operator Overloading Limited to predefined operators! Expression Translated to

    a += b a.plusAssign(b) a -= b a.minusAssign(b) a *= b a.timesAssign(b) a /= b a.divAssign(b) a %= b a.remAssign(b)
  52. @ToddGinsberg Operator Overloading Limited to predefined operators! Expression Translated to

    a > b a.compareTo(b) > 0 a < b a.compareTo(b) < 0 a >= b a.compareTo(b) >= 0 a <= b a.compareTo(b) <= 0
  53. @ToddGinsberg The apply Extension // Expression and Statements val p

    = Person() p.name = "Dr. Robert Hume" p.age = 47
  54. @ToddGinsberg The apply Extension // Single Expression val p =

    Person().apply { name = "Dr. Robert Hume" age = 47 }
  55. @ToddGinsberg The apply Extension // Single Expression val p =

    Person().apply { name = "Dr. Robert Hume" age = 47 address = Address().apply { line1 = "5 Tall Cedar Rd." … } }
  56. @ToddGinsberg Higher-Order Functions fun measureTimeMillis(block: () -> Unit): Long {

    val start = System.currentTimeMillis() block() return System.currentTimeMillis() - start }
  57. @ToddGinsberg Higher-Order Functions fun measureTimeMillis(block: () -> Unit): Long {

    val start = System.currentTimeMillis() block() return System.currentTimeMillis() - start } val time = measureTimeMillis { someSlowQuery() }
  58. @ToddGinsberg One More Thing on FUNctions • Functions are final

    by default. • Arguments are always final.
  59. @ToddGinsberg One More Thing on FUNctions • Functions are final

    by default. • Arguments are always final. • Functions can be defined in a file, outside of a class.
  60. @ToddGinsberg One More Thing on FUNctions • Functions are final

    by default. • Arguments are always final. • Functions can be defined in a file, outside of a class. • Functions can be defined within another function.
  61. @ToddGinsberg One More Thing on FUNctions • Functions are final

    by default. • Arguments are always final. • Functions can be defined in a file, outside of a class. • Functions can be defined within another function. • Kotlin supports tail recursive functions.
  62. @ToddGinsberg Lambdas listOf(1, 2, 3, 4) .filter { x ->

    x % 2 == 0 } .map { y -> y * 2 } // List[4, 8]
  63. @ToddGinsberg Lambdas listOf(1, 2, 3, 4) .filter { x ->

    x % 2 == 0 } .map { y -> y * 2 } // List[4, 8]
  64. @ToddGinsberg Lambdas listOf(1, 2, 3, 4) .filter { it %

    2 == 0 } .map { it * 2 } // List[4, 8]
  65. @ToddGinsberg Reified Generics // Thanks type erasure :( fun <T>

    loggerOf(): Logger = Logger.getLogger(T::class.java)
  66. @ToddGinsberg Reified Generics inline fun <reified T> loggerOf(): Logger =

    Logger.getLogger(T::class.java) // Works! val log = loggerOf<Metrics>()
  67. @ToddGinsberg So Many Things Left Out! :( - Companion objects

    - Massive STDLIB replaces your util classes - Inline classes - Sealed classes - Unsigned integers - Coroutines - DSL support - Contracts - Infix functions
  68. @ToddGinsberg Make “Bad” Choices Explicit or Impossible Fixed in Kotlin:

    - Singleton support built in - Override keyword mandatory - Properties over fields with getter/setter - Mutability is minimized (val + collections) - Inheritance prohibited by default - Builders are easy with default values - No checked exceptions - Structural equality is the same everywhere - Delegation support makes composition easier
  69. @ToddGinsberg Why Do I Use Kotlin? • I write far

    less code • The code I write is more expressive and clear
  70. @ToddGinsberg Why Do I Use Kotlin? • I write far

    less code • The code I write is more expressive and clear • I avoid whole classes of defects
  71. @ToddGinsberg Why Do I Use Kotlin? • I write far

    less code • The code I write is more expressive and clear • I avoid whole classes of defects • Allows me to write in a more functional style
  72. @ToddGinsberg Why Do I Use Kotlin? • I write far

    less code • The code I write is more expressive and clear • I avoid whole classes of defects • Allows me to write in a more functional style • Plays well with the tools I use (Spring, IDEA, Gradle)
  73. @ToddGinsberg Why Do I Use Kotlin? • I write far

    less code • The code I write is more expressive and clear • I avoid whole classes of defects • Allows me to write in a more functional style • Plays well with the tools I use (Spring, IDEA, Gradle) • Writing Kotlin, for me, is more fun
  74. @ToddGinsberg Quantified Fun! % of developers who are developing with

    the language or technology but have not expressed interest in continuing to do so (Stack Overflow Developer Survey)
  75. @ToddGinsberg Quantified Fun! % of developers who are developing with

    the language or technology but have not expressed interest in continuing to do so (Stack Overflow Developer Survey) Kotlin