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

Is Kotlin Right For You? - Chicago Java Users Group

Is Kotlin Right For You? - Chicago Java Users Group

Sure Java pays the bills for some of us, but there’s no reason why we can’t have fun developing again. Kotlin, developed by JetBrains, has been catching on lately because of its functional nature, null safety, 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 considering 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 22, 2018
Tweet

More Decks by Todd Ginsberg

Other Decks in Technology

Transcript

  1. Is Kotlin
    Right For You?
    Chicago Java User Group
    2018-03-22
    Todd Ginsberg
    @ToddGinsberg
    Principal Software Developer

    View full-size slide

  2. @ToddGinsberg
    Who Is This Person?
    Todd Ginsberg
    Principal Software Developer @Netspend
    (a payments company in Austin, TX)
    Java developer since 1995
    Kotlin developer since 2016
    Chicago Java User Group CFO

    View full-size slide

  3. @ToddGinsberg
    What’s in a Name?
    By Editors of Open Street Map - Open Street Map, CC BY-SA
    Kotlin Island

    View full-size slide

  4. @ToddGinsberg
    Hiding The Real Reason?

    View full-size slide

  5. @ToddGinsberg
    But First…
    I
    Java

    View full-size slide

  6. @ToddGinsberg
    Agenda
    1.What is Kotlin?
    2.Syntax and Code
    3.Community
    4.Summary / Wrap-up

    View full-size slide

  7. @ToddGinsberg
    What Is Kotlin?

    View full-size slide

  8. @ToddGinsberg
    What Is Kotlin?
    Statically typed JVM language, developed by JetBrains
    Released under Apache 2.0 license
    JVM 6 or 8 bytecode
    Also targets ECMAScript 5.1
    LLVM compiler can compile to native

    View full-size slide

  9. @ToddGinsberg
    Major Features
    100% interoperable with Java
    Very easy to learn
    Type Inference
    More than diamond operator or local var (thanks Java 10!)
    Null-safe
    168,000+ issues on GitHub!
    10,579 duplicates on Stack Overflow!
    Fantastic IDE support
    Large, positive community

    View full-size slide

  10. @ToddGinsberg
    Kotlin Adoption

    View full-size slide

  11. @ToddGinsberg
    Supported on Android

    View full-size slide

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

    View full-size slide

  13. @ToddGinsberg
    Supported in Gradle

    View full-size slide

  14. @ToddGinsberg
    Syntax

    View full-size slide

  15. @ToddGinsberg
    Variables and Values
    var place: String = "Chicago"
    place = "Illinois" // OK!
    val name: String = "Todd"
    name = "Emma" // Compile Error!

    View full-size slide

  16. @ToddGinsberg
    Type Inference
    val d: Int = 2
    val description: String = "Todd has $d doughnuts"

    View full-size slide

  17. @ToddGinsberg
    val d = 2
    val description = "Todd has $d doughnuts"
    Type Inference

    View full-size slide

  18. @ToddGinsberg
    Equality
    val name1 = "EXAMPLE"
    val name2 = "example"
    // Structural Equality
    name1 == name2.toUpperCase() // True!
    // Referential Equality
    name1 === name2 // False!
    // Unfortunately…
    name1 ==== name2 // Compiler Error L

    View full-size slide

  19. @ToddGinsberg
    Raw Strings
    val json = "{\n\"name\": \"Todd\"\n}”
    val json =
    """
    {
    "name": "Todd"
    }
    """

    View full-size slide

  20. @ToddGinsberg
    Null Safety
    // Guaranteed to never be null
    val name: String = "Todd"
    // May be null
    val salary: Int? = null

    View full-size slide

  21. @ToddGinsberg
    var city: String? = "Chicago"
    // Not allowed, might be null!
    city.toUpperCase()
    // Safe traversal
    city?.toUpperCase()
    Null-safe Traversal

    View full-size slide

  22. @ToddGinsberg
    val lowest : Int? = listOf(1, 2, 3).min()
    val lowest : Int = listOf(1, 2, 3).min() ?: 0
    Elvis

    View full-size slide

  23. @ToddGinsberg
    Combine Safe-Traversal and Elvis
    println(
    city?.toUpperCase() ?: ”UNKNOWN”
    )

    View full-size slide

  24. @ToddGinsberg
    val lowest: Int? = listOf(1, 2, 3).min()
    val lowest: Int = listOf(1, 2, 3).min()!!
    val lowest: Int = emptyList().min()!!
    // KotlinNullPointerException! L
    Manual Override

    View full-size slide

  25. @ToddGinsberg
    Null Safety
    Remember the names!
    ?. == Safe Traversal
    ?: == Elvis
    !! == Hold My Beer

    View full-size slide

  26. @ToddGinsberg
    Expressions – if
    val status = if (code == 42) {
    "Success"
    } else {
    "Fail"
    }

    View full-size slide

  27. @ToddGinsberg
    Expressions – try/catch
    val number = try {
    code.toInt()
    } catch (e: NumberFormatException) {
    0
    }

    View full-size slide

  28. @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”
    parseString(s) -> "the same as parseString”
    else -> "x doesn't match anything"
    }

    View full-size slide

  29. @ToddGinsberg
    when (x) {
    is Int -> print(x % 2 == 0)
    is String -> print(x.length + 1)
    is IntArray -> print(x.sum())
    }
    if(x != null) {
    println(x.toString())
    }
    Smart Casting

    View full-size slide

  30. @ToddGinsberg
    Classes
    class Entity : SomeInterface {
    // ...
    }

    View full-size slide

  31. @ToddGinsberg
    Classes - Inheritance
    open class Entity : SomeInterface {
    // ...
    }
    class Customer : Entity() {
    // ...
    }

    View full-size slide

  32. @ToddGinsberg
    Classes - Construction
    class Entity(type: String) {
    val description = "$type Entity"
    init {
    println("I am constructing a $type Entity")
    }
    }

    View full-size slide

  33. @ToddGinsberg
    Properties
    class Customer(var name: String) {
    var state: String? = null
    }
    val c = Customer("Todd")
    c.state = "IL"
    println("${c.name} from ${c.state}")
    // "Todd from IL"

    View full-size slide

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

    View full-size slide

  35. @ToddGinsberg
    Properties – Set
    class Customer(var name: String) {
    var state: String? = null
    private set(value) {
    field = value?.toUpperCase()
    }
    }

    View full-size slide

  36. @ToddGinsberg
    Properties – GET
    class Customer(var name: String) {
    var state: String? = null
    get() {
    return field?.toUpperCase()
    }
    }

    View full-size slide

  37. @ToddGinsberg
    Property Delegation
    class Country {
    val gdp: Int = slowCalculation()
    }
    class Country {
    val gdp: Int by lazy {
    slowCalculation()
    }
    }

    View full-size slide

  38. @ToddGinsberg
    Class Delegation
    // Java
    class MyJavaImpl implements HugeInterface {
    private final HugeInterface backing;
    public MyJavaImpl(HugeInterface hi) {
    backing = hi;
    }
    // IMPLEMENT EVERYTHING
    }

    View full-size slide

  39. @ToddGinsberg
    Class Delegation
    // Java
    class MyJavaImpl extends SomeImplementation {
    // Implement Some
    }

    View full-size slide

  40. @ToddGinsberg
    Class Delegation
    // Kotlin
    class MyImpl(h: HugeInterface) : HugeInterface by h
    {
    // Implement Some
    }

    View full-size slide

  41. @ToddGinsberg
    Sealed Classes
    sealed class Message
    class StartServer(val name: String) : Message()
    class StopServer(val name: String) : Message()
    object CountServers : Message()

    View full-size slide

  42. @ToddGinsberg
    Sealed Classes
    val response = when(msg) {
    is StartServer -> startServer(msg.name)
    is StopServer -> stopServer(msg.name)
    is CountServers -> countServers()
    }

    View full-size slide

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

    View full-size slide

  44. @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;
    }
    }

    View full-size slide

  45. @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;
    }
    }

    View full-size slide

  46. @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);
    }
    }

    View full-size slide

  47. @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 + '\'' +
    '}';
    }
    }

    View full-size slide

  48. @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…

    View full-size slide

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

    View full-size slide

  50. @ToddGinsberg
    Destructuring Data Classes
    val me = Person("Todd", "Ginsberg")
    val (first, last) = me
    // first == “Todd” last == “Ginsberg”

    View full-size slide

  51. @ToddGinsberg
    FUNctions!
    fun generateRandomNumber(): Int {
    return 4
    }
    fun generateRandomNumber(): Int = 4
    fun generateRandomNumber() = 4

    View full-size slide

  52. @ToddGinsberg
    FUNctions – Default Values
    fun random(offset: Int = 0): Int =
    offset + 4
    random() // 4
    random(1) // 5

    View full-size slide

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

    View full-size slide

  54. @ToddGinsberg
    FUNctions – Named & Default
    fun combine(first: Int,
    second: Int,
    third: Int = 0): Int =
    first + second + third
    combine(1, 2) // 3
    combine(second = 2, first = 1, third = 3) // 6

    View full-size slide

  55. @ToddGinsberg
    FUNction Names
    @Test
    fun `Replicants have a four year lifespan!`() {
    // ...
    }
    @Test
    fun replicantsHaveAFourYearLifespan() {
    // ...
    }

    View full-size slide

  56. @ToddGinsberg
    class Message {
    fun sendTo(recv: Receiver): Unit = // ...
    }
    val message = Message()
    val receiver = Receiver()
    message.sendTo(receiver)
    FUNctions – Infix

    View full-size slide

  57. @ToddGinsberg
    FUNctions – Infix
    class Message {
    infix fun sendTo(recv: Receiver): Unit = // ...
    }
    val message = Message()
    val receiver = Receiver()
    message.sendTo(receiver)
    message sendTo receiver

    View full-size slide

  58. @ToddGinsberg
    Operator Overloading
    Limited overloading – cannot define your own 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)

    View full-size slide

  59. @ToddGinsberg
    Operator Overloading
    Limited overloading – cannot define your own operators.
    Expression Translated to
    a in b b.contains(a)
    a !in b !b.contains(a)

    View full-size slide

  60. @ToddGinsberg
    Operator Overloading
    Limited overloading – cannot define your own operators.
    Expression Translated to
    a[i] a.get(i)
    a[i] = b a.set(i, b)

    View full-size slide

  61. @ToddGinsberg
    Operator Overloading
    Limited overloading – cannot define your own 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)

    View full-size slide

  62. @ToddGinsberg
    Operator Overloading
    Limited overloading – cannot define your own 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

    View full-size slide

  63. @ToddGinsberg
    fun measureTimeMillis(block: () -> Unit): Long {
    val start = System.currentTimeMillis()
    block()
    return System.currentTimeMillis() - start
    }
    val time = measureTimeMillis {
    someSlowQuery()
    }
    High Order FUNctions

    View full-size slide

  64. @ToddGinsberg
    Extension FUNctions
    // Java
    public static boolean isEven(int i) {
    return i % 2 == 0;
    }
    // Kotlin
    fun Int.isEven(): Boolean = this % 2 == 0
    2.isEven() // True!

    View full-size slide

  65. @ToddGinsberg
    The apply Extension
    // Expression and Statements
    val p = Person()
    p.name = "Todd"
    p.age = 21
    // Single Expression
    val p = Person().apply {
    name = "Todd"
    age = 21
    }

    View full-size slide

  66. @ToddGinsberg
    The use Extension
    // Java
    try (DatabaseConnection conn = getConnection()) {
    // ...
    }
    // Kotlin
    getConnection().use { conn ->
    // ...
    }

    View full-size slide

  67. @ToddGinsberg
    One More Thing On FUNctions…
    Functions are final by default.
    Functions can be defined in a file, outside of a class.
    Functions can be defined within another function.
    Kotlin supports tail recursive functions.

    View full-size slide

  68. @ToddGinsberg
    What About Checked Exceptions?
    NO

    View full-size slide

  69. @ToddGinsberg
    What About Static?
    class MyClass {
    companion object {
    fun fromDto(dto: MyClassDto): MyClass =
    // Create logic here...
    }
    }
    // Elsewhere…
    val instance = MyClass.fromDto(someDto)

    View full-size slide

  70. @ToddGinsberg
    What About Static?
    object Constants {
    val PREFIX_CODE = 16309
    }
    // Elsewhere…
    transmit(Constants.PREFIX_CODE)
    Can include functions
    Can implement interfaces

    View full-size slide

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

    View full-size slide

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

    View full-size slide

  73. @ToddGinsberg
    Lambdas Are Closures
    val ints = listOf(1, 2, 3, 4)
    var sum = 0
    ints.forEach { sum += it }
    println(sum) // 10

    View full-size slide

  74. @ToddGinsberg
    The Nothing Type
    Nothing has no instances. You can use Nothing to represent "a value
    that never exists”…
    fun TODO(): Nothing = throw NotImplementedError()
    override fun mustOverrideToCompile() = TODO()

    View full-size slide

  75. @ToddGinsberg
    Type Aliases
    fun doSomethingWithMap(
    ops: Map>
    ) {
    ops.entries // ...
    }

    View full-size slide

  76. @ToddGinsberg
    Type Aliases
    typealias Operations = Map>
    fun doSomethingWithMap(ops: Operations) {
    ops.entries // …
    }

    View full-size slide

  77. @ToddGinsberg
    Import Aliases
    import java.util.Date
    import java.sql.Date

    View full-size slide

  78. @ToddGinsberg
    Import Aliases
    import java.util.Date as UtilDate
    import java.sql.Date as SqlDate

    View full-size slide

  79. @ToddGinsberg
    Reified Generics
    // Ugly
    val log = Logger.getLogger(Metrics::class.java)
    // What I want
    val log = loggerOf()

    View full-size slide

  80. @ToddGinsberg
    // Thanks type erasure L
    fun loggerOf(): Logger =
    Logger.getLogger(T::class.java)
    Reified Generics

    View full-size slide

  81. @ToddGinsberg
    inline fun loggerOf(): Logger =
    Logger.getLogger(T::class.java)
    // Works!
    val log = loggerOf()
    Reified Generics

    View full-size slide

  82. @ToddGinsberg
    Community

    View full-size slide

  83. @ToddGinsberg
    Community Resources
    https://kotlinlang.slack.com
    • 15,000+ members
    • Get answers and chat with people who work with the language
    • Welcoming and helpful
    • Language authors hang out here
    Stack Overflow
    • Actually get meaningful answers
    • Not uncommon to get many useful answers
    • Language authors here as well

    View full-size slide

  84. @ToddGinsberg
    Community
    KΛTEGORY funKTionale
    Λrrow

    View full-size slide

  85. @ToddGinsberg
    Try Kotlin!
    https://try.kotlinlang.org

    View full-size slide

  86. @ToddGinsberg
    Fun == Fun
    Kotlin
    Thanks, Stack Overflow!

    View full-size slide

  87. @ToddGinsberg
    Summary

    View full-size slide

  88. @ToddGinsberg
    Why Kotlin is Right For Me
    I write far less code.
    The code I write is more expressive and clear.
    Allows me to write in a more functional style.
    Writing Kotlin, for me, is more fun.
    Plays well with the tools I already use (Spring, IDEA, Gradle)

    View full-size slide

  89. @ToddGinsberg
    Is Kotlin is Right For You?

    View full-size slide

  90. Than You!
    @ToddGinsberg
    https://todd.ginsberg.com

    View full-size slide