Kotlin —Aprovechando mejor @Kotlin

Armando Picón
DevPicon by Armando
4 min readMay 20, 2017

--

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 ifs:

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
}

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
}

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

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

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
}

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

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

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

fun makeDir(path: String): File {
val result = File(path)
result.mkdirs()
return result
}

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

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
}

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

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

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

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

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

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

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.

--

--

Armando Picón
DevPicon by Armando

lifelong learner • 👨🏽‍💻 Android eng (ex: @uber ) • 🇵🇪 @ 🇨🇱 • @gdgopen • content creator @devpicon | @primosauda