Kotlin —Aprovechando mejor @Kotlin

devpicon

Armando Picón

Posted on September 30, 2019

Kotlin —Aprovechando mejor @Kotlin

Si vienes de Java a Kotlin y te interesa aprovechar mejor este lenguaje considera los siguientes consejos.

Emplea expresiones

Podríamos tener el siguiente bloque de _if_s:

**fun** getDefaultLocale(deliveryArea: String): Locale{
**val** deliveryAreaLower = deliveryArea._toLowerCase_()
**if** (deliveryAreaLower == **"mexico"** || deliveryAreaLower == **"peru"** ){
**return** MyLocale. **SPANISH**  

}
**if** (deliveryAreaLower == **"brazil"** ){
**return** MyLocale. **PORTUGUESE**  

}
**if** (deliveryAreaLower == **"usa"** ){
**return** MyLocale. **ENGLISH**  
}

**return** MyLocale. **SPANISH**  
}
Enter fullscreen mode Exit fullscreen mode

Esto podría simplificarse de la siguiente manera haciendo uso de when:

**fun** getDefaultLocale(deliveryArea: String) = **when** (deliveryArea._toLowerCase_()) {
**"mexico"** , **"peru"** -> MyLocale.**SPANISH  
    "brazil" **-> MyLocale.** PORTUGUESE  
    "usa" **-> MyLocale.** ENGLISH  
    else **-> MyLocale.** SPANISH**  
}
Enter fullscreen mode Exit fullscreen mode

Es recomendable evaluar si puedes usar “when” como reemplazo de varios “if”.

Emplear Extension Functions para funciones utilitarias

En Java acostumbramos a generar nuestras clases utilitarias con funciones estáticas de la siguiente manera:

**public class** StringUtils {
**public static int** countAmountOfX(String string){
**return** string.length() - string.replace( **"x"** , **""** ).length();
    }
}
Enter fullscreen mode Exit fullscreen mode

Su conversión natural a Kotlin sería de esta manera:

**object** StringUtils {
**fun** countAmountOfX(string: String): Int {
**return** string. **length** - string._replace_( **"x"** , **""** ). **length**  
}
}
Enter fullscreen mode Exit fullscreen mode

Sin embargo, Kotlin nos permite prescindir del objeto que envuelve nuestra función, ya que las funciones son elementos de primer nivel en Kotlin (o en otras palabras puedes escribir una función en un archivo Kotlin sin necesidad de envolverlo con una clase como en Java):

**fun** countAmountOfX(string: String): Int {
**return** string. **length** - string._replace_( **"x"** , **""** ). **length**  
}
Enter fullscreen mode Exit fullscreen mode

Incluso, dependiendo de la función podríamos convertirla en una “extension function”:

**fun** String.countAmountOfX(): Int {
**return this**. **length** - **this**._replace_( **"x"** , **""** ). **length**  
}

**fun** main(args: Array<String>) {
_// Nos dará 4  
    println_ ( **"xEstoxEsxKotlinx"**._countAmountOfX_())
}
Enter fullscreen mode Exit fullscreen mode

También te hablo sobre Extension functions en el siguiente

Considera emplear apply()

Algunas veces tenemos esta clase de funciones en Java:

**public** File makeDir(String path){
    File result = **new** File(path);
    result.mkdirs();
**return** result;
}
Enter fullscreen mode Exit fullscreen mode

La cual en Kotlin se traduciría de la siguiente manera:

**fun** makeDir(path: String): File {
**val** result = File(path)
    result.mkdirs()
**return** result
}
Enter fullscreen mode Exit fullscreen mode

Consideremos el hecho de que se está declarando una variable sobre la que se están aplicando algunas funciones y retornando la misma variable al final. Esto se podría simplificar mediante el uso de la función apply().

**fun** makeDir(path: String) = File(path)._apply_ **{** mkdirs() **}**
Enter fullscreen mode Exit fullscreen mode

Podrías aplicar apply() también en el siguiente escenario, estamos poblando un datasource de la siguiente manera:

**fun** getDataSource(): MysqlDataSource {
**val** fileInputStream = FileInputStream( **"myfile.properties"** )

**val** properties = Properties()
    properties.load(fileInputStream)

**val** mySqlDataSource = MysqlDataSource()
    mySqlDataSource.setURL(properties.getProperty( **"MYSQL\_DB\_URL"** ))
    mySqlDataSource._user_ = properties.getProperty( **"MYSQL\_DB\_USERNAME"** )
    mySqlDataSource.setPassword(properties.getProperty( **"MYSQL\_DB\_PASSWORD"** ))
    mySqlDataSource._port_ = properties.getProperty( **"MYSQL\_DB\_PORT"** )._toInt_()
    mySqlDataSource._databaseName_ = properties.getProperty( **"MYSQL\_DB\_NAME"** )
    mySqlDataSource._maxQuerySizeToLog_ = properties.getProperty( **"MYSQL\_DB\_QUERYSIZE"** )._toInt_()

**return** mySqlDataSource
}
Enter fullscreen mode Exit fullscreen mode

