Cómo aprobar una entrevista de Kotlin: las mejores preguntas de nivel avanzado
\n\nLa entrevista para un puesto de desarrollador Kotlin no es solo una prueba de sintaxis. En el nivel avanzado, los entrevistadores quieren ver una comprensión profunda del lenguaje, sus características y la capacidad de escribir código eficiente, conciso y seguro. En este artículo, analizaremos los temas clave que suelen aparecer en las entrevistas técnicas: corrutinas, funciones inline, clases Sealed, delegación y trucos de expresiones lambda. El material está preparado para el portal educativo PythonLib, donde ayudamos a los desarrolladores a sistematizar sus conocimientos.
\n\n1. Corrutinas (Coroutines) y Structured Concurrency
\nLas corrutinas son la base de la programación asíncrona en Kotlin. Las preguntas sobre este tema muestran si comprendes cómo funciona el planificador, el contexto y el manejo de excepciones.
\n\n¿Qué es Structured Concurrency y para qué sirve?
\nStructured Concurrency (concurrencia estructurada) es un principio en el que el ciclo de vida de una corrutina está vinculado a un ámbito (scope). Si la corrutina padre se cancela, todas las tareas hijas se cancelan automáticamente. Esto previene fugas de memoria y hace que el código sea predecible.
\n\nfun main() = runBlocking {\n launch {\n delay(1000)\n println("Tarea 1 completada")\n }\n launch {\n delay(500)\n println("Tarea 2 completada")\n }\n println("El hilo principal no se bloquea")\n}\n\n\nDiferencia entre launch y async
\nlaunch inicia una corrutina que no devuelve un resultado (Unit). async devuelve un Deferred, del cual se puede obtener el resultado mediante await(). async es útil para cálculos paralelos.
val deferred1 = async { calculateSum(10, 20) }\nval deferred2 = async { calculateSum(30, 40) }\nval result = deferred1.await() + deferred2.await()\nprintln("Suma: $result")\n\n\nManejo de excepciones en corrutinas
\nUsa try-catch dentro de la corrutina o CoroutineExceptionHandler para el manejo global. Es importante recordar que las excepciones en launch se propagan hacia arriba en la jerarquía, mientras que en async se almacenan hasta que se llama a await().
val handler = CoroutineExceptionHandler { _, exception ->\n println("Error: ${exception.message}")\n}\n\nfun main() = runBlocking {\n val job = launch(handler) {\n throw RuntimeException("Algo salió mal")\n }\n}\n\n\n2. Funciones inline, reified y crossinline
\nEstos mecanismos permiten optimizar el rendimiento y trabajar con genéricos en tiempo de ejecución. Los entrevistadores suelen preguntar sobre la diferencia entre inline, noinline y crossinline.
¿Para qué sirven las funciones inline?
\nLas funciones inline insertan el cuerpo de la función directamente en el lugar de la llamada. Esto elimina la sobrecarga de crear objetos lambda. Es especialmente útil para funciones de orden superior.
\n\ninline fun measureTime(action: () -> Unit) {\n val start = System.currentTimeMillis()\n action()\n println("Tiempo: ${System.currentTimeMillis() - start} ms")\n}\n\n\n¿Qué es reified?
\nCon reified se puede obtener información sobre el tipo dentro de una función inline, algo imposible para los genéricos normales debido al borrado de tipos.
inline fun <reified T> isInstance(value: Any): Boolean {\n return value is T\n}\n\nfun main() {\n println(isInstance<String>("Hello")) // true\n}\n\n\nDiferencia entre noinline y crossinline
\n- \n
noinline— prohíbe la inserción en línea de una lambda específica (por ejemplo, si se pasa a otra función). \n crossinline— permite la inserción en línea, pero prohíbe el retorno no local (non-local return) desde la lambda, lo cual es seguro para llamadas asíncronas. \n