Volver a Kotlin Básico

Introducción

Una de las mayores fortalezas de Kotlin es la interoperabilidad perfecta con Java. Puedes llamar código Java desde Kotlin y viceversa sin ningún problema.

Llamando Java desde Kotlin

Clases Java:

// Clase Java public class Person { private String name; private int age; public Person(String name, int age) { this.name = name; this.age = age; } public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } }

Usando en Kotlin:

val persona = Person("Alicia", 25) println(persona.name) // Llama getName() persona.name = "Bob" // Llama setName() println(persona.age) // Llama getAge()

Propiedades vs Getters/Setters

Kotlin automáticamente convierte getters/setters de Java a propiedades:

// Java public class User { private String email; public String getEmail() { return email; } public void setEmail(String email) { this.email = email; } public boolean isActive() { return true; } }
// Uso en Kotlin val usuario = User() usuario.email = "[email protected]" // Llama setEmail() println(usuario.email) // Llama getEmail() println(usuario.isActive) // Llama isActive() - nota: sin prefijo 'is'

Null Safety y Platform Types

Java no tiene null safety, así que Kotlin trata los tipos Java como "platform types":

// Java public class JavaClass { public String nullableString() { return null; } public String nonNullString() { return "Hola"; } }
// Kotlin - platform types (String!) val javaClass = JavaClass() // Peligroso - podría lanzar NPE val str1: String = javaClass.nullableString() // Seguro - tipo nullable explícito val str2: String? = javaClass.nullableString() // Seguro con verificación de null val str3 = javaClass.nullableString() if (str3 != null) { println(str3.uppercase()) }

Anotaciones @Nullable y @NotNull

Usa anotaciones Java para ayudar a Kotlin a entender la nullabilidad:

// Java con anotaciones import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; public class User { @NotNull public String getName() { return "Alicia"; } @Nullable public String getEmail() { return null; } }
// Kotlin ahora conoce la nullabilidad val usuario = User() val nombre: String = usuario.name // OK - no nullable val email: String? = usuario.email // OK - nullable

Colecciones

Java a Kotlin:

// Java public class JavaClass { public List<String> getNames() { return Arrays.asList("Alicia", "Bob", "Carlos"); } }
// Kotlin val javaClass = JavaClass() val nombres = javaClass.names // List<String!> // Convertir a tipos Kotlin val listaKotlin: List<String> = nombres.filterNotNull() val listaMutable: MutableList<String> = nombres.toMutableList()

Kotlin a Java:

// Kotlin fun obtenerNumeros(): List<Int> { return listOf(1, 2, 3, 4, 5) }
// Java List<Integer> numeros = MyKotlinFileKt.obtenerNumeros();

Conversiones SAM

Interfaces Java Single Abstract Method pueden ser lambda en Kotlin:

// Java public interface OnClickListener { void onClick(View view); } public class Button { public void setOnClickListener(OnClickListener listener) { // ... } }
// Kotlin - conversión SAM val boton = Button() boton.setOnClickListener { view -> println("Botón clickeado") } // Comparar con expresión de objeto completa boton.setOnClickListener(object : OnClickListener { override fun onClick(view: View) { println("Botón clickeado") } })

Métodos Estáticos

Java static a Kotlin:

// Java public class MathUtils { public static int add(int a, int b) { return a + b; } }
// Kotlin val resultado = MathUtils.add(5, 3) // 8

Kotlin a Java:

// Kotlin object MathUtils { @JvmStatic fun add(a: Int, b: Int): Int { return a + b } }
// Java int resultado = MathUtils.add(5, 3); // Funciona con @JvmStatic

Companion Objects

// Kotlin class MiClase { companion object { @JvmStatic fun metodoEstatico() { println("Método estático") } fun metodoCompanion() { println("Método companion") } } }
// Java MiClase.metodoEstatico(); // Funciona con @JvmStatic MiClase.Companion.metodoCompanion(); // Sin @JvmStatic

Sobrecargas

Parámetros por defecto de Kotlin a Java:

// Kotlin @JvmOverloads fun saludar(nombre: String, saludo: String = "Hola") { println("$saludo, $nombre") }
// Java - genera múltiples métodos saludar("Alicia"); // Usa saludo por defecto saludar("Bob", "Hola"); // Saludo personalizado

Campos

Propiedades de Kotlin a campos Java:

