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

Introduction to Kotlin

Introduction to Kotlin

In this presentation I try to show You the biggest advantages (in my opinion) of a great programming language - Kotlin. I use it for over a year now, and I simply love its readability, elegant solutions of Java’s biggest issues, and vast amount of features that we won’t see in Java anytime soon… Furthermore, Kotlin works with Android out-of-the-box, and gained dedicated support in Spring 5. The situation is getting interesting...

Grzegorz Dyrda

April 20, 2017
Tweet

More Decks by Grzegorz Dyrda

Other Decks in Programming

Transcript

  1. What is Kotlin? • Statically typed programming language for JVM,

    Android and the browser - developer since 2010 by JetBrains • Similar to Java, but free of its legacy problems and limitations • Can be freely mixed with Java (6+), existing codebase, ecosystem (Maven, Gradle), libraries etc. • Benefits: improved safety (no NPEs), increased readability (minimum boilerplate), added missing features • Easy learning curve (similar to Java/C#/JS), modern & fun!
  2. • Null safety • No checked exceptions • Extension functions

    • Higher-order functions • Function types & lambdas • Default & named arguments • Properties • Type inference • Operator overloading • Smart casts Kotlin features
  3. • Null safety • No checked exceptions • Extension functions

    • Higher-order functions • Function types & lambdas • Default & named arguments • Properties • Type inference • Operator overloading • Smart casts • Data classes • Immutable collections • Enhanced switch-case • String interpolation • Ranges • Inline functions • Infix notation • Tail recursion • Coroutines (async/await) • Great Standard Library Kotlin features
  4. • Null safety • No checked exceptions • Extension functions

    • Higher-order functions • Function types & lambdas • Default & named arguments • Properties • Type inference • Operator overloading • Smart casts • Data classes • Immutable collections • Enhanced switch-case • String interpolation • Ranges • Inline functions • Infix notation • Tail recursion • Coroutines (async/await) • Great Standard Library • Sealed classes • Delegated & lazy properties • Class delegation • Singletons • Nested functions • Object decomposition • Top-level functions • Reified generics • Raw Strings • And more… + 100% Java interoperable + Compiles to Java 6 bytecode + Syntax similar to Java/C#/JavaScript + Great tooling + Great community + Rapid development Kotlin features
  5. Functions // Java public int sum(int a, int b) {


    return a + b;
 }} // Kotlin public fun sum(a: Int, b: Int): Int {
 return a + b
 }}
  6. // Java public int sum(int a, int b) {
 return

    a + b;
 }} // Kotlin public fun sum(a: Int, b: Int): Int {
 return a + b
 }} Functions
  7. // Java public int sum(int a, int b) {
 return

    a + b;
 }} // Kotlin public fun sum(a: Int, b: Int): Int {
 return a + b
 }} Functions
  8. // Java public int sum(int a, int b) {
 return

    a + b;
 }} // Kotlin public fun sum(a: Int, b: Int): Int {
 return a + b
 }} Functions
  9. // Java public int sum(int a, int b) {
 return

    a + b;
 }} // Kotlin public fun sum(a: Int, b: Int): Int {
 return a + b
 }} Functions
  10. // Java public int sum(int a, int b) {
 return

    a + b;
 }} // Kotlin public fun sum(a: Int, b: Int): Int {
 return a + b
 }} Functions
  11. // Java public int sum(int a, int b) {
 return

    a + b;
 }} // Kotlin public fun sum(a: Int, b: Int): Int = a + b Functions
  12. // Java public int sum(int a, int b) {
 return

    a + b;
 }} // Kotlin public fun sum(a: Int, b: Int) = a + b Functions
  13. Function Arguments // Java
 public void repeat(String str, int count,

    String separator) {
 ...
 }} repeat("abc", 5, "");
  14. // Java
 public void repeat(String str, int count, String separator)

    {
 ...
 }} repeat("abc", 5, ""); // Kotlin
 fun repeat(str: String, count: Int, separator: String) {
 ...
 }} repeat("abc", 5, "")) Function Arguments
  15. // Kotlin
 fun repeat(str: String, count: Int = 3, separator:

    String = "") {
 ...
 }} repeat("abc", 5, "")) // Java
 public void repeat(String str, int count, String separator) {
 ...
 }} repeat("abc", 5, ""); Function Arguments
  16. // Kotlin
 fun repeat(str: String, count: Int = 3, separator:

    String = "") {
 ...
 }} repeat("abc", 5)) // Java
 public void repeat(String str, int count, String separator) {
 ...
 }} repeat("abc", 5, ""); Function Arguments
  17. // Kotlin
 fun repeat(str: String, count: Int = 3, separator:

    String = "") {
 ...
 }} 
 repeat("abc", count = 5)) // Java
 public void repeat(String str, int count, String separator) {
 ...
 }} repeat("abc", 5, ""); Function Arguments
  18. // Kotlin
 fun repeat(str: String, count: Int = 3, separator:

    String = "") {
 ...
 }} 
 repeat("abc", count = 5, separator = ",")) // Java
 public void repeat(String str, int count, String separator) {
 ...
 }} repeat("abc", 5, ""); Function Arguments
  19. // Kotlin
 fun repeat(str: String, count: Int = 3, separator:

    String = "") {
 ...
 }} 
 repeat("abc", separator = ",")) // Java
 public void repeat(String str, int count, String separator) {
 ...
 }} repeat("abc", 5, ""); Function Arguments
  20. Variables // Java int a = 1;
 String b =

    "xyz"; // Kotlin val a: Int = 1
 val b: String = "xyz"
  21. // Java int a = 1;
 String b = "xyz";

    // Kotlin val a: Int = 1
 val b: String = "xyz" Variables
  22. // Java int a = 1;
 String b = "xyz";

    // Kotlin val a: Int = 1
 val b: String = "xyz" Variables
  23. // Java int a = 1;
 String b = "xyz";

    // Kotlin val a: Int = 1
 val b: String = "xyz" Variables
  24. // Kotlin val a = 1 // Inferred type is

    Int
 val b = "xyz" // Inferred type is String // Java int a = 1;
 String b = "xyz"; Variables
  25. (Im)mutability // Assign-once (read-only) variable val x = 1
 x

    = 2 // Compile-time error // Mutable variable var y = 5
 y = 10 // OK

  26. (Im)mutability // Assign-once (read-only) variable val x = 1
 x

    = 2 // Compile-time error // Mutable variable var y = 5
 y = 10 // OK
 // Always start with immutable "val" // Change to "var" only when necessary
  27. Null safety fun getLength(str: String?): Int? {
 if (str !=

    null) {
 return str.length
 }
 return 0 }}
  28. Null safety fun getLength(str: String?): Int? {
 if (str !=

    null) {
 return str.length // <-- Smart cast
 }
 return 0 }}
  29. Null safety // Java
 public ZipCode getZipCode(User user) {
 if

    (user != null) {
 if (user.getAddress() != null) {
 return user.getAddress().getZipCode();
 }}
 }}
 return null;
 }}
 // Kotlin fun getZipCode(user: User?): ZipCode? {}
 return user?.address?.zipCode }}
  30. Null safety // Java
 public ZipCode getZipCode(User user) {
 if

    (user != null) {
 if (user.getAddress() != null) {
 return user.getAddress().getZipCode();
 }}
 }}
 return null;
 }}
 // Kotlin fun getZipCode(user: User?) = user?.address?.zipCode
  31. String Interpolation override fun toString(): String {
 return "Song{id=" +


    id +
 ", title='" +
 title +
 "', author='" +
 author +
 "'}"
 }}
  32. Classes // Java
 public class User {
 
 String firstName;


    String lastName;
 int age; public User(String firstName, String lastName, int age) {
 this.firstName = firstName;
 this.lastName = lastName;
 this.age = age;
 }}
 
 }}
  33. Classes // Java
 public class User {
 
 String firstName;


    String lastName;
 int age; public User(String firstName, String lastName, int age) {
 this.firstName = firstName;
 this.lastName = lastName;
 this.age = age;
 }}
 
 public String getFirstName() {
 return firstName;
 }}
 
 public void setFirstName(String firstName) {
 this.firstName = firstName;
 }}
 
 public String getLastName() {
 return lastName;
 }}
 
 public void setLastName(String lastName) {
 this.lastName = lastName;
 }}
 
 public int getAge() {
 return age;
 }}
 
 public void setAge(int age) {
 this.age = age;
 }}
 
 }}
  34. Classes // Java
 public class User {
 
 String firstName;


    String lastName;
 int age; public User(String firstName, String lastName, int age) {
 this.firstName = firstName;
 this.lastName = lastName;
 this.age = age;
 }
 
 public String getFirstName() {
 return firstName;
 }
 
 public void setFirstName(String firstName) {
 this.firstName = firstName;
 }
 
 public String getLastName() {
 return lastName;
 }
 
 public void setLastName(String lastName) {
 this.lastName = lastName;
 }
 
 public int getAge() {
 return age;
 }
 
 public void setAge(int age) {
 this.age = age;
 }
 
 @Override
 public boolean equals(Object o) {
 if (this == o) return true;
 if (o == null || getClass() != o.getClass()) return false;
 
 User user = (User) o;
 
 if (age != user.age) return false;
 if (firstName != null ? !firstName.equals(user.firstName) : user.firstName != null)
 return false;
 return lastName != null ? lastName.equals(user.lastName) : user.lastName == null;
 
 }
 
 @Override
 public int hashCode() {
 int result = firstName != null ? firstName.hashCode() : 0;
 result = 31 * result + (lastName != null ? lastName.hashCode() : 0);
 result = 31 * result + age;
 return result;
 }
 
 @Override
 public String toString() {
 return "User{" +
 "firstName='" + firstName + '\'' +
 ", lastName='" + lastName + '\'' +
 ", age=" + age +
 '}';
 }
 
 }} 53 lines of code!
  35. Classes // Java
 public class User {
 
 String firstName;


    String lastName;
 int age; public User(String firstName, String lastName, int age) {
 this.firstName = firstName;
 this.lastName = lastName;
 this.age = age;
 }
 
 public String getFirstName() {
 return firstName;
 }
 
 public void setFirstName(String firstName) {
 this.firstName = firstName;
 }
 
 public String getLastName() {
 return lastName;
 }
 
 public void setLastName(String lastName) {
 this.lastName = lastName;
 }
 
 public int getAge() {
 return age;
 }
 
 public void setAge(int age) {
 this.age = age;
 }
 
 @Override
 public boolean equals(Object o) {
 if (this == o) return true;
 if (o == null || getClass() != o.getClass()) return false;
 
 User user = (User) o;
 
 if (age != user.age) return false;
 if (firstName != null ? !firstName.equals(user.firstName) : user.firstName != null)
 return false;
 return lastName != null ? lastName.equals(user.lastName) : user.lastName == null;
 
 }
 
 @Override
 public int hashCode() {
 int result = firstName != null ? firstName.hashCode() : 0;
 result = 31 * result + (lastName != null ? lastName.hashCode() : 0);
 result = 31 * result + age;
 return result;
 }
 
 @Override
 public String toString() {
 return "User{" +
 "firstName='" + firstName + '\'' +
 ", lastName='" + lastName + '\'' +
 ", age=" + age +
 '}';
 }
 
 }}
  36. Classes // Kotlin
 class User {
 
 var firstName: String?


    var lastName: String?
 var age: Int
 
 constructor(firstName: String?, lastName: String?, age: Int) {
 this.firstName = firstName
 this.lastName = lastName
 this.age = age
 }}
 
 override fun equals(other: Any?): Boolean {
 if (this === other) return true
 if (other?.javaClass != javaClass) return false
 
 other as User
 
 if (firstName != other.firstName) return false
 if (lastName != other.lastName) return false
 if (age != other.age) return false
 
 return true
 }}
 
 override fun hashCode(): Int {
 var result = firstName?.hashCode() ?: 0
 result = 31 * result + (lastName?.hashCode() ?: 0)
 result = 31 * result + age
 return result
 }}
 
 override fun toString(): String {
 return "User{" +
 "firstName='" + firstName + '\'' +
 ", lastName='" + lastName + '\'' +
 ", age=" + age +
 '}'
 }}
 
 }}
  37. Classes // Kotlin
 class User {
 
 var firstName: String?


    var lastName: String?
 var age: Int
 
 constructor(firstName: String?, lastName: String?, age: Int) {
 this.firstName = firstName
 this.lastName = lastName
 this.age = age
 }}
 
 override fun equals(other: Any?): Boolean {
 if (this === other) return true
 if (other?.javaClass != javaClass) return false
 
 other as User
 
 if (firstName != other.firstName) return false
 if (lastName != other.lastName) return false
 if (age != other.age) return false
 
 return true
 }}
 
 override fun hashCode(): Int {
 var result = firstName?.hashCode() ?: 0
 result = 31 * result + (lastName?.hashCode() ?: 0)
 result = 31 * result + age
 return result
 }}
 
 override fun toString(): String {
 return "User{" +
 "firstName='" + firstName + '\'' +
 ", lastName='" + lastName + '\'' +
 ", age=" + age +
 '}'
 }}
 
 }}
  38. Classes // Kotlin
 class User {
 
 var firstName: String?


    var lastName: String?
 var age: Int
 
 constructor(firstName: String?, lastName: String?, age: Int) {
 this.firstName = firstName
 this.lastName = lastName
 this.age = age
 }}
 
 override fun equals(other: Any?): Boolean {
 if (this === other) return true
 if (other?.javaClass != javaClass) return false
 
 other as User
 
 if (firstName != other.firstName) return false
 if (lastName != other.lastName) return false
 if (age != other.age) return false
 
 return true
 }}
 
 override fun hashCode(): Int {
 var result = firstName?.hashCode() ?: 0
 result = 31 * result + (lastName?.hashCode() ?: 0)
 result = 31 * result + age
 return result
 }}
 
 override fun toString() = "User{firstName='$firstName', lastName='$lastName', age=$age}"
 
 }}
  39. Classes // Kotlin
 class User(var firstName: String?, var lastName: String?,

    var age: Int) {
 
 override fun equals(other: Any?): Boolean {
 if (this === other) return true
 if (other?.javaClass != javaClass) return false
 
 other as User
 
 if (firstName != other.firstName) return false
 if (lastName != other.lastName) return false
 if (age != other.age) return false
 
 return true
 }}
 
 override fun hashCode(): Int {
 var result = firstName?.hashCode() ?: 0
 result = 31 * result + (lastName?.hashCode() ?: 0)
 result = 31 * result + age
 return result
 }}
 
 override fun toString() = "User{firstName='$firstName', lastName='$lastName', age=$age}"
 
 }}
  40. Data Classes // Kotlin
 data class User(var firstName: String?, var

    lastName: String?, var age: Int)
 
 // data = equals() + hashCode() + toString() + copy() 1 line in Kotlin vs 53 lines in Java
  41. Multiple items in file // Models.kt
 data class User(val firstName:

    String, val lastName: String, val age: Int)
 data class Address(val street: String, val zipCode: ZipCode)
 data class ZipCode(val prefix: String, val postfix: String)

  42. Properties class User {
 var firstName: String? = ...
 var

    lastName: String = ...
 val age: Int = ...
 }}
  43. Properties class User {
 var firstName: String? = ... //

    mutable (getter/setter)
 var lastName: String = ... // mutable
 val age: Int = ... // read-only (getter only)
 }}
  44. Properties class User {
 var firstName: String? = ... //

    mutable (getter/setter)
 var lastName: String = ... // mutable
 val age: Int = ... // read-only (getter only)
 }}
 // Use them as fields
 fun test() {
 val user = User()
 user.firstName = “Grzegorz” // setter is called
 print("firstName = ${user.firstName}") // getter is called
 }}
  45. Properties class User {
 var firstName: String? = ""
 var

    lastName: String = ""
 val age: Int = 0
 }}
  46. Properties class User {
 var firstName: String? = ""
 get()

    {
 return "abc"
 }}
 
 var lastName: String = ""
 val age: Int = 0
 }}
  47. Properties class User {
 var firstName: String? = ""
 get()

    = "abc"
 
 var lastName: String = ""
 val age: Int = 0
 }}
  48. Properties class User {
 var firstName: String? = ""
 get()

    = "abc"
 set(value) {
 field = value + "xyz"
 }}
 
 var lastName: String = ""
 val age: Int = 0
 }}
  49. Top-level functions // MyFunctions.kt
 package com.kotlin.demo
 
 fun warning(msg: String)

    {
 print("WARNING: $msg")
 } // Demo.kt
 import com.kotlin.demo.warning
 
 fun doSomething() {
 warning("I'm warning you!")
 }
  50. Top-level functions // MyFunctions.kt
 package com.kotlin.demo
 
 fun warning(msg: String)

    {
 print("WARNING: $msg”) // package kotlin.io
 } // Demo.kt
 import com.kotlin.demo.warning
 
 fun doSomething() {
 warning("I'm warning you!")
 }
  51. Extensions // Java
 public class StringUtils {
 public static String

    toCamelCase(String str) { return str.replaceAll...
 } }
  52. Extensions // Java
 public class StringUtils {
 public static String

    toCamelCase(String str) { return str.replaceAll...
 }} }} 
 
 
 String camelStr = StringUtils.toCamelCase("lorem ipsum");
  53. Extensions // Java
 public class StringUtils {
 public static String

    toCamelCase(String str) { return str.replaceAll...
 }} }} 
 
 import static com.demo.StringUtils.toCamelCase;
 
 String camelStr = toCamelCase("lorem ipsum");

  54. Extensions // Java
 public class StringUtils {
 public static String

    toCamelCase(String str) { return str.replaceAll...
 }} }} 
 
 import static com.demo.StringUtils.toCamelCase;
 
 BufferedReader br = new BufferedReader(new StringReader(toCamelCase("lorem ipsum")));
 ... 
 br.readLine();
  55. Extensions // MyFunctions.kt package com.kotlin.demo 
 fun String.toCamelCase(): String {


    return this.replace...
 }}
 
 // Demo.kt
 import com.kotlin.demo.toCamelCase 
 "lorem ipsum".toCamelCase()
  56. Extensions // MyFunctions.kt package com.kotlin.demo 
 fun String.toCamelCase(): String {


    return this.replace...
 }}
 
 // Demo.kt
 import com.kotlin.demo.toCamelCase 
 "lorem ipsum".toCamelCase().reader()
  57. Extensions // MyFunctions.kt package com.kotlin.demo 
 fun String.toCamelCase(): String {


    return this.replace...
 }}
 
 // Demo.kt
 import com.kotlin.demo.toCamelCase 
 "lorem ipsum".toCamelCase().reader().forEachLine { line ->
 print(line)
 }
  58. Extensions 
 
 listOf(1, 2, null, 4, 5)
 .filterNotNull()
 .filter({

    it -> it > 2 })
 .forEach({ it ->
 print(it)
 }})
  59. Extensions 
 
 listOf(1, 2, null, 4, 5) // factory

    of immutable lists
 .filterNotNull()
 .filter({ it -> it > 2 })
 .forEach({ it ->
 print(it)
 }})
  60. Extensions 
 
 listOf(1, 2, null, 4, 5)
 .filterNotNull() //

    extension of Iterable
 .filter({ it -> it > 2 }) // extension of Iterable
 .forEach({ it -> // extension of Iterable
 print(it)
 }}) // Why extensions?!
  61. Extensions 
 
 listOf(1, 2, null, 4, 5) // What

    type is it?
 .filterNotNull()
 .filter({ it -> it > 2 })
 .forEach({ it ->
 print(it)
 }})
  62. Extensions 
 
 listOf(1, 2, null, 4, 5) // kotlin.collections.List<T>


    .filterNotNull() // covers java.util.List<T>
 .filter({ it -> it > 2 })
 .forEach({ it ->
 print(it)
 }})
  63. Extensions 
 
 listOf(1, 2, null, 4, 5)
 .filterNotNull()
 .filter({

    it -> it > 2 })
 .forEach({ it ->
 print(it)
 }})
  64. Lambdas 
 
 listOf(1, 2, null, 4, 5)
 .filterNotNull()
 .filter({

    it -> it > 2 })
 .forEach({ it ->
 print(it)
 }})
  65. Lambdas listOf(1, 2, null, 4, 5)
 .filterNotNull()
 .filter() { it

    -> it > 2 }
 .forEach() { it ->
 print(it)
 }}
  66. Lambdas listOf(1, 2, null, 4, 5)
 .filterNotNull()
 .filter { it

    -> it > 2 }
 .forEach { it ->
 print(it)
 }}
  67. Function Types // Java 8
 Function<Integer, String> f1 = (a)

    -> {
 return String.valueOf(a);
 }; BiFunction<Integer, Integer, String> f2 = (a, b) -> {
 return String.valueOf(a+b);
 }; // TriFunction... ???
  68. Function Types // Java
 public interface TriFunction<T, U, V, R>

    {
 R apply(T t, U u, V v);
 }} TriFunction<Integer, Integer, Integer, String> f3 = (a, b, c) -> {
 return String.valueOf(a+b+c);
 }; void test(TriFunction<Integer, Integer, Integer, String> func) {
 func.apply(1, 2, 3);
 }}
  69. Function Types // Java
 public interface TriFunction<T, U, V, R>

    {
 R apply(T t, U u, V v);
 }} TriFunction<Integer, Integer, Integer, String> f3 = (a, b, c) -> {
 return String.valueOf(a+b+c);
 }; void test(TriFunction<Integer, Integer, Integer, String> func) {
 func.apply(1, 2, 3);
 }}
  70. Function Types // Kotlin 
 val func: (Int, Int, Int)

    -> String = { a, b, c ->
 (a+b+c).toString()
 }}
  71. Function Types // Kotlin 
 val func = { a:

    Int, b: Int, c: Int ->
 (a+b+c).toString()
 }}
  72. Function Types // Kotlin 
 val func = { a:

    Int, b: Int, c: Int ->
 (a+b+c).toString()
 }} fun functionTest(func: (Int, Int, Int) -> String): Unit {
 func(1, 2, 3)
 }}
  73. Function Types // Kotlin 
 val func = { a:

    Int, b: Int, c: Int ->
 (a+b+c).toString()
 }} fun functionTest(func: (Int, Int, Int) -> String): Unit {
 func(1, 2, 3)
 }}
  74. Example - RxJava // Java
 Observable.just("1", "5", "10", "20")
 .map(new

    Func1<String, Integer>() {
 @Override
 public Integer call(String s) {
 return Integer.parseInt(s);
 }}
 })
 .filter(new Func1<Integer, Boolean>() {
 @Override
 public Boolean call(Integer integer) {
 return integer > 5;
 }}
 })
 .subscribe(new Action1<Integer>() {
 @Override
 public void call(Integer integer) {
 System.out.println(integer);
 }}
 });
  75. Example - RxJava // Kotlin
 Observable.just("1", "5", "10", "20")
 .map

    { it.toInt() }
 .filter { it > 10 }
 .subscribe {
 print(it)
 } // Java
 Observable.just("1", "5", "10", "20")
 .map(new Func1<String, Integer>() {
 @Override
 public Integer call(String s) {
 return Integer.parseInt(s);
 }}
 })
 .filter(new Func1<Integer, Boolean>() {
 @Override
 public Boolean call(Integer integer) {
 return integer > 5;
 }}
 })
 .subscribe(new Action1<Integer>() {
 @Override
 public void call(Integer integer) {
 System.out.println(integer);
 }}
 });
  76. 1. Kotlin Increases Productivity • Increased readability (minimum boilerplate) •

    Includes modern features • Improved safety (no NPEs) • Since most barriers are gone, devs can focus on more important things - e.g. system architecture & security
  77. 2. Kotlin is Ready for Production • IntelliJ has parts

    written in Kotlin • JetBrains Rider - C# IDE - is written entirely in Kotlin • 150,000 developers all over the world use Kotlin • Gradle introduced Kotlin support • Spring 5 introduces Kotlin support • Kotlin enters TIOBE top 100
  78. How to Start? • Home: kotlinlang.org • Great documentation •

    Online IDE - Hello World, Examples, Advent of Code… • Slack: kotlinlang.slack.com • Great community • My blog: blog.geekydevs.com • Android + Kotlin. How to start? [PL]