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

Effective Kotlin

Effective Kotlin

A lightning talk about how Kotlin helps you to write effective code based on Effective Java by Joshua Block.

Marcello Galhardo
PRO

April 17, 2019
Tweet

More Decks by Marcello Galhardo

Other Decks in Programming

Transcript

  1. Effective Kotlin LIGHTNING TALK

  2. loves

  3. Let’s talk about… Singleton

  4. // Kotlin object Singleton // Java public class Singleton {

    private Singleton INSTANCE; private Singleton() { } public Singleton getInstance() { if (INSTANCE != null) { INSTANCE = new Singleton(); } return INSTANCE; } }
  5. Let’s talk about… Primitive Obsession

  6. public class Api { public List<Object> doSearch( String deviceToken //

    other parameters ) { String customerId = getCustomerIdFromSessionToken(deviceToken); // Do something and returns the search return ArrayList(); } private String getCustomerIdFromSessionToken(String authToken) { // Retrieve the customer through the user session return "CustomerId"; } }
  7. public class Api { public List<Object> doSearch( String deviceToken //

    other parameters ) { String customerId = getCustomerIdFromSessionToken(deviceToken); // Do something and returns the search return ArrayList(); } private String getCustomerIdFromSessionToken(String authToken) { // Retrieve the customer through the user session return "CustomerId"; } }
  8. public class Api { public List<Object> doSearch( String deviceToken //

    other parameters ) { String customerId = getCustomerIdFromSessionToken(deviceToken); // Do something and returns the search return ArrayList(); } private String getCustomerIdFromSessionToken(String authToken) { // Retrieve the customer through the user session return "CustomerId"; } }
  9. public class Api { public List<Object> doSearch( String deviceToken //

    other parameters ) { String customerId = getCustomerIdFromSessionToken(deviceToken); // Do something and returns the search return ArrayList(); } private String getCustomerIdFromSessionToken(String authToken) { // Retrieve the customer through the user session return "CustomerId"; } }
  10. public class Api { public List<Object> doSearch( String deviceToken //

    other parameters ) { String customerId = getCustomerIdFromSessionToken(deviceToken); // Do something and returns the search return ArrayList(); } private String getCustomerIdFromSessionToken(String authToken) { // Retrieve the customer through the user session return "CustomerId"; } }
  11. IllegalArgumentException: Invalid UUID

  12. class Api { fun doSearch( deviceToken: String // other parameters

    ): List<Any> { val customerId = getCustomerIdFromSessionToken(deviceToken) // Do something and returns the search return ArrayList() } private fun getCustomerIdFromSessionToken(authToken: String): String { // Retrieve the customer through the user session return "CustomerId" } }
  13. class Api { fun doSearch( deviceToken: String // other parameters

    ): List<Any> { val customerId = getCustomerIdFromSessionToken(deviceToken) // Do something and returns the search return ArrayList() } private fun getCustomerIdFromSessionToken(authToken: String): String { // Retrieve the customer through the user session return "CustomerId" } }
  14. class Api { fun doSearch( sessionToken: String // other parameters

    ): List<Any> { val customerId = getCustomerIdFromSessionToken(sessionToken) // Do something and returns the search return ArrayList() } private fun getCustomerIdFromSessionToken(sessionToken: String): String { // Retrieve the customer through the user session return "CustomerId" } }
  15. class Api { fun doSearch( sessionToken: SessionToken // other parameters

    ): List<Any> { val customerId = getCustomerIdFromSessionToken(sessionToken) // Do something and returns the search return ArrayList() } private fun getCustomerIdFromSessionToken(sessionToken: SessionToken): String { // Retrieve the customer through the user session return "CustomerId" } }
  16. class SessionToken(val token: UUID) { constructor(token: String): this(UUID.fromString(token)) }

  17. class SessionToken(val token: UUID) { constructor(token: String): this(UUID.fromString(token)) }

  18. class SessionToken(val token: UUID) { constructor(token: String): this(UUID.fromString(token)) }

  19. inline class SessionToken(val token: UUID) { constructor(token: String): this(UUID.fromString(token)) }

  20. Let’s talk about… Composition over Inheritance

  21. // Kotlin class Foo open class Foo // Java public

    final class Foo {} public class Foo {}
  22. data class CustomerList( val customers: List<Customer> ) { {…} }

  23. data class CustomerList( val customers: List<Customer> ) : Collection<Customer> {

    {…} }
  24. Class 'CustomerList' is not abstract and does not implement abstract

    member
  25. public interface Collection<E> : Iterable<E> { public val size: Int

    public fun isEmpty(): Boolean public fun contains(element: E): Boolean public fun containsAll(elements: Collection<E>): Boolean }
  26. data class CustomerList( val customers: List<Customer> ) : Collection<Customer> {

    {…} }
  27. data class CustomerList( val customers: List<Customer> ) : Collection<Customer> by

    customers { {…} }
  28. Let’s talk about… State Handling

  29. sealed class ViewState { object Started: ViewState() object EditMode: ViewState()

    object ViewMode: ViewState() } fun verifyState(state: ViewState) { when (state) { is ViewState.Started -> println("Started") is ViewState.EditMode -> println("EditMode") is ViewState.ViewMode -> println("ViewMode") } }
  30. sealed class ViewState { object Started: ViewState() object EditMode: ViewState()

    object ViewMode: ViewState() class Error(val message: String = "Unknown error"): ViewState() } fun verifyState(state: ViewState) { when (state) { is ViewState.Started -> println("Started") is ViewState.EditMode -> println("EditMode") is ViewState.ViewMode -> println("ViewMode") } }
  31. sealed class ViewState { object Started: ViewState() object EditMode: ViewState()

    object ViewMode: ViewState() class Error(val message: String = "Unknown error"): ViewState() } fun verifyState(state: ViewState) { when (state) { is ViewState.Started -> println("Started") is ViewState.EditMode -> println("EditMode") is ViewState.ViewMode -> println("ViewMode") } } when expressions guarantee that their branches exhaustively check the possible subclasses of a sealed class.
  32. 'when' expression on sealed classes is recommended to be exhaustive,

    add 'Error' branch or 'else' branch instead
  33. sealed class ViewState { object Started: ViewState() object EditMode: ViewState()

    object ViewMode: ViewState() class Error(val message: String = "Unknown error"): ViewState() } fun verifyState(state: ViewState) { when (state) { is ViewState.Started -> println("Started") is ViewState.EditMode -> println("EditMode") is ViewState.ViewMode -> println(“ViewMode") is ViewState.Error -> println(state.message) } }
  34. Let’s talk about… Contracts

  35. fun requireNotNull(any: Any?) { if (any == null) throw IllegalArgumentException()

    }
  36. fun requireNotNull(any: Any?) { if (any == null) throw IllegalArgumentException()

    } fun foo(s: String?) { requireNotNull(s) s.length }
  37. Only safe (?.) or non-null asserted (!!.) calls are allowed

    on a nullable receiver of type String?
  38. fun requireNotNull(any: Any?) { contract { returns() implies (any !=

    null) } if (any == null) throw IllegalArgumentException() } fun foo(s: String?) { requireNotNull(s) s.length }
  39. Questions?