Save 37% off PRO during our Black Friday Sale! »

Effective Kotlin

Effective Kotlin

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

5cefbec62d834db21a3823a8e66d59d8?s=128

Marcello Galhardo
PRO

April 17, 2019
Tweet

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?