Podemos agrupar el seteo de las propiedades del objeto mySqlDataSource, y evitamos de paso repetir la misma variable varias veces, de la siguiente forma:

**val** mySqlDataSource = MysqlDataSource()._apply_ **{**  
setURL(properties.getProperty( **"MYSQL\_DB\_URL"** ))
_user_ = properties.getProperty( **"MYSQL\_DB\_USERNAME"** )
    setPassword(properties.getProperty( **"MYSQL\_DB\_PASSWORD"** ))
_port_ = properties.getProperty( **"MYSQL\_DB\_PORT"** )._toInt_()
_databaseName_ = properties.getProperty( **"MYSQL\_DB\_NAME"** )
_maxQuerySizeToLog_ = properties.getProperty( **"MYSQL\_DB\_QUERYSIZE"** )
**}**
Enter fullscreen mode Exit fullscreen mode

Evita la sobrecarga de funciones para argumentos por defecto

Suelen ser útiles en Java, pero no hay necesidad de recurrir a lo siguiente para trabajar con argumentos por defecto:

**fun** findPhoneNumber(number:String):String{
**return** findPhoneNumber(number, **"MX"** )
}

**fun** findPhoneNumber(number: String, country: String): String {
_TODO_( **"Implementa tu búsqueda"** )
}
Enter fullscreen mode Exit fullscreen mode

Esto lo podemos simplificar aplicando un valor por defecto al argumento correspondiente (o a ambos si así lo quisieramos):

**fun** findPhoneNumber(number: String, locale: String = **"MX"** ): String {
_TODO_( **"Implementa tu búsqueda"** )
}
Enter fullscreen mode Exit fullscreen mode

De este modo podríamos invocar a la función findPhoneNumber enviando un solo parámetro y automáticamente Kotlin empleará para el segundo parámetro el valor que declaramos por defecto.

Reemplaza la validación de null por let()

Considera la siguiente validación:

private fun insertDataIntoDatabase(db: SQLiteDatabase?, comicValues: MutableList<ContentValues>) {
    if (db != null) {
        try {
            db.beginTransaction()
            comicValues._forEach_ **{** db.insert(ComicContract.ComicEntry.TABLE\_NAME, null, **it** ) **}**  
db.setTransactionSuccessful()
        } catch (e: SQLException) {
            Log.e(_javaClass_._simpleName_, **"Ha ocurrido un error durante la inserción."** , e)
        } finally {
            db.endTransaction()
        }
    }
}
Enter fullscreen mode Exit fullscreen mode

En el interior de esta función estamos validando si el argumento recibido db es nulo o no, como somos nuevos en Kotlin podríamos considerar reescribir esta función haciendo uso del operador ?. para evitar la validación anterior.

try {
    db?.beginTransaction()
    comicValues._forEach_ **{** db?.insert(ComicContract.ComicEntry.TABLE\_NAME, null, **it** ) **}**  
db?.setTransactionSuccessful()
} catch (e: SQLException) {
    Log.e(_javaClass_._simpleName_, **"Ha ocurrido un error durante la inserción."** , e)
} finally {
    db?.endTransaction()
}
Enter fullscreen mode Exit fullscreen mode

Sin embargo, una mejor manera de hacerlo sería empleando let() de la siguiente forma:

db?._let_ **{**  
try {
        db.beginTransaction()
        comicValues._forEach_ **{** db.insert(ComicContract.ComicEntry.TABLE\_NAME, null, **it** ) **}**  
db.setTransactionSuccessful()
    } catch (e: SQLException) {
        Log.e(_javaClass_._simpleName_, **"Ha ocurrido un error durante la inserción."** , e)
    } finally {
        db.endTransaction()
    }            
**}**
Enter fullscreen mode Exit fullscreen mode

La función let() además nos permite crear bloques de código, es decir, toda variable que se creara dentro de este bloque solo residiría en él evitando algún problema que se pudiera suscitar manteniendo dichas variables más allá de donde solo se requieren.

Nota final

Estas son algunas de las formas de mejorar tu código en Kotlin, con el transcurso de los días iré sumando algunos más; pero por lo pronto estas son algunas mejoras que tuve que ir mejorando en mi paso de Java a Kotlin.

Pueden encontrar el gist con código de este artículo en mi repositorio en Github.

¡Gracias por leer el artículo, significa mucho para mi! Si lo disfrutaste o fue de utilidad por favor recomiéndalo mediante el ícono del corazón ❤ y compartelo con tus amigos.

Me puedes encontrar en Twitter y en Github.


💖 💪 🙅 🚩
devpicon
Armando Picón

Posted on September 30, 2019

Join Our Newsletter. No Spam, Only the good stuff.

Sign up to receive the latest update from our blog.

Related

Kotlin —Aprovechando mejor @Kotlin
androidappdevelopm Kotlin —Aprovechando mejor @Kotlin

September 30, 2019