Slide 1

Slide 1 text

Is Kotlin Right For You? KCDC X 2018-07-12 Todd Ginsberg @ToddGinsberg Principal Software Developer

Slide 2

Slide 2 text

TITANIUM SPONSORS Platinum Sponsors Gold Sponsors

Slide 3

Slide 3 text

@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

Slide 4

Slide 4 text

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

Slide 5

Slide 5 text

@ToddGinsberg But First… I Java

Slide 6

Slide 6 text

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

Slide 7

Slide 7 text

@ToddGinsberg What Is Kotlin?

Slide 8

Slide 8 text

@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

Slide 9

Slide 9 text

@ToddGinsberg Major Features 100% interoperable with Java Very easy to learn Fantastic IDE support Large, positive community

Slide 10

Slide 10 text

@ToddGinsberg Major Features Designed to avoid entire classes of defects Null-safe 172,000+ issues on GitHub! 11,584 duplicates on Stack Overflow! Type Inference More than diamond operator or local var (thanks Java 10!)

Slide 11

Slide 11 text

@ToddGinsberg Kotlin Adoption MAR 2017 Assess NOV 2017 Trial MAY 2018 Adopt ThoughtWorks Technology Radar

Slide 12

Slide 12 text

@ToddGinsberg Supported on Android Beep! You can use Kotlin now! - 2017

Slide 13

Slide 13 text

@ToddGinsberg Recommended on Android Beep! Prefer Kotlin over Java! - 2018

Slide 14

Slide 14 text

@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

Slide 15

Slide 15 text

@ToddGinsberg Supported in Gradle

Slide 16

Slide 16 text

@ToddGinsberg Syntax

Slide 17

Slide 17 text

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

Slide 18

Slide 18 text

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

Slide 19

Slide 19 text

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

Slide 20

Slide 20 text

@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

Slide 21

Slide 21 text

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

Slide 22

Slide 22 text

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

Slide 23

Slide 23 text

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

Slide 24

Slide 24 text

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

Slide 25

Slide 25 text

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

Slide 26

Slide 26 text

@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

Slide 27

Slide 27 text

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

Slide 28

Slide 28 text

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

Slide 29

Slide 29 text

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

Slide 30

Slide 30 text

@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" }

Slide 31

Slide 31 text

@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

Slide 32

Slide 32 text

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

Slide 33

Slide 33 text

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

Slide 34

Slide 34 text

@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"

Slide 35

Slide 35 text

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

Slide 36

Slide 36 text

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

Slide 37

Slide 37 text

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

Slide 38

Slide 38 text

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

Slide 39

Slide 39 text

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

Slide 40

Slide 40 text

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

Slide 41

Slide 41 text

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

Slide 42

Slide 42 text

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

Slide 43

Slide 43 text

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

Slide 44

Slide 44 text

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

Slide 45

Slide 45 text

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

Slide 46

Slide 46 text

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

Slide 47

Slide 47 text

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

Slide 48

Slide 48 text

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

Slide 49

Slide 49 text

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

Slide 50

Slide 50 text

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

Slide 51

Slide 51 text

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

Slide 52

Slide 52 text

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

Slide 53

Slide 53 text

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

Slide 54

Slide 54 text

@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

Slide 55

Slide 55 text

@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

Slide 56

Slide 56 text

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

Slide 57

Slide 57 text

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

Slide 58

Slide 58 text

@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!

Slide 59

Slide 59 text

@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 }

Slide 60

Slide 60 text

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

Slide 61

Slide 61 text

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

Slide 62

Slide 62 text

@ToddGinsberg What About Checked Exceptions? NO

Slide 63

Slide 63 text

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

Slide 64

Slide 64 text

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

Slide 65

Slide 65 text

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

Slide 66

Slide 66 text

@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(): Int = TODO()

Slide 67

Slide 67 text

@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)

Slide 68

Slide 68 text

@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)

Slide 69

Slide 69 text

@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)

Slide 70

Slide 70 text

@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)

Slide 71

Slide 71 text

@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

Slide 72

Slide 72 text

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

Slide 73

Slide 73 text

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

Slide 74

Slide 74 text

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

Slide 75

Slide 75 text

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

Slide 76

Slide 76 text

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

Slide 77

Slide 77 text

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

Slide 78

Slide 78 text

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

Slide 79

Slide 79 text

@ToddGinsberg Community

Slide 80

Slide 80 text

@ToddGinsberg Community Resources https://kotlinlang.slack.com • 17,300+ 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

Slide 81

Slide 81 text

@ToddGinsberg Community KΛTEGORY funKTionale Λrrow

Slide 82

Slide 82 text

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

Slide 83

Slide 83 text

@ToddGinsberg Learn Kotlin! http://bit.ly/GoogleKotlinClass

Slide 84

Slide 84 text

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

Slide 85

Slide 85 text

@ToddGinsberg Summary

Slide 86

Slide 86 text

@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. Writing Kotlin, for me, is more fun. Plays well with the tools I already use (Spring, IDEA, Gradle)

Slide 87

Slide 87 text

@ToddGinsberg Is Kotlin is Right For You?

Slide 88

Slide 88 text

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