An Introduction to Kotlin

An Introduction to Kotlin

Kotlin has been catching on lately as an alternative to Java because of its null safety guarantees, type inference, cross-platform support, and ease of use with Android and Spring. Not to mention the fact that it is fully interoperable with Java. Is this something you and your team should considering spending time to learn? Come to this session for an overview of Kotlin intended for Java developers (don't worry if you don't know Java, Kotlin is very easy to learn!). We will go over the major language features, syntax, and the Kotlin ecosystem so you'll know enough to make your own decisions by the end. You will come away from this session with enough knowledge to decide if this is something you and your team should consider adopting.

2777430c1f9869e411ab5d8b17d8ba2a?s=128

Todd Ginsberg

July 18, 2019
Tweet

Transcript

  1. 1.

    An Introduction To Kotlin Kansas City Developer Conference 2019 2019-07-18

    Todd Ginsberg ` @ToddGinsberg Principal Software Developer
  2. 3.

    @ToddGinsberg What’s in a Name? By Editors of Open Street

    Map - Open Street Map, CC BY-SA Kotlin Island
  3. 5.

    @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 Board Member and CFO
  4. 6.

    @ToddGinsberg Agenda 1.What is Kotlin? 2.Am I Alone? 3.Syntax and

    Code 4.Community 5.Summary / Wrap-up 6.Q & A
  5. 8.

    @ToddGinsberg What Is Kotlin? Statically typed language, developed by JetBrains

    Released under Apache 2.0 license Designed as a general purpose language • Targets JVM bytecode 6 through 12 • Targets ECMAScript 5.1 • Targets native thanks to LLVM
  6. 9.

    @ToddGinsberg Major Features 100% interoperable with Java Very easy to

    learn Fantastic IDE support Large, positive community Pragmatic – No shame in copying language features that make developers more productive
  7. 10.

    @ToddGinsberg Major Features Designed to avoid entire classes of defects

    Null-safe 186,000+ issues on GitHub! 14,110 duplicates on Stack Overflow! Type Inference More than diamond operator or local var (thanks Java 10!)
  8. 15.

    @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
  9. 18.

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

    = "Illinois" // OK! val name: String = "Todd" name = "Emma" // Compile Error!
  10. 20.
  11. 21.

    @ToddGinsberg Equality val name1 = "EXAMPLE" val name2 = "example"

    // Structural Equality name1 == name2.toUpperCase() // True! // Referential Equality name1 === name2 // False!
  12. 22.

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

    = """ { "name": "Todd" } """ val json = """{ "name": "Todd" }"""
  13. 23.

    @ToddGinsberg Null Safety // Guaranteed to never be null val

    name: String = "Todd" // May be null val salary: Int? = null
  14. 24.

    @ToddGinsberg var city: String? = "Chicago" // Not allowed, might

    be null! city.toUpperCase() // Safe traversal city?.toUpperCase() Null-safe Traversal
  15. 25.

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

    lowest : Int = listOf(1, 2, 3).min() ?: 0 Elvis
  16. 27.

    @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
  17. 29.
  18. 31.

    @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" }
  19. 32.

    @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
  20. 34.

    @ToddGinsberg Classes - Inheritance open class Entity : SomeInterface {

    // ... } class Customer : Entity() { // ... }
  21. 35.

    @ToddGinsberg Properties public class Customer { private String name; public

    String getName() { return name; } public void setName(final String name) { this.name = name; } }
  22. 36.

    @ToddGinsberg Properties class Customer { var name: String? = null

    } val c = Customer() c.name = "Todd" println("My name is ${c.name}")
  23. 38.

    @ToddGinsberg Properties class Customer { var name: String? = null

    set(value) { field = value?.toUpperCase() } }
  24. 39.

    @ToddGinsberg Properties class Customer { var name: String? = null

    private set(value) { field = value?.toUpperCase() } }
  25. 40.
  26. 41.

    @ToddGinsberg Property Delegation class Country { val gdp: Int =

    slowCalculation() } class Country { val gdp: Int by lazy { slowCalculation() } }
  27. 42.

    @ToddGinsberg Class Delegation // Java class MyJavaImpl implements HugeInterface {

    private final HugeInterface backing; public MyJavaImpl(HugeInterface hi) { backing = hi; } // IMPLEMENT EVERYTHING }
  28. 45.

    @ToddGinsberg Sealed Classes sealed class Message class StartServer(val name: String)

    : Message() class StopServer(val name: String) : Message() object CountServers : Message()
  29. 46.

    @ToddGinsberg Sealed Classes val response = when(msg) { is StartServer

    -> startServer(msg.name) is StopServer -> stopServer(msg.name) is CountServers -> countServers() }
  30. 47.

    @ToddGinsberg Let’s Write a POJO! public class Person { public

    String firstName; public String lastName; }
  31. 48.

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

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

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

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

    @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…
  36. 53.

    @ToddGinsberg Copying Data Classes val me = Person("Todd", "Ginsberg") val

    emma = me.copy(firstName = "Emma") // Person(”Emma", "Ginsberg")
  37. 54.

    @ToddGinsberg Destructuring Data Classes val me = Person("Todd", "Ginsberg") val

    (first, last) = me // first == “Todd” last == “Ginsberg”
  38. 55.

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

    generateRandomNumber(): Int = 4 fun generateRandomNumber() = 4
  39. 56.

    @ToddGinsberg FUNctions – Default Values fun random(offset: Int = 0):

    Int = offset + 4 random() // 4 random(1) // 5
  40. 57.

    @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
  41. 58.

    @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
  42. 59.

    @ToddGinsberg FUNction Names @Test fun `Replicants have a four year

    lifespan!`() { // ... } @Test fun replicantsHaveAFourYearLifespan() { // ... }
  43. 60.

    @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)
  44. 61.

    @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)
  45. 62.

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

    @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)
  47. 64.

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

    @ToddGinsberg fun measureTimeMillis(block: () -> Unit): Long { val start

    = System.currentTimeMillis() block() return System.currentTimeMillis() - start } val time = measureTimeMillis { someSlowQuery() } High Order FUNctions
  49. 66.

    @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!
  50. 67.

    @ToddGinsberg The use Extension // Java try (DatabaseConnection conn =

    getConnection()) { // ... } // Kotlin getConnection().use { conn -> // ... }
  51. 68.

    @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 }
  52. 69.

    @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.
  53. 71.

    @ToddGinsberg listOf(1, 2, 3, 4) .filter { x -> x

    % 2 == 0 } .map { y -> y * 2 } // List[4, 8] Lambdas
  54. 72.

    @ToddGinsberg Lambdas listOf(1, 2, 3, 4) .filter { it %

    2 == 0 } .map { it * 2 } // List[4, 8]
  55. 79.

    @ToddGinsberg // Thanks type erasure L fun <T> loggerOf(): Logger

    = Logger.getLogger(T::class.java) Reified Generics
  56. 82.

    @ToddGinsberg Community Resources https://kotlinlang.slack.com • 22,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
  57. 86.

    @ToddGinsberg Fun == Fun Kotlin % of developers who are

    developing with the language or technology but have not expressed interest in continuing to do so (Stack Overflow Developer Survey 2019)
  58. 88.

    @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
  59. 89.

    @ToddGinsberg Why Kotlin is Right For Me 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 already use (Spring, IDEA, Gradle) Writing Kotlin, for me, is more fun.