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

April 17, 2019
Tweet

More Decks by Marcello Galhardo

Other Decks in Programming

Transcript

  1. Effective Kotlin
    LIGHTNING TALK

    View Slide

  2. loves

    View Slide

  3. Let’s talk about…
    Singleton

    View Slide

  4. // Kotlin
    object Singleton
    // Java
    public class Singleton {
    private Singleton INSTANCE;
    private Singleton() {
    }
    public Singleton getInstance() {
    if (INSTANCE != null) {
    INSTANCE = new Singleton();
    }
    return INSTANCE;
    }
    }

    View Slide

  5. Let’s talk about…
    Primitive Obsession

    View Slide

  6. public class Api {
    public List 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";
    }
    }

    View Slide

  7. public class Api {
    public List 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";
    }
    }

    View Slide

  8. public class Api {
    public List 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";
    }
    }

    View Slide

  9. public class Api {
    public List 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";
    }
    }

    View Slide

  10. public class Api {
    public List 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";
    }
    }

    View Slide

  11. IllegalArgumentException: Invalid UUID

    View Slide

  12. class Api {
    fun doSearch(
    deviceToken: String
    // other parameters
    ): List {
    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"
    }
    }

    View Slide

  13. class Api {
    fun doSearch(
    deviceToken: String
    // other parameters
    ): List {
    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"
    }
    }

    View Slide

  14. class Api {
    fun doSearch(
    sessionToken: String
    // other parameters
    ): List {
    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"
    }
    }

    View Slide

  15. class Api {
    fun doSearch(
    sessionToken: SessionToken
    // other parameters
    ): List {
    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"
    }
    }

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

  20. Let’s talk about…
    Composition over Inheritance

    View Slide

  21. // Kotlin
    class Foo
    open class Foo
    // Java
    public final class Foo {}
    public class Foo {}

    View Slide

  22. data class CustomerList(
    val customers: List
    ) {
    {…}
    }

    View Slide

  23. data class CustomerList(
    val customers: List
    ) : Collection {
    {…}
    }

    View Slide

  24. Class 'CustomerList' is not abstract
    and does not implement abstract
    member

    View Slide

  25. public interface Collection : Iterable {
    public val size: Int
    public fun isEmpty(): Boolean
    public fun contains(element: E): Boolean
    public fun containsAll(elements: Collection): Boolean
    }

    View Slide

  26. data class CustomerList(
    val customers: List
    ) : Collection {
    {…}
    }

    View Slide

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

    View Slide

  28. Let’s talk about…
    State Handling

    View Slide

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

    View Slide

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

    View Slide

  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.

    View Slide

  32. 'when' expression on sealed classes is
    recommended to be exhaustive, add
    'Error' branch or 'else' branch instead

    View Slide

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

    View Slide

  34. Let’s talk about…
    Contracts

    View Slide

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

    View Slide

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

    View Slide

  37. Only safe (?.) or non-null asserted
    (!!.) calls are allowed on a nullable
    receiver of type String?

    View Slide

  38. fun requireNotNull(any: Any?) {
    contract { returns() implies (any != null) }
    if (any == null) throw IllegalArgumentException()
    }
    fun foo(s: String?) {
    requireNotNull(s)
    s.length
    }

    View Slide

  39. Questions?

    View Slide