← Kotlin EspañolChapter 13 of 13

Mejores Prácticas

## Objetivos de Aprendizaje - Aprender convenciones de código en Kotlin - Comprender Kotlin idiomático - Trabajar con interoperabilidad Java - Aplicar mejores prácticas en desarrollo Android ## Convenciones de Código ### Nomenclatura ```kotlin // Classes: PascalCase class UserAccount // Functions: camelCase fun calculateTotal() // Properties: camelCase val userName = "Alice" // Constants: SCREAMING_SNAKE_CASE const val MAX_RETRY_COUNT = 3 // Packages: lowercase package com.example.myapp ``` ### Indentación y Formato ```kotlin // 4 spaces for indent fun main() { if (condition) { doSomething() } } // Chained calls val result = items .filter { it > 0 } .map { it * 2 } .firstOrNull() ``` ### Documentación ```kotlin /** * Calculates the sum of two integers. * * @param a First integer * @param b Second integer * @return The sum of a and b */ fun sum(a: Int, b: Int): Int = a + b ``` ## Kotlin Idiomático ### Tipos Anulables ```kotlin // Bad if (name != null) { println(name.length) } else { println(0) } // Good println(name?.length ?: 0) ``` ### Plantillas de Cadenas ```kotlin // Bad println("User: " + user.name + ", Age: " + user.age) // Good println("User: ${user.name}, Age: ${user.age}") ``` ### Valores por Defecto ```kotlin // Bad fun createUser( name: String, age: Int, email: String, phone: String ) { // ... } createUser("Alice", 30, "alice@example.com", "") // Good fun createUser( name: String, age: Int = 18, email: String = "unknown@example.com", phone: String = "" ) { // ... } createUser("Alice") ``` ### Data Classes ```kotlin // Bad class User { val name: String val email: String constructor(name: String, email: String) { this.name = name this.email = email } fun equals(other: User) = name == other.name && email == other.email fun hashCode() = name.hashCode() * 31 + email.hashCode() fun toString() = "User(name=$name, email=$email)" } // Good data class User(val name: String, val email: String) ``` ### Operaciones de Colecciones ```kotlin // Bad val result = mutableListOf() for (item in items) { if (item.isNotEmpty()) { result.add(item.uppercase()) } } // Good val result = items .filter { it.isNotEmpty() } .map { it.uppercase() } ``` ### apply y with ```kotlin // Bad val person = Person() person.name = "Alice" person.age = 30 person.email = "alice@example.com" // Good val person = Person().apply { name = "Alice" age = 30 email = "alice@example.com" } // with for transforming val info = with(person) { "$name is $age years old" } ``` ## Interoperabilidad Java ### Llamando Java desde Kotlin ```kotlin // Java method returning null val javaObject = JavaClass() javaObject.nullableMethod?.let { /* safe call */ } // Java method with @Nullable annotation val result: String? = javaObject.method() ``` ### Llamando Kotlin desde Java ```kotlin // Kotlin top-level function // Java calls: FunctionsKt.repeat("Hello", 3) // Kotlin object object MySingleton { fun doSomething() {} } // Java calls: MySingleton.doSomething() // Kotlin companion object class MyClass { companion object { fun create() = MyClass() } } // Java calls: MyClass.create() ``` ### Anotaciones para Java ```kotlin // @JvmField exposes property as field class User { @JvmField val id: Int = 0 } // @JvmName specifies Java method name @JvmName("getUsersByRole") fun getUsers(role: String) { } // @JvmStatic for companion object methods class Utils { companion object { @JvmStatic fun helper() {} } } // @Throws for checked exceptions @Throws(IOException::class) fun readFile(path: String): String { } ``` ## Desarrollo Android ### View Binding ```kotlin class MainActivity : AppCompatActivity() { private lateinit var binding: ActivityMainBinding override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) binding = ActivityMainBinding.inflate(layoutInflater) setContentView(binding.root) binding.button.setOnClickListener { binding.textView.text = "Clicked!" } } } ``` ### Corrutinas con ViewModel ```kotlin class MyViewModel : ViewModel() { private val _data = MutableLiveData() val data: LiveData = _data private val _scope = ViewModelScope(Dispatchers.Main) fun loadData() { _scope.launch { val result = withContext(Dispatchers.IO) { api.fetchData() } _data.value = result } } } ``` ### Funciones de Extensión para Vistas ```kotlin fun View.visible() { visibility = View.VISIBLE } fun View.gone() { visibility = View.GONE } fun View.onClick(action: () -> Unit) { setOnClickListener { action() } } // Usage binding.button.visible() binding.progressBar.gone() binding.button.onClick { doSomething() } ``` ### Kotlin Android Extensions ```kotlin // build.gradle // apply plugin: 'kotlin-android-extensions' // In Activity import kotlinx.android.synthetic.main.activity_main.* class MainActivity : AppCompatActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) button.setOnClickListener { textView.text = "Hello!" } } } ``` ## Consejos de Rendimiento ### Evitar Crear Objetos Innecesarios ```kotlin // Bad - creates String each iteration val result = items.joinToString("") { it.value } // Good - reuse separator val result = items.joinToString("") { it.value } ``` ### Usar inline para Funciones Pequeñas ```kotlin inline fun List.first(predicate: (T) -> Boolean): T? { for (element in this) { if (predicate(element)) return element } return null } ``` ### Secuencia para Colecciones Grandes ```kotlin // When processing large collections val result = largeList .asSequence() .map { expensiveOperation(it) } .filter { it > 0 } .take(10) .toList() ``` ## Manejo de Errores ### Usar Tipo Result ```kotlin fun divide(a: Int, b: Int): Result { return if (b == 0) { Result.failure(IllegalArgumentException("Cannot divide by zero")) } else { Result.success(a / b) } } fun main() { val result = divide(10, 2) result.fold( onSuccess = { println("Result: $it") }, onFailure = { println("Error: ${it.message}") } ) } ``` ### runCatching ```kotlin fun main() { val result = runCatching { "hello".toInt() } println(result.isSuccess) // false println(result.exceptionOrNull()) // NumberFormatException } ``` ## Pruebas ```kotlin // Using JUnit 5 with Kotlin class CalculatorTest { private val calculator = Calculator() @Test fun `adds two numbers`() { assertEquals(5, calculator.add(2, 3)) } @Test fun `divides two numbers`() { assertThrows { calculator.divide(1, 0) } } } ``` ## Resumen - Sigue las convenciones de nomenclatura y formato de Kotlin - Usa patrones de Kotlin idiomáticos (elvis, let, apply) - Las data classes reducen el código repetitivo - Encadena operaciones de colecciones en lugar de bucles - Usa anotaciones @Jvm para interoperabilidad con Java - El desarrollo Android se beneficia de extensiones y corrutinas - Usa secuencias para procesamiento de colecciones grandes - Tipos Result y runCatching para manejo de errores

Comments

Comments powered by Giscus

To enable comments, add your Giscus embed code here.

Learn more about Giscus →