// Kotlin class Usuario { @JvmField val nombre: String = "Alicia" val email: String = "[email protected]" }
// Java Usuario usuario = new Usuario(); String nombre = usuario.nombre; // Acceso directo al campo con @JvmField String email = usuario.getEmail(); // Getter sin @JvmField

Funciones de Extensión

Las funciones de extensión no son directamente accesibles en Java:

// Kotlin fun String.agregarExclamacion(): String { return "$this!" }
// Java - debe usar método estático String resultado = MyKotlinFileKt.agregarExclamacion("Hola");

Excepciones Checked

Kotlin no tiene excepciones checked, pero Java sí:

// Kotlin @Throws(IOException::class) fun leerArchivo(ruta: String): String { throw IOException("Archivo no encontrado") }
// Java - debe capturar o declarar try { String contenido = MyKotlinFileKt.leerArchivo("archivo.txt"); } catch (IOException e) { e.printStackTrace(); }

Varargs

// Kotlin fun suma(vararg numeros: Int): Int { return numeros.sum() }
// Java int resultado = MyKotlinFileKt.suma(1, 2, 3, 4, 5);

Declaraciones de Object

// Kotlin object Singleton { fun hacerAlgo() { println("Método singleton") } }
// Java Singleton.INSTANCE.hacerAlgo();

Ejemplos Prácticos

Integración de Biblioteca Java:

// Usando Collections de Java import java.util.ArrayList import java.util.HashMap val arrayList = ArrayList<String>() arrayList.add("Alicia") arrayList.add("Bob") val hashMap = HashMap<String, Int>() hashMap.put("Alicia", 25) hashMap["Bob"] = 30 // Sintaxis Kotlin

Java Stream API:

import java.util.stream.Collectors val numeros = listOf(1, 2, 3, 4, 5) val resultado = numeros.stream() .filter { it % 2 == 0 } .map { it * 2 } .collect(Collectors.toList()) println(resultado) // [4, 8]

Spring Framework:

import org.springframework.stereotype.Service import org.springframework.beans.factory.annotation.Autowired @Service class ServicioUsuario @Autowired constructor( private val repositorioUsuario: RepositorioUsuario ) { fun encontrarUsuario(id: Long): Usuario? { return repositorioUsuario.findById(id).orElse(null) } }

Buenas Prácticas

  • Usa @JvmStatic para métodos estáticos en companion objects
  • Usa @JvmOverloads para funciones con parámetros por defecto
  • Usa @JvmField para exponer propiedades como campos
  • Usa anotaciones @Nullable y @NotNull en Java para mejor interoperación con Kotlin
  • Usa @Throws para documentar excepciones para llamadores Java
  • Ten cuidado con platform types - agrega verificaciones explícitas de null
  • Prefiere colecciones Kotlin pero sabe cómo trabajar con las de Java

Anotaciones Comunes

  • @JvmStatic - Hacer función de companion object estática
  • @JvmOverloads - Generar métodos sobrecargados para parámetros por defecto
  • @JvmField - Exponer propiedad como campo sin getter/setter
  • @JvmName - Cambiar el nombre del método Java generado
  • @Throws - Declarar excepciones checked para Java
  • @JvmSuppressWildcards - Suprimir wildcards en tipos genéricos
  • @JvmWildcard - Agregar wildcards a tipos genéricos

Consejos de Migración

Migración Gradual:

  1. Empieza con nuevas características en Kotlin
  2. Convierte clases de utilidad Java a Kotlin
  3. Convierte data classes (POJOs) a Kotlin data classes
  4. Migra lógica de negocio incrementalmente
  5. Mantén las pruebas en el lenguaje original inicialmente
  6. Usa características específicas de Kotlin gradualmente

Conversiones Comunes:

// Java public final class User { private final String name; private final int age; public User(String name, int age) { this.name = name; this.age = age; } public String getName() { return name; } public int getAge() { return age; } }
// Kotlin - mucho más simple! data class Usuario(val nombre: String, val edad: Int)

Conclusión

La interoperabilidad de Kotlin con Java es excelente, haciendo fácil adoptar Kotlin gradualmente en proyectos Java existentes. Entender los platform types y usar las anotaciones correctas asegura una integración suave entre código Kotlin y Java.

¡Esto completa el curso de Kotlin Básico! Ahora tienes una base sólida para construir aplicaciones con Kotlin.