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.

2777430c1f9869e411ab5d8b17d8ba2a?s=128

Todd Ginsberg

March 22, 2018
Tweet

Transcript

  1. Is Kotlin Right For You? Chicago Java User Group 2018-03-22

    Todd Ginsberg @ToddGinsberg Principal Software Developer
  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
  3. @ToddGinsberg What’s in a Name? By Editors of Open Street

    Map - Open Street Map, CC BY-SA Kotlin Island
  4. @ToddGinsberg Hiding The Real Reason?

  5. @ToddGinsberg But First… I Java

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

    / Wrap-up
  7. @ToddGinsberg What Is Kotlin?

  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
  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
  10. @ToddGinsberg Kotlin Adoption

  11. @ToddGinsberg Supported on Android

  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
  13. @ToddGinsberg Supported in Gradle

  14. @ToddGinsberg Syntax

  15. @ToddGinsberg Variables and Values var place: String = "Chicago" place

    = "Illinois" // OK! val name: String = "Todd" name = "Emma" // Compile Error!
  16. @ToddGinsberg Type Inference val d: Int = 2 val description:

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

    $d doughnuts" Type Inference
  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
  19. @ToddGinsberg Raw Strings val json = "{\n\"name\": \"Todd\"\n}” val json

    = """ { "name": "Todd" } """
  20. @ToddGinsberg Null Safety // Guaranteed to never be null val

    name: String = "Todd" // May be null val salary: Int? = null
  21. @ToddGinsberg var city: String? = "Chicago" // Not allowed, might

    be null! city.toUpperCase() // Safe traversal city?.toUpperCase() Null-safe Traversal
  22. @ToddGinsberg val lowest : Int? = listOf(1, 2, 3).min() val

    lowest : Int = listOf(1, 2, 3).min() ?: 0 Elvis
  23. @ToddGinsberg Combine Safe-Traversal and Elvis println( city?.toUpperCase() ?: ”UNKNOWN” )

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

    Int = listOf(1, 2, 3).min()!! val lowest: Int = emptyList<Int>().min()!! // KotlinNullPointerException! L Manual Override
  25. @ToddGinsberg Null Safety Remember the names! ?. == Safe Traversal

    ?: == Elvis !! == Hold My Beer
  26. @ToddGinsberg Expressions – if val status = if (code ==

    42) { "Success" } else { "Fail" }
  27. @ToddGinsberg Expressions – try/catch val number = try { code.toInt()

    } catch (e: NumberFormatException) { 0 }
  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" }
  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
  30. @ToddGinsberg Classes class Entity : SomeInterface { // ... }

  31. @ToddGinsberg Classes - Inheritance open class Entity : SomeInterface {

    // ... } class Customer : Entity() { // ... }
  32. @ToddGinsberg Classes - Construction class Entity(type: String) { val description

    = "$type Entity" init { println("I am constructing a $type Entity") } }
  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"
  34. @ToddGinsberg Properties – Set class Customer(var name: String) { var

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

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

    state: String? = null get() { return field?.toUpperCase() } }
  37. @ToddGinsberg Property Delegation class Country { val gdp: Int =

    slowCalculation() } class Country { val gdp: Int by lazy { slowCalculation() } }
  38. @ToddGinsberg Class Delegation // Java class MyJavaImpl implements HugeInterface {

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

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

    by h { // Implement Some }
  41. @ToddGinsberg Sealed Classes sealed class Message class StartServer(val name: String)

    : Message() class StopServer(val name: String) : Message() object CountServers : Message()
  42. @ToddGinsberg Sealed Classes val response = when(msg) { is StartServer

    -> startServer(msg.name) is StopServer -> stopServer(msg.name) is CountServers -> countServers() }
  43. @ToddGinsberg Let’s Write a POJO! public class Person { public

    String firstName; public String lastName; }
  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; } }
  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; } }
  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); } }
  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 + '\'' + '}'; } }
  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…
  49. @ToddGinsberg Copying Data Classes val me = Person("Todd", "Ginsberg") val

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

    (first, last) = me // first == “Todd” last == “Ginsberg”
  51. @ToddGinsberg FUNctions! fun generateRandomNumber(): Int { return 4 } fun

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

    Int = offset + 4 random() // 4 random(1) // 5
  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
  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
  55. @ToddGinsberg FUNction Names @Test fun `Replicants have a four year

    lifespan!`() { // ... } @Test fun replicantsHaveAFourYearLifespan() { // ... }
  56. @ToddGinsberg class Message { fun sendTo(recv: Receiver): Unit = //

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

    Receiver): Unit = // ... } val message = Message() val receiver = Receiver() message.sendTo(receiver) message sendTo receiver
  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)
  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)
  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)
  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)
  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
  63. @ToddGinsberg fun measureTimeMillis(block: () -> Unit): Long { val start

    = System.currentTimeMillis() block() return System.currentTimeMillis() - start } val time = measureTimeMillis { someSlowQuery() } High Order FUNctions
  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!
  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 }
  66. @ToddGinsberg The use Extension // Java try (DatabaseConnection conn =

    getConnection()) { // ... } // Kotlin getConnection().use { conn -> // ... }
  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.
  68. @ToddGinsberg What About Checked Exceptions? NO

  69. @ToddGinsberg What About Static? class MyClass { companion object {

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

    16309 } // Elsewhere… transmit(Constants.PREFIX_CODE) Can include functions Can implement interfaces
  71. @ToddGinsberg listOf(1, 2, 3, 4) .filter { x -> x

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

    2 == 0 } .map { it * 2 } // List[4, 8]
  73. @ToddGinsberg Lambdas Are Closures val ints = listOf(1, 2, 3,

    4) var sum = 0 ints.forEach { sum += it } println(sum) // 10
  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()
  75. @ToddGinsberg Type Aliases fun doSomethingWithMap( ops: Map<SomeType, List<String>> ) {

    ops.entries // ... }
  76. @ToddGinsberg Type Aliases typealias Operations = Map<SomeType, List<String>> fun doSomethingWithMap(ops:

    Operations) { ops.entries // … }
  77. @ToddGinsberg Import Aliases import java.util.Date import java.sql.Date

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

    SqlDate
  79. @ToddGinsberg Reified Generics // Ugly val log = Logger.getLogger(Metrics::class.java) //

    What I want val log = loggerOf<Metrics>()
  80. @ToddGinsberg // Thanks type erasure L fun <T> loggerOf(): Logger

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

    Works! val log = loggerOf<Metrics>() Reified Generics
  82. @ToddGinsberg Community

  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
  84. @ToddGinsberg Community KΛTEGORY funKTionale Λrrow

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

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

  87. @ToddGinsberg Summary

  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)
  89. @ToddGinsberg Is Kotlin is Right For You?

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